📄 ixgbe_main.c
字号:
if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) { ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); cleaned_count = 0; } /* use prefetched values */ rx_desc = next_rxd; rx_buffer_info = next_buffer; staterr = le32_to_cpu(rx_desc->wb.upper.status_error); is_vlan = (staterr & IXGBE_RXD_STAT_VP); vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); } rx_ring->next_to_clean = i; cleaned_count = IXGBE_DESC_UNUSED(rx_ring); if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); return cleaned;}#define IXGBE_MAX_INTR 10/** * ixgbe_configure_msix - Configure MSI-X hardware * @adapter: board private structure * * ixgbe_configure_msix sets up the hardware to properly generate MSI-X * interrupts. **/static void ixgbe_configure_msix(struct ixgbe_adapter *adapter){ int i, vector = 0; for (i = 0; i < adapter->num_tx_queues; i++) { ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), IXGBE_MSIX_VECTOR(vector)); writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr), adapter->hw.hw_addr + adapter->tx_ring[i].itr_register); vector++; } for (i = 0; i < adapter->num_rx_queues; i++) { ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i), IXGBE_MSIX_VECTOR(vector)); writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr), adapter->hw.hw_addr + adapter->rx_ring[i].itr_register); vector++; } vector = adapter->num_tx_queues + adapter->num_rx_queues; ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, IXGBE_MSIX_VECTOR(vector)); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950);}static irqreturn_t ixgbe_msix_lsc(int irq, void *data){ struct net_device *netdev = data; struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); if (eicr & IXGBE_EICR_LSC) { adapter->lsc_int++; if (!test_bit(__IXGBE_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies); } IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); return IRQ_HANDLED;}static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data){ struct ixgbe_ring *txr = data; struct ixgbe_adapter *adapter = txr->adapter; ixgbe_clean_tx_irq(adapter, txr); return IRQ_HANDLED;}static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data){ struct ixgbe_ring *rxr = data; struct ixgbe_adapter *adapter = rxr->adapter; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value); netif_rx_schedule(adapter->netdev, &adapter->napi); return IRQ_HANDLED;}static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget){ struct ixgbe_adapter *adapter = container_of(napi, struct ixgbe_adapter, napi); struct net_device *netdev = adapter->netdev; int work_done = 0; struct ixgbe_ring *rxr = adapter->rx_ring; /* Keep link state information with original netdev */ if (!netif_carrier_ok(netdev)) goto quit_polling; ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ if ((work_done < budget) || !netif_running(netdev)) {quit_polling: netif_rx_complete(netdev, napi); if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->eims_value); } return work_done;}/** * ixgbe_setup_msix - Initialize MSI-X interrupts * * ixgbe_setup_msix allocates MSI-X vectors and requests * interrutps from the kernel. **/static int ixgbe_setup_msix(struct ixgbe_adapter *adapter){ struct net_device *netdev = adapter->netdev; int i, int_vector = 0, err = 0; int max_msix_count; /* +1 for the LSC interrupt */ max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1; adapter->msix_entries = kcalloc(max_msix_count, sizeof(struct msix_entry), GFP_KERNEL); if (!adapter->msix_entries) return -ENOMEM; for (i = 0; i < max_msix_count; i++) adapter->msix_entries[i].entry = i; err = pci_enable_msix(adapter->pdev, adapter->msix_entries, max_msix_count); if (err) goto out; for (i = 0; i < adapter->num_tx_queues; i++) { sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i); err = request_irq(adapter->msix_entries[int_vector].vector, &ixgbe_msix_clean_tx, 0, adapter->tx_ring[i].name, &(adapter->tx_ring[i])); if (err) { DPRINTK(PROBE, ERR, "request_irq failed for MSIX interrupt " "Error: %d\n", err); goto release_irqs; } adapter->tx_ring[i].eims_value = (1 << IXGBE_MSIX_VECTOR(int_vector)); adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector); int_vector++; } for (i = 0; i < adapter->num_rx_queues; i++) { if (strlen(netdev->name) < (IFNAMSIZ - 5)) sprintf(adapter->rx_ring[i].name, "%s-rx%d", netdev->name, i); else memcpy(adapter->rx_ring[i].name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[int_vector].vector, &ixgbe_msix_clean_rx, 0, adapter->rx_ring[i].name, &(adapter->rx_ring[i])); if (err) { DPRINTK(PROBE, ERR, "request_irq failed for MSIX interrupt " "Error: %d\n", err); goto release_irqs; } adapter->rx_ring[i].eims_value = (1 << IXGBE_MSIX_VECTOR(int_vector)); adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector); int_vector++; } sprintf(adapter->lsc_name, "%s-lsc", netdev->name); err = request_irq(adapter->msix_entries[int_vector].vector, &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev); if (err) { DPRINTK(PROBE, ERR, "request_irq for msix_lsc failed: %d\n", err); goto release_irqs; } /* FIXME: implement netif_napi_remove() instead */ adapter->napi.poll = ixgbe_clean_rxonly; adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; return 0;release_irqs: int_vector--; for (; int_vector >= adapter->num_tx_queues; int_vector--) free_irq(adapter->msix_entries[int_vector].vector, &(adapter->rx_ring[int_vector - adapter->num_tx_queues])); for (; int_vector >= 0; int_vector--) free_irq(adapter->msix_entries[int_vector].vector, &(adapter->tx_ring[int_vector]));out: kfree(adapter->msix_entries); adapter->msix_entries = NULL; adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; return err;}/** * ixgbe_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure * @pt_regs: CPU registers structure **/static irqreturn_t ixgbe_intr(int irq, void *data){ struct net_device *netdev = data; struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 eicr; eicr = IXGBE_READ_REG(hw, IXGBE_EICR); if (!eicr) return IRQ_NONE; /* Not our interrupt */ if (eicr & IXGBE_EICR_LSC) { adapter->lsc_int++; if (!test_bit(__IXGBE_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies); } if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* Disable interrupts and register for poll. The flush of the * posted write is intentionally left out. */ atomic_inc(&adapter->irq_sem); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); __netif_rx_schedule(netdev, &adapter->napi); } return IRQ_HANDLED;}/** * ixgbe_request_irq - initialize interrupts * @adapter: board private structure * * Attempts to configure interrupts using the best available * capabilities of the hardware and kernel. **/static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues){ struct net_device *netdev = adapter->netdev; int flags, err; irqreturn_t(*handler) (int, void *) = &ixgbe_intr; flags = IRQF_SHARED; err = ixgbe_setup_msix(adapter); if (!err) goto request_done; /* * if we can't do MSI-X, fall through and try MSI * No need to reallocate memory since we're decreasing the number of * queues. We just won't use the other ones, also it is freed correctly * on ixgbe_remove. */ *num_rx_queues = 1; /* do MSI */ err = pci_enable_msi(adapter->pdev); if (!err) { adapter->flags |= IXGBE_FLAG_MSI_ENABLED; flags &= ~IRQF_SHARED; handler = &ixgbe_intr; } err = request_irq(adapter->pdev->irq, handler, flags, netdev->name, netdev); if (err) DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);request_done: return err;}static void ixgbe_free_irq(struct ixgbe_adapter *adapter){ struct net_device *netdev = adapter->netdev; if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { int i; for (i = 0; i < adapter->num_tx_queues; i++) free_irq(adapter->msix_entries[i].vector, &(adapter->tx_ring[i])); for (i = 0; i < adapter->num_rx_queues; i++) free_irq(adapter->msix_entries[i + adapter->num_tx_queues].vector, &(adapter->rx_ring[i])); i = adapter->num_rx_queues + adapter->num_tx_queues; free_irq(adapter->msix_entries[i].vector, netdev); pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; return; } free_irq(adapter->pdev->irq, netdev); if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { pci_disable_msi(adapter->pdev); adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED; }}/** * ixgbe_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter){ atomic_inc(&adapter->irq_sem); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); synchronize_irq(adapter->pdev->irq);}/** * ixgbe_irq_enable - Enable default interrupt generation settings * @adapter: board private structure **/static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter){ if (atomic_dec_and_test(&adapter->irq_sem)) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, (IXGBE_EIMS_ENABLE_MASK & ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC))); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_ENABLE_MASK); IXGBE_WRITE_FLUSH(&adapter->hw); }}/** * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts * **/static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter){ int i; struct ixgbe_hw *hw = &adapter->hw; if (adapter->rx_eitr) IXGBE_WRITE_REG(hw, IXGBE_EITR(0), EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr)); /* for re-triggering the interrupt in non-NAPI mode */ adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0); for (i = 0; i < adapter->num_tx_queues; i++) ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i);}/** * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset * @adapter: board private structure * * Configure the Tx unit of the MAC after a reset. **/static void ixgbe_configure_tx(struct ixgbe_adapter *adapter){ u64 tdba; struct ixgbe_hw *hw = &adapter->hw; u32 i, tdlen; /* Setup the HW Tx Head and Tail descriptor pointers */ for (i = 0; i < adapter->num_tx_queues; i++) { tdba = adapter->tx_ring[i].dma; tdlen = adapter->tx_ring[i].count * sizeof(union ixgbe_adv_tx_desc); IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK)); IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen); IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); adapter->tx_ring[i].head = IXGBE_TDH(i); adapter->tx_ring[i].tail = IXGBE_TDT(i); } IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT);}#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2/** * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset * @adapter: board private structure * * Configure the Rx unit of the MAC after a reset. **/static void ixgbe_configure_rx(struct ixgbe_adapter *adapter){ u64 rdba; struct ixgbe_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; u32 rdlen, rxctrl, rxcsum; u32 random[10]; u32 reta, mrqc; int i; u32 fctrl, hlreg0; u32 srrctl; u32 pages; /* Decide whether to use packet split mode or not */ if (netdev->mtu > ETH_DATA_LEN) adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; else adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; /* Set the RX buffer length according to the mode */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { adapter->rx_buf_len = IXGBE_RX_HDR_SIZE; } else { if (netdev->mtu <= ETH_DATA_LEN) adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else adapter->rx_buf_len = ALIGN(max_frame, 1024); } fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); fctrl |= IXGBE_FCTRL_BAM; IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); if (adapter->netdev->mtu <= ETH_DATA_LEN) hlreg0 &= ~IXGBE_HLREG0_JUMBOEN; else hlreg0 |= IXGBE_HLREG0_JUMBOEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); pages = PAGE_USE_COUNT(adapter->netdev->mtu); srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; srrctl |= ((IXGBE_RX_HDR_SIZE <<
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -