netxen_nic_main.c

来自「linux 内核源代码」· C语言 代码 · 共 1,360 行 · 第 1/3 页

C
1,360
字号
/* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that 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., 59 Temple Place - Suite 330, Boston, * MA  02111-1307, USA. * * The full GNU General Public License is included in this distribution * in the file called LICENSE. * * Contact Information: *    info@netxen.com * NetXen, * 3965 Freedom Circle, Fourth floor, * Santa Clara, CA 95054 * * *  Main source file for NetXen NIC Driver on Linux * */#include <linux/vmalloc.h>#include <linux/highmem.h>#include "netxen_nic_hw.h"#include "netxen_nic.h"#include "netxen_nic_phan_reg.h"#include <linux/dma-mapping.h>#include <net/ip.h>MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");MODULE_LICENSE("GPL");MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);char netxen_nic_driver_name[] = "netxen_nic";static char netxen_nic_driver_string[] = "NetXen Network Driver version "    NETXEN_NIC_LINUX_VERSIONID;#define NETXEN_NETDEV_WEIGHT 120#define NETXEN_ADAPTER_UP_MAGIC 777#define NETXEN_NIC_PEG_TUNE 0/* Local functions to NetXen NIC driver */static int __devinit netxen_nic_probe(struct pci_dev *pdev,				      const struct pci_device_id *ent);static void __devexit netxen_nic_remove(struct pci_dev *pdev);static int netxen_nic_open(struct net_device *netdev);static int netxen_nic_close(struct net_device *netdev);static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);static void netxen_tx_timeout(struct net_device *netdev);static void netxen_tx_timeout_task(struct work_struct *work);static void netxen_watchdog(unsigned long);static int netxen_handle_int(struct netxen_adapter *, struct net_device *);static int netxen_nic_poll(struct napi_struct *napi, int budget);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void netxen_nic_poll_controller(struct net_device *netdev);#endifstatic irqreturn_t netxen_intr(int irq, void *data);int physical_port[] = {0, 1, 2, 3};/*  PCI Device ID Table  */static struct pci_device_id netxen_pci_tbl[] __devinitdata = {	{PCI_DEVICE(0x4040, 0x0001)},	{PCI_DEVICE(0x4040, 0x0002)},	{PCI_DEVICE(0x4040, 0x0003)},	{PCI_DEVICE(0x4040, 0x0004)},	{PCI_DEVICE(0x4040, 0x0005)},	{PCI_DEVICE(0x4040, 0x0024)},	{PCI_DEVICE(0x4040, 0x0025)},	{0,}};MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);struct workqueue_struct *netxen_workq;static void netxen_watchdog(unsigned long);static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,							uint32_t crb_producer){	switch (adapter->portnum) {		case 0:			writel(crb_producer, NETXEN_CRB_NORMALIZE					(adapter, CRB_CMD_PRODUCER_OFFSET));			return;		case 1:			writel(crb_producer, NETXEN_CRB_NORMALIZE					(adapter, CRB_CMD_PRODUCER_OFFSET_1));			return;		case 2:			writel(crb_producer, NETXEN_CRB_NORMALIZE					(adapter, CRB_CMD_PRODUCER_OFFSET_2));			return;		case 3:			writel(crb_producer, NETXEN_CRB_NORMALIZE					(adapter, CRB_CMD_PRODUCER_OFFSET_3));			return;		default:			printk(KERN_WARNING "We tried to update "					"CRB_CMD_PRODUCER_OFFSET for invalid "					"PCI function id %d\n",					adapter->portnum);			return;	}}static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,							u32 crb_consumer){	switch (adapter->portnum) {		case 0:			writel(crb_consumer, NETXEN_CRB_NORMALIZE				(adapter, CRB_CMD_CONSUMER_OFFSET));			return;		case 1:			writel(crb_consumer, NETXEN_CRB_NORMALIZE				(adapter, CRB_CMD_CONSUMER_OFFSET_1));			return;		case 2:			writel(crb_consumer, NETXEN_CRB_NORMALIZE				(adapter, CRB_CMD_CONSUMER_OFFSET_2));			return;		case 3:			writel(crb_consumer, NETXEN_CRB_NORMALIZE				(adapter, CRB_CMD_CONSUMER_OFFSET_3));			return;		default:			printk(KERN_WARNING "We tried to update "					"CRB_CMD_PRODUCER_OFFSET for invalid "					"PCI function id %d\n",					adapter->portnum);			return;	}}#define	ADAPTER_LIST_SIZE 12int netxen_cards_found;static void netxen_nic_disable_int(struct netxen_adapter *adapter){	uint32_t	mask = 0x7ff;	int retries = 32;	DPRINTK(1, INFO, "Entered ISR Disable \n");	switch (adapter->portnum) {	case 0:		writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));		break;	case 1:		writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));		break;	case 2:		writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));		break;	case 3:		writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));		break;	}	if (adapter->intr_scheme != -1 &&	    adapter->intr_scheme != INTR_SCHEME_PERPORT)		writel(mask,PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));	/* Window = 0 or 1 */	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {		do {			writel(0xffffffff,			       PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_TARGET_STATUS));			mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));			if (!(mask & 0x80))				break;			udelay(10);		} while (--retries);		if (!retries) {			printk(KERN_NOTICE "%s: Failed to disable interrupt completely\n",					netxen_nic_driver_name);		}	}	DPRINTK(1, INFO, "Done with Disable Int\n");}static void netxen_nic_enable_int(struct netxen_adapter *adapter){	u32 mask;	DPRINTK(1, INFO, "Entered ISR Enable \n");	if (adapter->intr_scheme != -1 &&		adapter->intr_scheme != INTR_SCHEME_PERPORT) {		switch (adapter->ahw.board_type) {		case NETXEN_NIC_GBE:			mask  =  0x77b;			break;		case NETXEN_NIC_XGBE:			mask  =  0x77f;			break;		default:			mask  =  0x7ff;			break;		}		writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));	}	switch (adapter->portnum) {	case 0:		writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));		break;	case 1:		writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));		break;	case 2:		writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));		break;	case 3:		writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));		break;	}	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {		mask = 0xbff;		if (adapter->intr_scheme != -1 &&			adapter->intr_scheme != INTR_SCHEME_PERPORT) {			writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));		}		writel(mask,		       PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_TARGET_MASK));	}	DPRINTK(1, INFO, "Done with enable Int\n");}/* * netxen_nic_probe() * * The Linux system will invoke this after identifying the vendor ID and * device Id in the pci_tbl supported by this module. * * A quad port card has one operational PCI config space, (function 0), * which is used to access all four ports. * * This routine will initialize the adapter, and setup the global parameters * along with the port's specific structure. */static int __devinitnetxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent){	struct net_device *netdev = NULL;	struct netxen_adapter *adapter = NULL;	void __iomem *mem_ptr0 = NULL;	void __iomem *mem_ptr1 = NULL;	void __iomem *mem_ptr2 = NULL;	unsigned long first_page_group_end;	unsigned long first_page_group_start;	u8 __iomem *db_ptr = NULL;	unsigned long mem_base, mem_len, db_base, db_len;	int pci_using_dac, i = 0, err;	int ring;	struct netxen_recv_context *recv_ctx = NULL;	struct netxen_rcv_desc_ctx *rcv_desc = NULL;	struct netxen_cmd_buffer *cmd_buf_arr = NULL;	u64 mac_addr[FLASH_NUM_PORTS + 1];	int valid_mac = 0;	u32 val;	int pci_func_id = PCI_FUNC(pdev->devfn);	DECLARE_MAC_BUF(mac);	printk(KERN_INFO "%s \n", netxen_nic_driver_string);	if (pdev->class != 0x020000) {		printk(KERN_ERR"NetXen function %d, class %x will not"				"be enabled.\n",pci_func_id, pdev->class);		return -ENODEV;	}	if ((err = pci_enable_device(pdev)))		return err;	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {		err = -ENODEV;		goto err_out_disable_pdev;	}	if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))		goto err_out_disable_pdev;	pci_set_master(pdev);	if (pdev->revision == NX_P2_C1 &&	    (pci_set_dma_mask(pdev, DMA_35BIT_MASK) == 0) &&	    (pci_set_consistent_dma_mask(pdev, DMA_35BIT_MASK) == 0)) {		pci_using_dac = 1;	} else {		if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||		    (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)))			goto err_out_free_res;		pci_using_dac = 0;	}	netdev = alloc_etherdev(sizeof(struct netxen_adapter));	if(!netdev) {		printk(KERN_ERR"%s: Failed to allocate memory for the "				"device block.Check system memory resource"				" usage.\n", netxen_nic_driver_name);		goto err_out_free_res;	}	SET_NETDEV_DEV(netdev, &pdev->dev);	adapter = netdev->priv;	adapter->ahw.pdev = pdev;	adapter->ahw.pci_func  = pci_func_id;	spin_lock_init(&adapter->tx_lock);	/* remap phys address */	mem_base = pci_resource_start(pdev, 0);	/* 0 is for BAR 0 */	mem_len = pci_resource_len(pdev, 0);	/* 128 Meg of memory */	if (mem_len == NETXEN_PCI_128MB_SIZE) {		mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);		mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,				SECOND_PAGE_GROUP_SIZE);		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,				THIRD_PAGE_GROUP_SIZE);		first_page_group_start = FIRST_PAGE_GROUP_START;		first_page_group_end   = FIRST_PAGE_GROUP_END;	} else if (mem_len == NETXEN_PCI_32MB_SIZE) {		mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -			SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);		first_page_group_start = 0;		first_page_group_end   = 0;	} else {		err = -EIO; 		goto err_out_free_netdev;	}	if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||			(mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {		DPRINTK(ERR,			"Cannot remap adapter memory aborting.:"			"0 -> %p, 1 -> %p, 2 -> %p\n",			mem_ptr0, mem_ptr1, mem_ptr2);		err = -EIO;		goto err_out_iounmap;	}	db_base = pci_resource_start(pdev, 4);	/* doorbell is on bar 4 */	db_len = pci_resource_len(pdev, 4);	if (db_len == 0) {		printk(KERN_ERR "%s: doorbell is disabled\n",		       netxen_nic_driver_name);		err = -EIO;		goto err_out_iounmap;	}	DPRINTK(INFO, "doorbell ioremap from %lx a size of %lx\n", db_base,		db_len);	db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);	if (!db_ptr) {		printk(KERN_ERR "%s: Failed to allocate doorbell map.",		       netxen_nic_driver_name);		err = -EIO;		goto err_out_iounmap;	}	DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);	adapter->ahw.pci_base0 = mem_ptr0;	adapter->ahw.first_page_group_start = first_page_group_start;	adapter->ahw.first_page_group_end   = first_page_group_end;	adapter->ahw.pci_base1 = mem_ptr1;	adapter->ahw.pci_base2 = mem_ptr2;	adapter->ahw.db_base = db_ptr;	adapter->ahw.db_len = db_len;	adapter->netdev  = netdev;	adapter->pdev    = pdev;	netif_napi_add(netdev, &adapter->napi,		       netxen_nic_poll, NETXEN_NETDEV_WEIGHT);	/* this will be read from FW later */	adapter->intr_scheme = -1;	/* This will be reset for mezz cards  */	adapter->portnum = pci_func_id;	adapter->status   &= ~NETXEN_NETDEV_STATUS;	adapter->rx_csum = 1;	netdev->open		   = netxen_nic_open;	netdev->stop		   = netxen_nic_close;	netdev->hard_start_xmit    = netxen_nic_xmit_frame;	netdev->get_stats	   = netxen_nic_get_stats;		netdev->set_multicast_list = netxen_nic_set_multi;	netdev->set_mac_address    = netxen_nic_set_mac;	netdev->change_mtu	   = netxen_nic_change_mtu;	netdev->tx_timeout	   = netxen_tx_timeout;	netdev->watchdog_timeo     = HZ;	netxen_nic_change_mtu(netdev, netdev->mtu);	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);#ifdef CONFIG_NET_POLL_CONTROLLER	netdev->poll_controller = netxen_nic_poll_controller;#endif	/* ScatterGather support */	netdev->features = NETIF_F_SG;	netdev->features |= NETIF_F_IP_CSUM;	netdev->features |= NETIF_F_TSO;	if (pci_using_dac)		netdev->features |= NETIF_F_HIGHDMA;	if (pci_enable_msi(pdev))		adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;	else		adapter->flags |= NETXEN_NIC_MSI_ENABLED;	netdev->irq = pdev->irq;	INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);	/*	 * Set the CRB window to invalid. If any register in window 0 is	 * accessed it should set the window to 0 and then reset it to 1.	 */	adapter->curr_window = 255;	/* initialize the adapter */	netxen_initialize_adapter_hw(adapter);	/*	 *  Adapter in our case is quad port so initialize it before	 *  initializing the ports

⌨️ 快捷键说明

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