📄 netdev.c
字号:
rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; writel(0, adapter->hw.hw_addr + rx_ring->head); writel(0, adapter->hw.hw_addr + rx_ring->tail);}/** * e1000_free_rx_resources - Free Rx Resources * @adapter: board private structure * * Free all receive software resources **/void e1000_free_rx_resources(struct e1000_adapter *adapter){ struct pci_dev *pdev = adapter->pdev; struct e1000_ring *rx_ring = adapter->rx_ring; int i; e1000_clean_rx_ring(adapter); for (i = 0; i < rx_ring->count; i++) { kfree(rx_ring->buffer_info[i].ps_pages); } vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, rx_ring->dma); rx_ring->desc = NULL;}/** * e1000_update_itr - update the dynamic ITR value based on statistics * @adapter: pointer to adapter * @itr_setting: current adapter->itr * @packets: the number of packets during this measurement interval * @bytes: the number of bytes during this measurement interval * * Stores a new ITR value based on packets and byte * counts during the last interrupt. The advantage of per interrupt * computation is faster updates and more accurate ITR for the current * traffic pattern. Constants in this function were computed * based on theoretical maximum wire speed and thresholds were set based * on testing data as well as attempting to minimize response time * while increasing bulk throughput. This functionality is controlled * by the InterruptThrottleRate module parameter. **/static unsigned int e1000_update_itr(struct e1000_adapter *adapter, u16 itr_setting, int packets, int bytes){ unsigned int retval = itr_setting; if (packets == 0) goto update_itr_done; switch (itr_setting) { case lowest_latency: /* handle TSO and jumbo frames */ if (bytes/packets > 8000) retval = bulk_latency; else if ((packets < 5) && (bytes > 512)) { retval = low_latency; } break; case low_latency: /* 50 usec aka 20000 ints/s */ if (bytes > 10000) { /* this if handles the TSO accounting */ if (bytes/packets > 8000) { retval = bulk_latency; } else if ((packets < 10) || ((bytes/packets) > 1200)) { retval = bulk_latency; } else if ((packets > 35)) { retval = lowest_latency; } } else if (bytes/packets > 2000) { retval = bulk_latency; } else if (packets <= 2 && bytes < 512) { retval = lowest_latency; } break; case bulk_latency: /* 250 usec aka 4000 ints/s */ if (bytes > 25000) { if (packets > 35) { retval = low_latency; } } else if (bytes < 6000) { retval = low_latency; } break; }update_itr_done: return retval;}static void e1000_set_itr(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u16 current_itr; u32 new_itr = adapter->itr; /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ if (adapter->link_speed != SPEED_1000) { current_itr = 0; new_itr = 4000; goto set_itr_now; } adapter->tx_itr = e1000_update_itr(adapter, adapter->tx_itr, adapter->total_tx_packets, adapter->total_tx_bytes); /* conservative mode (itr 3) eliminates the lowest_latency setting */ if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) adapter->tx_itr = low_latency; adapter->rx_itr = e1000_update_itr(adapter, adapter->rx_itr, adapter->total_rx_packets, adapter->total_rx_bytes); /* conservative mode (itr 3) eliminates the lowest_latency setting */ if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) adapter->rx_itr = low_latency; current_itr = max(adapter->rx_itr, adapter->tx_itr); switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: new_itr = 70000; break; case low_latency: new_itr = 20000; /* aka hwitr = ~200 */ break; case bulk_latency: new_itr = 4000; break; default: break; }set_itr_now: if (new_itr != adapter->itr) { /* * this attempts to bias the interrupt rate towards Bulk * by adding intermediate steps when interrupt rate is * increasing */ new_itr = new_itr > adapter->itr ? min(adapter->itr + (new_itr >> 2), new_itr) : new_itr; adapter->itr = new_itr;#ifdef CONFIG_E1000E_MSIX adapter->rx_ring->itr_val = new_itr; if (adapter->msix_entries) adapter->rx_ring->set_itr = 1; else#endif ew32(ITR, 1000000000 / (new_itr * 256)); }}/** * e1000_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure * * the return value indicates if there is more work to do (later) **/static bool e1000_clean_tx_irq(struct e1000_adapter *adapter){ struct net_device *netdev = adapter->netdev; struct e1000_hw *hw = &adapter->hw; struct e1000_ring *tx_ring = adapter->tx_ring; struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; unsigned int i, eop; bool cleaned = 0, retval = 1; unsigned int total_tx_bytes = 0, total_tx_packets = 0; i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { for (cleaned = 0; !cleaned; ) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; cleaned = (i == eop); if (cleaned) { struct sk_buff *skb = buffer_info->skb;#ifdef NETIF_F_TSO unsigned int segs, bytecount; segs = skb_shinfo(skb)->gso_segs ?: 1; /* multiply data chunks by size of headers */ bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len; total_tx_packets += segs; total_tx_bytes += bytecount;#else total_tx_packets++; total_tx_bytes += skb->len;#endif } e1000_put_txbuf(adapter, buffer_info); tx_desc->upper.data = 0; i++; if (i == tx_ring->count) i = 0;#ifdef CONFIG_E1000E_NAPI if (total_tx_packets >= tx_ring->count) { retval = 0; goto done_cleaning; }#endif } eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); }#ifdef CONFIG_E1000E_NAPIdone_cleaning:#endif tx_ring->next_to_clean = i;#define TX_WAKE_THRESHOLD 32 if (cleaned && netif_carrier_ok(netdev) && e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) { /* * Make sure that anybody stopping the queue after this * sees the new next_to_clean. */ smp_mb(); if (netif_queue_stopped(netdev) && !(test_bit(__E1000_DOWN, &adapter->state))) { netif_wake_queue(netdev); ++adapter->restart_queue; } } if (adapter->detect_tx_hung) { /* * Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = 0; if (tx_ring->buffer_info[eop].dma && time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + (adapter->tx_timeout_factor * HZ)) && !(er32(STATUS) & E1000_STATUS_TXOFF)) { e1000_print_tx_hang(adapter); netif_stop_queue(netdev); } } adapter->total_tx_bytes += total_tx_bytes; adapter->total_tx_packets += total_tx_packets; adapter->net_stats.tx_bytes += total_tx_bytes; adapter->net_stats.tx_packets += total_tx_packets; return retval;}/** * e1000_intr_msi - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure **/static irqreturn_t e1000_intr_msi(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;#endif /* read ICR disables interrupts using IAM */ u32 icr = er32(ICR); 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))) e1000_gig_downshift_workaround_ich8lan(hw); /* * 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 */ u32 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++) { int rx_cleaned = adapter->clean_rx(adapter); int 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;}/** * 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 */ 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))) e1000_gig_downshift_workaround_ich8lan(hw); /* * 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -