📄 ixgb_main.c
字号:
/******************************************************************************* Copyright(c) 1999 - 2005 Intel Corporation. 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: Linux NICS <linux.nics@intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************/#include "ixgb.h"/* Change Log * 1.0.96 04/19/05 * - Make needlessly global code static -- bunk@stusta.de * - ethtool cleanup -- shemminger@osdl.org * - Support for MODULE_VERSION -- linville@tuxdriver.com * - add skb_header_cloned check to the tso path -- herbert@apana.org.au * 1.0.88 01/05/05 * - include fix to the condition that determines when to quit NAPI - Robert Olsson * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down * 1.0.84 10/26/04 * - reset buffer_info->dma in Tx resource cleanup logic * 1.0.83 10/12/04 * - sparse cleanup - shemminger@osdl.org * - fix tx resource cleanup logic */char ixgb_driver_name[] = "ixgb";static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";#ifndef CONFIG_IXGB_NAPI#define DRIVERNAPI#else#define DRIVERNAPI "-NAPI"#endif#define DRV_VERSION "1.0.100-k2"DRIVERNAPIchar ixgb_driver_version[] = DRV_VERSION;static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";/* ixgb_pci_tbl - PCI Device ID Table * * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */static struct pci_device_id ixgb_pci_tbl[] = { {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_SR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_LR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* required last entry */ {0,}};MODULE_DEVICE_TABLE(pci, ixgb_pci_tbl);/* Local Function Prototypes */int ixgb_up(struct ixgb_adapter *adapter);void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog);void ixgb_reset(struct ixgb_adapter *adapter);int ixgb_setup_tx_resources(struct ixgb_adapter *adapter);int ixgb_setup_rx_resources(struct ixgb_adapter *adapter);void ixgb_free_tx_resources(struct ixgb_adapter *adapter);void ixgb_free_rx_resources(struct ixgb_adapter *adapter);void ixgb_update_stats(struct ixgb_adapter *adapter);static int ixgb_init_module(void);static void ixgb_exit_module(void);static int ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);static void __devexit ixgb_remove(struct pci_dev *pdev);static int ixgb_sw_init(struct ixgb_adapter *adapter);static int ixgb_open(struct net_device *netdev);static int ixgb_close(struct net_device *netdev);static void ixgb_configure_tx(struct ixgb_adapter *adapter);static void ixgb_configure_rx(struct ixgb_adapter *adapter);static void ixgb_setup_rctl(struct ixgb_adapter *adapter);static void ixgb_clean_tx_ring(struct ixgb_adapter *adapter);static void ixgb_clean_rx_ring(struct ixgb_adapter *adapter);static void ixgb_set_multi(struct net_device *netdev);static void ixgb_watchdog(unsigned long data);static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev);static struct net_device_stats *ixgb_get_stats(struct net_device *netdev);static int ixgb_change_mtu(struct net_device *netdev, int new_mtu);static int ixgb_set_mac(struct net_device *netdev, void *p);static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs);static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);#ifdef CONFIG_IXGB_NAPIstatic int ixgb_clean(struct net_device *netdev, int *budget);static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do);#elsestatic boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter);#endifstatic void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter);void ixgb_set_ethtool_ops(struct net_device *netdev);static void ixgb_tx_timeout(struct net_device *dev);static void ixgb_tx_timeout_task(struct net_device *dev);static void ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);static void ixgb_restore_vlan(struct ixgb_adapter *adapter);#ifdef CONFIG_NET_POLL_CONTROLLER/* for netdump / net console */static void ixgb_netpoll(struct net_device *dev);#endif/* Exported from other modules */extern void ixgb_check_options(struct ixgb_adapter *adapter);static struct pci_driver ixgb_driver = { .name = ixgb_driver_name, .id_table = ixgb_pci_tbl, .probe = ixgb_probe, .remove = __devexit_p(ixgb_remove),};MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);/* some defines for controlling descriptor fetches in h/w */#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below * this */#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail * is pushed this many descriptors * from head *//** * ixgb_init_module - Driver Registration Routine * * ixgb_init_module is the first routine called when the driver is * loaded. All it does is register with the PCI subsystem. **/static int __initixgb_init_module(void){ printk(KERN_INFO "%s - version %s\n", ixgb_driver_string, ixgb_driver_version); printk(KERN_INFO "%s\n", ixgb_copyright); return pci_module_init(&ixgb_driver);}module_init(ixgb_init_module);/** * ixgb_exit_module - Driver Exit Cleanup Routine * * ixgb_exit_module is called just before the driver is removed * from memory. **/static void __exitixgb_exit_module(void){ pci_unregister_driver(&ixgb_driver);}module_exit(ixgb_exit_module);/** * ixgb_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/static inline voidixgb_irq_disable(struct ixgb_adapter *adapter){ atomic_inc(&adapter->irq_sem); IXGB_WRITE_REG(&adapter->hw, IMC, ~0); IXGB_WRITE_FLUSH(&adapter->hw); synchronize_irq(adapter->pdev->irq);}/** * ixgb_irq_enable - Enable default interrupt generation settings * @adapter: board private structure **/static inline voidixgb_irq_enable(struct ixgb_adapter *adapter){ if(atomic_dec_and_test(&adapter->irq_sem)) { IXGB_WRITE_REG(&adapter->hw, IMS, IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | IXGB_INT_LSC); IXGB_WRITE_FLUSH(&adapter->hw); }}intixgb_up(struct ixgb_adapter *adapter){ struct net_device *netdev = adapter->netdev; int err; int max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; struct ixgb_hw *hw = &adapter->hw; /* hardware has been reset, we need to reload some things */ ixgb_set_multi(netdev); ixgb_restore_vlan(adapter); ixgb_configure_tx(adapter); ixgb_setup_rctl(adapter); ixgb_configure_rx(adapter); ixgb_alloc_rx_buffers(adapter);#ifdef CONFIG_PCI_MSI { boolean_t pcix = (IXGB_READ_REG(&adapter->hw, STATUS) & IXGB_STATUS_PCIX_MODE) ? TRUE : FALSE; adapter->have_msi = TRUE; if (!pcix) adapter->have_msi = FALSE; else if((err = pci_enable_msi(adapter->pdev))) { printk (KERN_ERR "Unable to allocate MSI interrupt Error: %d\n", err); adapter->have_msi = FALSE; /* proceed to try to request regular interrupt */ } }#endif if((err = request_irq(adapter->pdev->irq, &ixgb_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) return err; /* disable interrupts and get the hardware into a known state */ IXGB_WRITE_REG(&adapter->hw, IMC, 0xffffffff); if((hw->max_frame_size != max_frame) || (hw->max_frame_size != (IXGB_READ_REG(hw, MFS) >> IXGB_MFS_SHIFT))) { hw->max_frame_size = max_frame; IXGB_WRITE_REG(hw, MFS, hw->max_frame_size << IXGB_MFS_SHIFT); if(hw->max_frame_size > IXGB_MAX_ENET_FRAME_SIZE_WITHOUT_FCS + ENET_FCS_LENGTH) { uint32_t ctrl0 = IXGB_READ_REG(hw, CTRL0); if(!(ctrl0 & IXGB_CTRL0_JFE)) { ctrl0 |= IXGB_CTRL0_JFE; IXGB_WRITE_REG(hw, CTRL0, ctrl0); } } } mod_timer(&adapter->watchdog_timer, jiffies); ixgb_irq_enable(adapter);#ifdef CONFIG_IXGB_NAPI netif_poll_enable(netdev);#endif return 0;}voidixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog){ struct net_device *netdev = adapter->netdev; ixgb_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev);#ifdef CONFIG_PCI_MSI if(adapter->have_msi == TRUE) pci_disable_msi(adapter->pdev);#endif if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer);#ifdef CONFIG_IXGB_NAPI netif_poll_disable(netdev);#endif adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); netif_stop_queue(netdev); ixgb_reset(adapter); ixgb_clean_tx_ring(adapter); ixgb_clean_rx_ring(adapter);}voidixgb_reset(struct ixgb_adapter *adapter){ ixgb_adapter_stop(&adapter->hw); if(!ixgb_init_hw(&adapter->hw)) IXGB_DBG("ixgb_init_hw failed.\n");}/** * ixgb_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in ixgb_pci_tbl * * Returns 0 on success, negative on failure * * ixgb_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. **/static int __devinitixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *netdev = NULL; struct ixgb_adapter *adapter; static int cards_found = 0; unsigned long mmio_start; int mmio_len; int pci_using_dac; int i; int err; if((err = pci_enable_device(pdev))) return err; if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { IXGB_ERR("No usable DMA configuration, aborting\n"); return err; } pci_using_dac = 0; } if((err = pci_request_regions(pdev, ixgb_driver_name))) return err; pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct ixgb_adapter)); if(!netdev) { err = -ENOMEM; goto err_alloc_etherdev; } SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->hw.back = adapter; mmio_start = pci_resource_start(pdev, BAR_0); mmio_len = pci_resource_len(pdev, BAR_0); adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); if(!adapter->hw.hw_addr) { err = -EIO; goto err_ioremap; } for(i = BAR_1; i <= BAR_5; i++) { if(pci_resource_len(pdev, i) == 0) continue; if(pci_resource_flags(pdev, i) & IORESOURCE_IO) { adapter->hw.io_base = pci_resource_start(pdev, i); break; } } netdev->open = &ixgb_open; netdev->stop = &ixgb_close; netdev->hard_start_xmit = &ixgb_xmit_frame; netdev->get_stats = &ixgb_get_stats; netdev->set_multicast_list = &ixgb_set_multi; netdev->set_mac_address = &ixgb_set_mac; netdev->change_mtu = &ixgb_change_mtu; ixgb_set_ethtool_ops(netdev); netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = HZ;#ifdef CONFIG_IXGB_NAPI netdev->poll = &ixgb_clean; netdev->weight = 64;#endif netdev->vlan_rx_register = ixgb_vlan_rx_register; netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid;#ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = ixgb_netpoll;#endif netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; netdev->base_addr = adapter->hw.io_base; adapter->bd_number = cards_found; adapter->link_speed = 0; adapter->link_duplex = 0; /* setup the private structure */ if((err = ixgb_sw_init(adapter))) goto err_sw_init; netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;#ifdef NETIF_F_TSO netdev->features |= NETIF_F_TSO;#endif if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; /* make sure the EEPROM is good */ if(!ixgb_validate_eeprom_checksum(&adapter->hw)) { printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n"); err = -EIO; goto err_eeprom; } ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); if(!is_valid_ether_addr(netdev->perm_addr)) { err = -EIO; goto err_eeprom; } adapter->part_num = ixgb_get_ee_pba_number(&adapter->hw); init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &ixgb_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; INIT_WORK(&adapter->tx_timeout_task, (void (*)(void *))ixgb_tx_timeout_task, netdev); if((err = register_netdev(netdev))) goto err_register; /* we're going to reset, so assume we have no link for now */ netif_carrier_off(netdev); netif_stop_queue(netdev); printk(KERN_INFO "%s: Intel(R) PRO/10GbE Network Connection\n", netdev->name); ixgb_check_options(adapter); /* reset the hardware with the new settings */ ixgb_reset(adapter); cards_found++; return 0;err_register:err_sw_init:err_eeprom: iounmap(adapter->hw.hw_addr);err_ioremap: free_netdev(netdev);err_alloc_etherdev: pci_release_regions(pdev); return err;}/** * ixgb_remove - Device Removal Routine * @pdev: PCI device information struct * * ixgb_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. The could be caused by a * Hot-Plug event, or because the driver is going to be removed from * memory. **/static void __devexitixgb_remove(struct pci_dev *pdev){ struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); free_netdev(netdev);}/** * ixgb_sw_init - Initialize general software structures (struct ixgb_adapter)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -