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 + -
显示快捷键?