⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netdev.c

📁 Intel 82546系列lan driver源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*******************************************************************************  Intel PRO/1000 Linux driver  Copyright(c) 1999 - 2008 Intel Corporation.  This program is free software; you can redistribute it and/or modify it  under the terms and conditions of the GNU General Public License,  version 2, as published by the Free Software Foundation.  This program is distributed in the hope it will be useful, but WITHOUT  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for  more details.  You should have received a copy of the GNU General Public License along with  this program; if not, write to the Free Software Foundation, Inc.,  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.  The full GNU General Public License is included in this distribution in  the file called "COPYING".  Contact Information:  Linux NICS <linux.nics@intel.com>  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************/#include <linux/module.h>#include <linux/types.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/pagemap.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/tcp.h>#include <linux/ipv6.h>#ifdef NETIF_F_TSO#include <net/checksum.h>#ifdef NETIF_F_TSO6#include <net/ip6_checksum.h>#endif#endif#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/if_vlan.h>#include "e1000.h"#ifdef CONFIG_E1000E_NAPI#define DRV_NAPI "-NAPI"#else#define DRV_NAPI#endif#define DRV_DEBUG#define DRV_VERSION "0.5.11.2" DRV_NAPI DRV_DEBUGchar e1000e_driver_name[] = "e1000e";const char e1000e_driver_version[] = DRV_VERSION;static s32 e1000_get_variants_82571(struct e1000_adapter *adapter){	struct e1000_hw *hw = &adapter->hw;	static int global_quad_port_a; /* global port a indication */	struct pci_dev *pdev = adapter->pdev;	u16 eeprom_data = 0;	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;	/* tag quad port adapters first, it's used below */	switch (pdev->device) {	case E1000_DEV_ID_82571EB_QUAD_COPPER:	case E1000_DEV_ID_82571EB_QUAD_FIBER:	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:	case E1000_DEV_ID_82571PT_QUAD_COPPER:		adapter->flags |= FLAG_IS_QUAD_PORT;		/* mark the first port */		if (global_quad_port_a == 0)			adapter->flags |= FLAG_IS_QUAD_PORT_A;		/* Reset for multiple quad port adapters */		global_quad_port_a++;		if (global_quad_port_a == 4)			global_quad_port_a = 0;		break;	default:		break;	}	switch (adapter->hw.mac.type) {	case e1000_82571:		/* these dual ports don't have WoL on port B at all */		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&		    (is_port_b))			adapter->flags &= ~FLAG_HAS_WOL;		/* quad ports only support WoL on port A */		if (adapter->flags & FLAG_IS_QUAD_PORT &&		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))			adapter->flags &= ~FLAG_HAS_WOL;		/* Does not support WoL on any port */		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)			adapter->flags &= ~FLAG_HAS_WOL;		break;	case e1000_82573:		if (pdev->device == E1000_DEV_ID_82573L) {			if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,			                   &eeprom_data) < 0)				break;			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK))				adapter->flags |= FLAG_HAS_JUMBO_FRAMES;		}		break;	default:		break;	}	return 0;}static struct e1000_info e1000_82571_info = {	.mac			= e1000_82571,	.flags			= FLAG_HAS_HW_VLAN_FILTER				  | FLAG_HAS_JUMBO_FRAMES				  | FLAG_HAS_WOL				  | FLAG_APME_IN_CTRL3				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_HAS_SMART_POWER_DOWN				  | FLAG_RESET_OVERWRITES_LAA /* errata */				  | FLAG_TARC_SPEED_MODE_BIT /* errata */				  | FLAG_APME_CHECK_PORT_B,	.pba			= 38,	.init_ops		= e1000_init_function_pointers_82571,	.get_variants		= e1000_get_variants_82571,};static struct e1000_info e1000_82572_info = {	.mac			= e1000_82572,	.flags			= FLAG_HAS_HW_VLAN_FILTER				  | FLAG_HAS_JUMBO_FRAMES				  | FLAG_HAS_WOL				  | FLAG_APME_IN_CTRL3				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */	.pba			= 38,	.init_ops		= e1000_init_function_pointers_82571,	.get_variants		= e1000_get_variants_82571,};static struct e1000_info e1000_82573_info = {	.mac			= e1000_82573,	.flags			= FLAG_HAS_HW_VLAN_FILTER				  | FLAG_HAS_WOL				  | FLAG_APME_IN_CTRL3				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_SMART_POWER_DOWN				  | FLAG_HAS_AMT				  | FLAG_HAS_ERT				  | FLAG_HAS_SWSM_ON_LOAD,	.pba			= 20,	.init_ops		= e1000_init_function_pointers_82571,	.get_variants		= e1000_get_variants_82571,};static struct e1000_info e1000_82574_info = {	.mac			= e1000_82574,	.flags			= FLAG_HAS_HW_VLAN_FILTER#ifdef CONFIG_E1000E_MSIX				  | FLAG_HAS_MSIX#endif				  | FLAG_HAS_JUMBO_FRAMES				  | FLAG_HAS_WOL				  | FLAG_APME_IN_CTRL3				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_SMART_POWER_DOWN				  | FLAG_HAS_AMT				  | FLAG_HAS_CTRLEXT_ON_LOAD,	.pba			= 20,	.init_ops		= e1000_init_function_pointers_82571,	.get_variants		= e1000_get_variants_82571,};static struct e1000_info e1000_es2_info = {	.mac			= e1000_80003es2lan,	.flags			= FLAG_HAS_HW_VLAN_FILTER				  | FLAG_HAS_JUMBO_FRAMES				  | FLAG_HAS_WOL				  | FLAG_APME_IN_CTRL3				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_RX_NEEDS_RESTART /* errata */				  | FLAG_TARC_SET_BIT_ZERO /* errata */				  | FLAG_APME_CHECK_PORT_B				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,	.pba			= 38,	.init_ops		= e1000_init_function_pointers_80003es2lan,	.get_variants		= NULL,};static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter){	if (adapter->hw.phy.type == e1000_phy_ife)		adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;	if ((adapter->hw.mac.type == e1000_ich8lan) &&	    (adapter->hw.phy.type == e1000_phy_igp_3))		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;	return 0;}static struct e1000_info e1000_ich8_info = {	.mac			= e1000_ich8lan,	.flags			= FLAG_HAS_WOL				  | FLAG_IS_ICH				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_HAS_AMT				  | FLAG_HAS_FLASH				  | FLAG_APME_IN_WUC,	.pba			= 8,	.init_ops		= e1000_init_function_pointers_ich8lan,	.get_variants		= e1000_get_variants_ich8lan,};static struct e1000_info e1000_ich9_info = {	.mac			= e1000_ich9lan,	.flags			= FLAG_HAS_JUMBO_FRAMES				  | FLAG_IS_ICH				  | FLAG_HAS_WOL				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_HAS_AMT				  | FLAG_HAS_ERT				  | FLAG_HAS_FLASH				  | FLAG_APME_IN_WUC,	.pba			= 10,	.init_ops		= e1000_init_function_pointers_ich8lan,	.get_variants		= e1000_get_variants_ich8lan,};static struct e1000_info e1000_ich10_info = {	.mac			= e1000_ich10lan,	.flags			= FLAG_HAS_JUMBO_FRAMES				  | FLAG_IS_ICH				  | FLAG_HAS_WOL				  | FLAG_RX_CSUM_ENABLED				  | FLAG_HAS_CTRLEXT_ON_LOAD				  | FLAG_HAS_AMT				  | FLAG_HAS_ERT				  | FLAG_HAS_FLASH				  | FLAG_APME_IN_WUC,	.pba			= 10,	.init_ops		= e1000_init_function_pointers_ich8lan,	.get_variants		= e1000_get_variants_ich8lan,};static const struct e1000_info *e1000_info_tbl[] = {	[board_82571]		= &e1000_82571_info,	[board_82572]		= &e1000_82572_info,	[board_82573]		= &e1000_82573_info,	[board_82574]		= &e1000_82574_info,	[board_80003es2lan]	= &e1000_es2_info,	[board_ich8lan]		= &e1000_ich8_info,	[board_ich9lan]		= &e1000_ich9_info,	[board_ich10lan]	= &e1000_ich10_info,};/** * e1000_desc_unused - calculate if we have unused descriptors **/static int e1000_desc_unused(struct e1000_ring *ring){	if (ring->next_to_clean > ring->next_to_use)		return ring->next_to_clean - ring->next_to_use - 1;	return ring->count + ring->next_to_clean - ring->next_to_use - 1;}/** * e1000_receive_skb - helper function to handle Rx indications * @adapter: board private structure * @status: descriptor status field as written by hardware * @vlan: descriptor vlan field as written by hardware (no le/be conversion) * @skb: pointer to sk_buff to be indicated to stack **/static void e1000_receive_skb(struct e1000_adapter *adapter,			      struct net_device *netdev,			      struct sk_buff *skb,			      u8 status, __le16 vlan){	skb->protocol = eth_type_trans(skb, netdev);#ifdef CONFIG_E1000E_NAPI	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,					 le16_to_cpu(vlan));	else		netif_receive_skb(skb);#else	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))		vlan_hwaccel_rx(skb, adapter->vlgrp, le16_to_cpu(vlan));	else		netif_rx(skb);#endif	netdev->last_rx = jiffies;}/** * e1000_rx_checksum - Receive Checksum Offload for 82543 * @adapter:     board private structure * @status_err:  receive descriptor status and error fields * @csum:	receive descriptor csum field * @sk_buff:     socket buffer with received data **/static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,			      u32 csum, struct sk_buff *skb){	u16 status = (u16)status_err;	u8 errors = (u8)(status_err >> 24);	skb->ip_summed = CHECKSUM_NONE;	/* Ignore Checksum bit is set */	if (status & E1000_RXD_STAT_IXSM)		return;	/* TCP/UDP checksum error bit is set */	if (errors & E1000_RXD_ERR_TCPE) {		/* let the stack verify checksum errors */		adapter->hw_csum_err++;		return;	}	/* TCP/UDP Checksum has not been calculated */	if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)))		return;	/* It must be a TCP or UDP packet with a valid checksum */	if (status & E1000_RXD_STAT_TCPCS) {		/* TCP checksum is good */		skb->ip_summed = CHECKSUM_UNNECESSARY;	} else {		/*		 * IP fragment with UDP payload		 * Hardware complements the payload checksum, so we undo it		 * and then put the value in host order for further stack use.		 */		csum = ntohl(csum ^ 0xFFFF);		skb->csum = csum;		skb->ip_summed = CHECKSUM_COMPLETE;	}	adapter->hw_csum_good++;}/** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,				   int cleaned_count){	struct net_device *netdev = adapter->netdev;	struct pci_dev *pdev = adapter->pdev;	struct e1000_ring *rx_ring = adapter->rx_ring;	struct e1000_rx_desc *rx_desc;	struct e1000_buffer *buffer_info;	struct sk_buff *skb;	unsigned int i;	unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;	i = rx_ring->next_to_use;	buffer_info = &rx_ring->buffer_info[i];	while (cleaned_count--) {		skb = buffer_info->skb;		if (skb) {			skb_trim(skb, 0);			goto map_skb;		}		skb = netdev_alloc_skb(netdev, bufsz);		if (!skb) {			/* Better luck next round */			adapter->alloc_rx_buff_failed++;			break;		}		/*		 * Make buffer alignment 2 beyond a 16 byte boundary		 * this will result in a 16 byte aligned IP header after		 * the 14 byte MAC header is removed		 */		skb_reserve(skb, NET_IP_ALIGN);		buffer_info->skb = skb;map_skb:		buffer_info->dma = pci_map_single(pdev, skb->data,						  adapter->rx_buffer_len,						  PCI_DMA_FROMDEVICE);		if (pci_dma_mapping_error(pdev, buffer_info->dma)) {			dev_err(&pdev->dev, "RX DMA map failed\n");			adapter->rx_dma_failed++;			break;		}		rx_desc = E1000_RX_DESC(*rx_ring, i);		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);		i++;		if (i == rx_ring->count)			i = 0;		buffer_info = &rx_ring->buffer_info[i];	}	if (rx_ring->next_to_use != i) {		rx_ring->next_to_use = i;		if (i-- == 0)			i = (rx_ring->count - 1);		/*		 * Force memory writes to complete before letting h/w		 * know there are new descriptors to fetch.  (Only		 * applicable for weak-ordered memory model archs,		 * such as IA-64).		 */		wmb();		writel(i, adapter->hw.hw_addr + rx_ring->tail);	}}/** * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split * @adapter: address of board private structure **/static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,				      int cleaned_count){	struct net_device *netdev = adapter->netdev;	struct pci_dev *pdev = adapter->pdev;	union e1000_rx_desc_packet_split *rx_desc;	struct e1000_ring *rx_ring = adapter->rx_ring;	struct e1000_buffer *buffer_info;	struct e1000_ps_page *ps_page;	struct sk_buff *skb;	unsigned int i, j;	i = rx_ring->next_to_use;	buffer_info = &rx_ring->buffer_info[i];	while (cleaned_count--) {		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);		for (j = 0; j < PS_PAGE_BUFFERS; j++) {			ps_page = &buffer_info->ps_pages[j];			if (j >= adapter->rx_ps_pages) {				/* all unused desc entries get hw null ptr */				rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);				continue;			}			if (!ps_page->page) {				ps_page->page = alloc_page(GFP_ATOMIC);				if (!ps_page->page) {					adapter->alloc_rx_buff_failed++;					goto no_buffers;				}				ps_page->dma = pci_map_page(pdev,						   ps_page->page,						   0, PAGE_SIZE,						   PCI_DMA_FROMDEVICE);				if (pci_dma_mapping_error(pdev, ps_page->dma)) {					dev_err(&adapter->pdev->dev,					  "RX DMA page map failed\n");					adapter->rx_dma_failed++;					goto no_buffers;				}			}			/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -