📄 netdev.c
字号:
if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter);#endif /* CONFIG_E1000E_NAPI */ return IRQ_HANDLED;}/** * e1000_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure **/static irqreturn_t e1000_intr(int irq, void *data){ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw;#ifndef CONFIG_E1000E_NAPI int i; int rx_cleaned, tx_cleaned_complete;#endif u32 rctl, icr = er32(ICR); if (!icr) return IRQ_NONE; /* Not our interrupt */#ifdef CONFIG_E1000E_NAPI /* * IMS will not auto-mask if INT_ASSERTED is not set, and if it is * not set, then the adapter didn't send an interrupt */ if (!(icr & E1000_ICR_INT_ASSERTED)) return IRQ_NONE;#endif /* CONFIG_E1000E_NAPI */ /* * Interrupt Auto-Mask...upon reading ICR, * interrupts are masked. No need for the * IMC write */ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { hw->mac.get_link_status = 1; /* * ICH8 workaround-- Call gig speed drop workaround on cable * disconnect (LSC) before accessing any PHY registers */ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && (!(er32(STATUS) & E1000_STATUS_LU))) schedule_work(&adapter->downshift_task); /* * 80003ES2LAN workaround-- * For packet buffer work-around on link down event; * disable receives here in the ISR and * reset adapter in watchdog */ if (netif_carrier_ok(netdev) && (adapter->flags & FLAG_RX_NEEDS_RESTART)) { /* disable receives */ rctl = er32(RCTL); ew32(RCTL, rctl & ~E1000_RCTL_EN); adapter->flags |= FLAG_RX_RESTART_NOW; } /* guard against interrupt when we're going down */ if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); }#ifdef CONFIG_E1000E_NAPI if (netif_rx_schedule_prep(netdev, &adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; __netif_rx_schedule(netdev, &adapter->napi); }#else adapter->total_tx_bytes = 0; adapter->total_rx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_packets = 0; for (i = 0; i < E1000_MAX_INTR; i++) { rx_cleaned = adapter->clean_rx(adapter); tx_cleaned_complete = e1000_clean_tx_irq(adapter); if (!rx_cleaned && tx_cleaned_complete) break; } if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter);#endif /* CONFIG_E1000E_NAPI */ return IRQ_HANDLED;}#ifdef CONFIG_E1000E_MSIXstatic irqreturn_t e1000_msix_other(int irq, void *data){ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u32 icr = er32(ICR); if (!(icr & E1000_ICR_INT_ASSERTED)) { ew32(IMS, E1000_IMS_OTHER); return IRQ_NONE; } if (icr & adapter->eiac_mask) ew32(ICS, (icr & adapter->eiac_mask)); if (icr & E1000_ICR_OTHER) { if (!(icr & E1000_ICR_LSC)) goto no_link_interrupt; hw->mac.get_link_status = 1; /* guard against interrupt when we're going down */ if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); }no_link_interrupt: ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER); return IRQ_HANDLED;}#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLERstatic irqreturn_t e1000_intr_msix_tx(int irq, void *data){ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct e1000_ring *tx_ring = adapter->tx_ring; adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; if (!e1000_clean_tx_irq(adapter)) /* Ring was not completely cleaned, so fire another interrupt */ ew32(ICS, tx_ring->ims_val); return IRQ_HANDLED;}#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */static irqreturn_t e1000_intr_msix_rx(int irq, void *data){ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev);#ifndef CONFIG_E1000E_NAPI int i; 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 e1000e_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;}/** * e1000e_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 e1000e_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"); e1000e_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-rx-0", 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-tx-0", 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_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;#ifndef CONFIG_E1000E_MSIX int irq_flags = IRQF_SHARED;#endif int err;#ifdef CONFIG_E1000E_MSIX if (adapter->msix_entries) { err = e1000_request_msix(adapter); if (!err) return err; /* fall back to MSI */ e1000e_reset_interrupt_capability(adapter); adapter->int_mode = E1000E_INT_MODE_MSI; e1000e_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 */ e1000e_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 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++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -