e 1000駆動分析


linuxモジュール分析エントリ:module init関数
【2.6.31】

デバイス検出プロセス
static int __init e1000_init_module(void)
{
int ret;
printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s
", e1000e_driver_name, e1000e_driver_version); printk(KERN_INFO "%s: Copyright (c) 1999-2008 Intel Corporation.
", e1000e_driver_name); // ,82574 , pci 。 ret = pci_register_driver(&e1000_driver); pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name, PM_QOS_DEFAULT_VALUE); return ret; } /* PCI Device API Driver */ static struct pci_driver e1000_driver = { .name = e1000e_driver_name, /* table, pci pci , id id , probe ,struc t pci_dev *pdev , configure space */ .id_table = e1000_pci_tbl, // ,e1000_probe .probe = e1000_probe, .remove = __devexit_p(e1000_remove), #ifdef CONFIG_PM /* Power Management Hooks */ .suspend = e1000_suspend, .resume = e1000_resume, #endif .shutdown = e1000_shutdown, .err_handler = &e1000_err_handler };

2分析下probe関数
static int __devinit e1000_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *netdev;
struct e1000_adapter *adapter;
struct e1000_hw *hw;
const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
resource_size_t mmio_start, mmio_len;
resource_size_t flash_start, flash_len;
static int cards_found;
int i, err, pci_using_dac;
u16 eeprom_data = 0;
u16 eeprom_apme_mask = E1000_EEPROM_APME;
e1000e_disable_l1aspm(pdev);
err = pci_enable_device_mem(pdev);
if (err)
return err;
pci_using_dac = 0;
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (!err) {
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (!err)
pci_using_dac = 1;
} else {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
err = pci_set_consistent_dma_mask(pdev,
DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev, "No usable DMA "
"configuration, aborting
"); goto err_dma; } } } err = pci_request_selected_regions_exclusive(pdev, pci_select_bars(pdev, IORESOURCE_MEM), e1000e_driver_name); if (err) goto err_pci_reg; /* AER (Advanced Error Reporting) hooks */ err = pci_enable_pcie_error_reporting(pdev); if (err) { dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " "0x%x
", err); /* non-fatal, continue */ } pci_set_master(pdev); /* PCI config space info */ err = pci_save_state(pdev); if (err) goto err_alloc_etherdev; err = -ENOMEM; //e1000_addapter net_device , , 。 netdev = alloc_etherdev(sizeof(struct e1000_adapter)); if (!netdev) goto err_alloc_etherdev; // pci_dev -->net_device-->e1000_adapter SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); adapter = netdev_priv(netdev); hw = &adapter->hw; //e1000_adapter net_device pci_dev adapter->netdev = netdev; adapter->pdev = pdev; adapter->ei = ei; adapter->pba = ei->pba; adapter->flags = ei->flags; adapter->flags2 = ei->flags2; adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; adapter->max_hw_frame_size = ei->max_hw_frame_size; adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; // 0 bar mmio_start = pci_resource_start(pdev, 0); mmio_len = pci_resource_len(pdev, 0); err = -EIO; //ioremap adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); if (!adapter->hw.hw_addr) goto err_ioremap; //1 flash if ((adapter->flags & FLAG_HAS_FLASH) && (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { flash_start = pci_resource_start(pdev, 1); flash_len = pci_resource_len(pdev, 1); adapter->hw.flash_address = ioremap(flash_start, flash_len); if (!adapter->hw.flash_address) goto err_flashmap; } /* construct the net_device struct */ /* */ netdev->netdev_ops = &e1000e_netdev_ops; /*ethtool */ e1000e_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; /*napi */ netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; adapter->bd_number = cards_found++; e1000e_check_options(adapter); /* setup adapter struct */ /* , , 。 */ err = e1000_sw_init(adapter); if (err) goto err_sw_init; err = -EIO; memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops)); memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); err = ei->get_variants(adapter); if (err) goto err_hw_init; if ((adapter->flags & FLAG_IS_ICH) && (adapter->flags & FLAG_READ_ONLY_NVM)) e1000e_write_protect_nvm_ich8lan(&adapter->hw); hw->mac.ops.get_bus_info(&adapter->hw); adapter->hw.phy.autoneg_wait_to_complete = 0; /* Copper options */ if (adapter->hw.phy.media_type == e1000_media_type_copper) { adapter->hw.phy.mdix = AUTO_ALL_MODES; adapter->hw.phy.disable_polarity_correction = 0; adapter->hw.phy.ms_type = e1000_ms_hw_default; } if (e1000_check_reset_block(&adapter->hw)) e_info("PHY reset is blocked due to SOL/IDER session.
"); netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) netdev->features |= NETIF_F_HW_VLAN_FILTER; netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_HW_CSUM; netdev->vlan_features |= NETIF_F_SG; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; if (e1000e_enable_mng_pass_thru(&adapter->hw)) adapter->flags |= FLAG_MNG_PT_ENABLED; /* * before reading the NVM, reset the controller to * put the device in a known good starting state */ adapter->hw.mac.ops.reset_hw(&adapter->hw); /* * systems with ASPM and others may see the checksum fail on the first * attempt. Let's give it a few tries */ for (i = 0;; i++) { if (e1000_validate_nvm_checksum(&adapter->hw) >= 0) break; if (i == 2) { e_err("The NVM Checksum Is Not Valid
"); err = -EIO; goto err_eeprom; } } e1000_eeprom_checks(adapter); /* copy the MAC address out of the NVM */ if (e1000e_read_mac_addr(&adapter->hw)) e_err("NVM Read Error while reading MAC address
"); memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { e_err("Invalid MAC Address: %pM
", netdev->perm_addr); err = -EIO; goto err_eeprom; } /*watchdog */ init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &e1000_watchdog; adapter->watchdog_timer.data = (unsigned long) adapter; init_timer(&adapter->phy_info_timer); adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; /* work_struct*/ INIT_WORK(&adapter->reset_task, e1000_reset_task); INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; adapter->fc_autoneg = 1; adapter->hw.fc.requested_mode = e1000_fc_default; adapter->hw.fc.current_mode = e1000_fc_default; adapter->hw.phy.autoneg_advertised = 0x2f; /* ring size defaults */ adapter->rx_ring->count = 256; adapter->tx_ring->count = 256; /* * Initial Wake on LAN setting - If APM wake is enabled in * the EEPROM, enable the ACPI Magic Packet filter */ if (adapter->flags & FLAG_APME_IN_WUC) { /* APME bit in EEPROM is mapped to WUC.APME */ eeprom_data = er32(WUC); eeprom_apme_mask = E1000_WUC_APME; if (eeprom_data & E1000_WUC_PHY_WAKE) adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP; } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) e1000_read_nvm(&adapter->hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); else e1000_read_nvm(&adapter->hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); } /* fetch WoL from EEPROM */ if (eeprom_data & eeprom_apme_mask) adapter->eeprom_wol |= E1000_WUFC_MAG; /* * now that we have the eeprom settings, apply the special cases * where the eeprom may be wrong or the board simply won't support * wake on lan on a particular port */ if (!(adapter->flags & FLAG_HAS_WOL)) adapter->eeprom_wol = 0; /* initialize the wol settings based on the eeprom settings */ adapter->wol = adapter->eeprom_wol; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); /* save off EEPROM version number */ e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); /* reset the hardware with the new settings */ e1000e_reset(adapter); /* * If the controller has AMT, do not set DRV_LOAD until the interface * is up. For all other cases, let the f/w know that the h/w is now * under the control of the driver. */ if (!(adapter->flags & FLAG_HAS_AMT)) e1000_get_hw_control(adapter); strcpy(netdev->name, "eth%d"); /* , net_device */ err = register_netdev(netdev); if (err) goto err_register; /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); /* */ e1000_print_device_info(adapter); return 0; err_register: if (!(adapter->flags & FLAG_HAS_AMT)) e1000_release_hw_control(adapter); err_eeprom: if (!e1000_check_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); err_hw_init: kfree(adapter->tx_ring); kfree(adapter->rx_ring); err_sw_init: if (adapter->hw.flash_address) iounmap(adapter->hw.flash_address); e1000e_reset_interrupt_capability(adapter); err_flashmap: iounmap(adapter->hw.hw_addr); err_ioremap: free_netdev(netdev); err_alloc_etherdev: pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); err_pci_reg: err_dma: pci_disable_device(pdev); return err; } e1000e /** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure * * Returns 0 on success, negative value on failure * * The open entry point is called when a network interface is made * active by the system (IFF_UP). At this point all resources needed * for transmit and receive operations are allocated, the interrupt * handler is registered with the OS, the watchdog timer is started, * and the stack is notified that the interface is ready. **/ static int e1000_open(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int err; /* disallow open during test */ if (test_bit(__E1000_TESTING, &adapter->state)) return -EBUSY; netif_carrier_off(netdev); /* allocate transmit descriptors */ err = e1000e_setup_tx_resources(adapter); if (err) goto err_setup_tx; /* allocate receive descriptors */ err = e1000e_setup_rx_resources(adapter); if (err) goto err_setup_rx; e1000e_power_up_phy(adapter); adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) e1000_update_mng_vlan(adapter); /* * If AMT is enabled, let the firmware know that the network * interface is now open */ if (adapter->flags & FLAG_HAS_AMT) e1000_get_hw_control(adapter); /* * before we allocate an interrupt, we must be ready to handle it. * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt * as soon as we call pci_request_irq, so we have to setup our * clean_rx handler before we do so. */ e1000_configure(adapter); err = e1000_request_irq(adapter); if (err) goto err_req_irq; /* * Work around PCIe errata with MSI interrupts causing some chipsets to * ignore e1000e MSI messages, which means we need to test our MSI * interrupt now */ if (adapter->int_mode != E1000E_INT_MODE_LEGACY) { err = e1000_test_msi(adapter); if (err) { e_err("Interrupt allocation failed
"); goto err_req_irq; } } /* From here on the code is the same as e1000e_up() */ clear_bit(__E1000_DOWN, &adapter->state); napi_enable(&adapter->napi); e1000_irq_enable(adapter); netif_start_queue(netdev); /* fire a link status change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); return 0; err_req_irq: e1000_release_hw_control(adapter); e1000_power_down_phy(adapter); e1000e_free_rx_resources(adapter); err_setup_rx: e1000e_free_tx_resources(adapter); err_setup_tx: e1000e_reset(adapter); return err; }