📄 netdev.c
字号:
struct e1000_hw *hw = &adapter->hw;#endif /* Write the ITR value calculated at the end of the * previous interrupt. */ if (adapter->rx_ring->set_itr) { writel(1000000000 / (adapter->rx_ring->itr_val * 256), adapter->hw.hw_addr + adapter->rx_ring->itr_register); adapter->rx_ring->set_itr = 0; } #ifdef CONFIG_E1000E_NAPI if (netif_rx_schedule_prep(netdev, &adapter->napi)) { adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0;#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0;#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ __netif_rx_schedule(netdev, &adapter->napi); }#else adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0;#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0;#endif for (i = 0; i < E1000_MAX_INTR; i++) { int rx_cleaned = adapter->clean_rx(adapter);#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER int tx_cleaned_complete = e1000_clean_tx_irq(adapter); if (!rx_cleaned && tx_cleaned_complete)#else if (!rx_cleaned)#endif goto out; } /* If we got here, the ring was not completely cleaned, * so fire another interrupt. */ ew32(ICS, adapter->rx_ring->ims_val);out:#endif /* CONFIG_E1000E_NAPI */ return IRQ_HANDLED;}/** * e1000_configure_msix - Configure MSI-X hardware * * e1000_configure_msix sets up the hardware to properly * generate MSI-X interrupts. **/static void e1000_configure_msix(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; struct e1000_ring *rx_ring = adapter->rx_ring; struct e1000_ring *tx_ring = adapter->tx_ring; int vector = 0; u32 ctrl_ext, ivar = 0; adapter->eiac_mask = 0; /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ if (hw->mac.type == e1000_82574) { u32 rfctl = er32(RFCTL); rfctl |= E1000_RFCTL_ACK_DIS; ew32(RFCTL, rfctl); }#define E1000_IVAR_INT_ALLOC_VALID 0x8 /* Configure Rx vector */ rx_ring->ims_val = E1000_IMS_RXQ0; adapter->eiac_mask |= rx_ring->ims_val; if (rx_ring->itr_val) writel(1000000000 / (rx_ring->itr_val * 256), hw->hw_addr + rx_ring->itr_register); else writel(1, hw->hw_addr + rx_ring->itr_register); ivar = E1000_IVAR_INT_ALLOC_VALID | vector; /* Configure Tx vector */ tx_ring->ims_val = E1000_IMS_TXQ0;#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER vector++; if (tx_ring->itr_val) writel(1000000000 / (tx_ring->itr_val * 256), hw->hw_addr + tx_ring->itr_register); else writel(1, hw->hw_addr + tx_ring->itr_register);#else rx_ring->ims_val |= tx_ring->ims_val;#endif adapter->eiac_mask |= tx_ring->ims_val; ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8); /* set vector for Other Causes, e.g. link changes */ vector++; ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16); if (rx_ring->itr_val) writel(1000000000 / (rx_ring->itr_val * 256), hw->hw_addr + E1000_EITR_82574(vector)); else writel(1, hw->hw_addr + E1000_EITR_82574(vector)); /* Cause Tx interrupts on every write back */ ivar |= (1 << 31); ew32(IVAR, ivar); /* enable MSI-X PBA support */ ctrl_ext = er32(CTRL_EXT); ctrl_ext |= E1000_CTRL_EXT_PBA_CLR; /* Auto-Mask Other interrupts upon ICR read */ ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER); ctrl_ext |= E1000_CTRL_EXT_EIAME; ew32(CTRL_EXT, ctrl_ext); e1e_flush();}void e1000_reset_interrupt_capability(struct e1000_adapter *adapter){ if (adapter->msix_entries) { pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; } else if (adapter->flags & FLAG_MSI_ENABLED) { pci_disable_msi(adapter->pdev); adapter->flags &= ~FLAG_MSI_ENABLED; } return;}/** * e1000_set_interrupt_capability - set MSI or MSI-X if supported * * Attempt to configure interrupts using the best available * capabilities of the hardware and kernel. **/void e1000_set_interrupt_capability(struct e1000_adapter *adapter){ int err; int numvecs, i; switch (adapter->int_mode) { case E1000E_INT_MODE_MSIX: if (adapter->flags & FLAG_HAS_MSIX) {#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER numvecs = 3; /* RxQ0, TxQ0 and other */#else numvecs = 2; /* RxQ0/TxQ0 and other */#endif adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), GFP_KERNEL); if (adapter->msix_entries) { for (i=0; i < numvecs; i++) adapter->msix_entries[i].entry = i; err = pci_enable_msix(adapter->pdev, adapter->msix_entries, numvecs); if (err == 0) return; } /* MSI-X failed, so fall through and try MSI */ e_err("Failed to initialize MSI-X interrupts. " "Falling back to MSI interrupts.\n"); e1000_reset_interrupt_capability(adapter); } adapter->int_mode = E1000E_INT_MODE_MSI; /* Fall through */ case E1000E_INT_MODE_MSI: if (!pci_enable_msi(adapter->pdev)) { adapter->flags |= FLAG_MSI_ENABLED; } else { adapter->int_mode = E1000E_INT_MODE_LEGACY; e_err("Failed to initialize MSI interrupts. Falling " "back to legacy interrupts.\n"); } /* Fall through */ case E1000E_INT_MODE_LEGACY: /* Don't do anything; this is the system default */ break; } return;}/** * e1000_request_msix - Initialize MSI-X interrupts * * e1000_request_msix allocates MSI-X vectors and requests interrupts from the * kernel. **/static int e1000_request_msix(struct e1000_adapter *adapter){ struct net_device *netdev = adapter->netdev; int err = 0, vector = 0; if (strlen(netdev->name) < (IFNAMSIZ - 5))#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);#else sprintf(adapter->rx_ring->name, "%s-Q0", netdev->name);#endif else memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, &e1000_intr_msix_rx, 0, adapter->rx_ring->name, netdev); if (err) goto out; adapter->rx_ring->itr_register = E1000_EITR_82574(vector); adapter->rx_ring->itr_val = adapter->itr; vector++;#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER if (strlen(netdev->name) < (IFNAMSIZ - 5)) sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); else memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, &e1000_intr_msix_tx, 0, adapter->tx_ring->name, netdev); if (err) goto out; adapter->tx_ring->itr_register = E1000_EITR_82574(vector); adapter->tx_ring->itr_val = adapter->itr; vector++;#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ err = request_irq(adapter->msix_entries[vector].vector, &e1000_msix_other, 0, netdev->name, netdev); if (err) goto out; e1000_configure_msix(adapter); return 0;out: return err;}#endif /* CONFIG_E1000E_MSIX *//** * e1000_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize **/static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter){ adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); if (!adapter->tx_ring) goto err; adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); if (!adapter->rx_ring) goto err; return 0;err: e_err("Unable to allocate memory for queues\n"); kfree(adapter->rx_ring); kfree(adapter->tx_ring); return -ENOMEM;}/** * e1000_request_irq - initialize interrupts * * Attempts to configure interrupts using the best available * capabilities of the hardware and kernel. **/static int e1000_request_irq(struct e1000_adapter *adapter){ struct net_device *netdev = adapter->netdev; int err;#ifdef CONFIG_E1000E_MSIX if (adapter->msix_entries) { err = e1000_request_msix(adapter); if (!err) return err; /* fall back to MSI */ e1000_reset_interrupt_capability(adapter); adapter->int_mode = E1000E_INT_MODE_MSI; e1000_set_interrupt_capability(adapter); } if (adapter->flags & FLAG_MSI_ENABLED) { err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, netdev->name, netdev); if (!err) return err; /* fall back to legacy interrupt */ e1000_reset_interrupt_capability(adapter); adapter->int_mode = E1000E_INT_MODE_LEGACY; } err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, netdev->name, netdev); if (err) e_err("Unable to allocate interrupt, Error: %d\n", err);#else int irq_flags = IRQF_SHARED; if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) { err = pci_enable_msi(adapter->pdev); if (!err) { adapter->flags |= FLAG_MSI_ENABLED; irq_flags = 0; } } err = request_irq(adapter->pdev->irq, ((adapter->flags & FLAG_MSI_ENABLED) ? &e1000_intr_msi : &e1000_intr), irq_flags, netdev->name, netdev); if (err) { if (adapter->flags & FLAG_MSI_ENABLED) { pci_disable_msi(adapter->pdev); adapter->flags &= ~FLAG_MSI_ENABLED; } e_err("Unable to allocate interrupt, Error: %d\n", err); }#endif /* CONFIG_E1000E_MSIX */ return err;}static void e1000_free_irq(struct e1000_adapter *adapter){ struct net_device *netdev = adapter->netdev;#ifdef CONFIG_E1000E_MSIX if (adapter->msix_entries) { int vector = 0; free_irq(adapter->msix_entries[vector].vector, netdev); vector++;#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER free_irq(adapter->msix_entries[vector].vector, netdev); vector++;#endif /* Other Causes interrupt vector */ free_irq(adapter->msix_entries[vector].vector, netdev); return; }#endif /* CONFIG_E1000E_MSIX */ free_irq(adapter->pdev->irq, netdev);#ifndef CONFIG_E1000E_MSIX if (adapter->flags & FLAG_MSI_ENABLED) { pci_disable_msi(adapter->pdev); adapter->flags &= ~FLAG_MSI_ENABLED; }#endif}/** * e1000_irq_disable - Mask off interrupt generation on the NIC **/static void e1000_irq_disable(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; ew32(IMC, ~0);#ifdef CONFIG_E1000E_MSIX if (adapter->msix_entries) { ew32(EIAC_82574, 0); }#endif /* CONFIG_E1000E_MSIX */ e1e_flush(); synchronize_irq(adapter->pdev->irq);}/** * e1000_irq_enable - Enable default interrupt generation settings **/static void e1000_irq_enable(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw;#ifdef CONFIG_E1000E_MSIX if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); } else { ew32(IMS, IMS_ENABLE_MASK); }#else ew32(IMS, IMS_ENABLE_MASK);#endif /* CONFIG_E1000E_MSIX */}/** * e1000_get_hw_control - get control of the h/w from f/w * @adapter: address of board private structure * * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit. * For ASF and Pass Through versions of f/w this means that * the driver is loaded. For AMT version (only with 82573) * of the f/w this means that the network i/f is open. **/static void e1000_get_hw_control(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 ctrl_ext; u32 swsm; /* Let firmware know the driver has taken over */ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { swsm = er32(SWSM); ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { ctrl_ext = er32(CTRL_EXT); ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); }}/** * e1000_release_hw_control - release control of the h/w to f/w * @adapter: address of board private structure * * e1000_release_hw_control resets {CTRL_EXT|SWSM}:DRV_LOAD bit. * For ASF and Pass Through versions of f/w this means that the * driver is no longer loaded. For AMT version (only with 82573) i * of the f/w this means that the network i/f is closed. * **/static void e1000_release_hw_control(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 ctrl_ext; u32 swsm; /* Let firmware taken over control of h/w */ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { swsm = er32(SWSM); ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD); } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { ctrl_ext = er32(CTRL_EXT); ew32(CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); }}#ifdef CONFIG_E1000E_NAPI/** * e1000_poll - NAPI Rx polling callback * @napi: struct associated with this polling callback * @budget: amount of packets driver is allowed to process this poll **/static int e1000_poll(struct napi_struct *napi, int budget){ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); struct net_device *netdev = adapter->netdev; int tx_clean_complete = 1, work_done = 0;#ifdef CONFIG_E1000E_MSIX struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries && !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) goto clean_rx;#endif /* * e1000_poll is called per-cpu. This lock protects * tx_ring from being cleaned by multiple cpus * simultaneously. A failure obtaining the lock means * tx_ring is currently being cleaned anyway. */ if (spin_trylock(&adapter->tx_queue_lo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -