From 42bfd33ab7bce7d2abaa8bd968ae9ad0dc9a4771 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 20 Jun 2008 12:10:30 +0900 Subject: igb: make ioport free This patch makes igb driver ioport-free. This corrects behavior in probe function so as not to request ioport resources as long as they are not really needed. Signed-off-by: Taku Izumi Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 6b2e7d351d65..0eecb8b2abd2 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -271,6 +271,10 @@ struct igb_adapter { unsigned int msi_enabled; u32 eeprom_wol; + + /* for ioport free */ + int bars; + int need_ioport; }; enum e1000_state_t { -- cgit v1.2.3-70-g09d2 From 844290e56067aed0a54142d756565abb9614136c Mon Sep 17 00:00:00 2001 From: PJ Waskiewicz Date: Fri, 27 Jun 2008 11:00:39 -0700 Subject: igb: add NAPI Rx queue support Update the NAPI implementation to use the new napi_struct infrstructure. This removes the need of multiple net_device structs to implement a multiqueue NAPI. Signed-off-by: PJ Waskiewicz Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 2 + drivers/net/igb/igb_main.c | 148 ++++++++++++++++++--------------------------- 2 files changed, 61 insertions(+), 89 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 0eecb8b2abd2..2c48eec17660 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -150,6 +150,7 @@ struct igb_ring { u16 itr_register; u16 cpu; + int queue_index; unsigned int total_bytes; unsigned int total_packets; @@ -265,6 +266,7 @@ struct igb_adapter { int msg_enable; struct msix_entry *msix_entries; u32 eims_enable_mask; + u32 eims_other; /* to not mess up cache alignment, always add to the bottom */ unsigned long state; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e5dff61f162e..7bc6fae182a7 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -227,12 +227,11 @@ static int igb_alloc_queues(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); ring->adapter = adapter; + ring->queue_index = i; ring->itr_register = E1000_ITR; - if (!ring->napi.poll) - netif_napi_add(adapter->netdev, &ring->napi, igb_clean, - adapter->napi.weight / - adapter->num_rx_queues); + /* set a default napi handler for each rx_ring */ + netif_napi_add(adapter->netdev, &ring->napi, igb_clean, 64); } return 0; } @@ -300,9 +299,6 @@ static void igb_configure_msix(struct igb_adapter *adapter) array_wr32(E1000_MSIXBM(0), vector++, E1000_EIMS_OTHER); - /* disable IAM for ICR interrupt bits */ - wr32(E1000_IAM, 0); - tmp = rd32(E1000_CTRL_EXT); /* enable MSI-X PBA support*/ tmp |= E1000_CTRL_EXT_PBA_CLR; @@ -313,6 +309,7 @@ static void igb_configure_msix(struct igb_adapter *adapter) wr32(E1000_CTRL_EXT, tmp); adapter->eims_enable_mask |= E1000_EIMS_OTHER; + adapter->eims_other = E1000_EIMS_OTHER; wrfl(); } @@ -355,6 +352,9 @@ static int igb_request_msix(struct igb_adapter *adapter) goto out; ring->itr_register = E1000_EITR(0) + (vector << 2); ring->itr_val = adapter->itr; + /* overwrite the poll routine for MSIX, we've already done + * netif_napi_add */ + ring->napi.poll = &igb_clean_rx_ring_msix; vector++; } @@ -363,9 +363,6 @@ static int igb_request_msix(struct igb_adapter *adapter) if (err) goto out; - adapter->napi.poll = igb_clean_rx_ring_msix; - for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].napi.poll = adapter->napi.poll; igb_configure_msix(adapter); return 0; out: @@ -434,12 +431,8 @@ static int igb_request_irq(struct igb_adapter *adapter) if (adapter->msix_entries) { err = igb_request_msix(adapter); - if (!err) { - /* enable IAM, auto-mask, - * DO NOT USE EIAM or IAM in legacy mode */ - wr32(E1000_IAM, IMS_ENABLE_MASK); + if (!err) goto request_done; - } /* fall back to MSI */ igb_reset_interrupt_capability(adapter); if (!pci_enable_msi(adapter->pdev)) @@ -448,7 +441,11 @@ static int igb_request_irq(struct igb_adapter *adapter) igb_free_all_rx_resources(adapter); adapter->num_rx_queues = 1; igb_alloc_queues(adapter); + } else { + wr32(E1000_MSIXBM(0), (E1000_EICR_RX_QUEUE0 | + E1000_EIMS_OTHER)); } + if (adapter->msi_enabled) { err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0, netdev->name, netdev); @@ -500,9 +497,12 @@ static void igb_irq_disable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { + wr32(E1000_EIAM, 0); wr32(E1000_EIMC, ~0); wr32(E1000_EIAC, 0); } + + wr32(E1000_IAM, 0); wr32(E1000_IMC, ~0); wrfl(); synchronize_irq(adapter->pdev->irq); @@ -517,13 +517,14 @@ static void igb_irq_enable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIMS, - adapter->eims_enable_mask); - wr32(E1000_EIAC, - adapter->eims_enable_mask); + wr32(E1000_EIAC, adapter->eims_enable_mask); + wr32(E1000_EIAM, adapter->eims_enable_mask); + wr32(E1000_EIMS, adapter->eims_enable_mask); wr32(E1000_IMS, E1000_IMS_LSC); - } else - wr32(E1000_IMS, IMS_ENABLE_MASK); + } else { + wr32(E1000_IMS, IMS_ENABLE_MASK); + wr32(E1000_IAM, IMS_ENABLE_MASK); + } } static void igb_update_mng_vlan(struct igb_adapter *adapter) @@ -661,13 +662,10 @@ int igb_up(struct igb_adapter *adapter) clear_bit(__IGB_DOWN, &adapter->state); - napi_enable(&adapter->napi); - - if (adapter->msix_entries) { - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_ring[i].napi); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); + if (adapter->msix_entries) igb_configure_msix(adapter); - } /* Clear any pending interrupts. */ rd32(E1000_ICR); @@ -704,11 +702,9 @@ void igb_down(struct igb_adapter *adapter) wrfl(); msleep(10); - napi_disable(&adapter->napi); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_disable(&adapter->rx_ring[i].napi); - if (adapter->msix_entries) - for (i = 0; i < adapter->num_rx_queues; i++) - napi_disable(&adapter->rx_ring[i].napi); igb_irq_disable(adapter); del_timer_sync(&adapter->watchdog_timer); @@ -933,7 +929,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_set_ethtool_ops(netdev); netdev->tx_timeout = &igb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netif_napi_add(netdev, &adapter->napi, igb_clean, 64); netdev->vlan_rx_register = igb_vlan_rx_register; netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid; @@ -1298,15 +1293,14 @@ static int igb_open(struct net_device *netdev) /* From here on the code is the same as igb_up() */ clear_bit(__IGB_DOWN, &adapter->state); - napi_enable(&adapter->napi); - if (adapter->msix_entries) - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_ring[i].napi); - - igb_irq_enable(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); /* Clear any pending interrupts. */ rd32(E1000_ICR); + + igb_irq_enable(adapter); + /* Fire a link status change interrupt to start the watchdog. */ wr32(E1000_ICS, E1000_ICS_LSC); @@ -1534,8 +1528,6 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, rx_ring->pending_skb = NULL; rx_ring->adapter = adapter; - /* FIXME: do we want to setup ring->napi->poll here? */ - rx_ring->napi.poll = adapter->napi.poll; return 0; @@ -3034,26 +3026,19 @@ static irqreturn_t igb_msix_other(int irq, void *data) struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 eicr; - /* disable interrupts from the "other" bit, avoid re-entry */ - wr32(E1000_EIMC, E1000_EIMS_OTHER); - - eicr = rd32(E1000_EICR); + u32 icr = rd32(E1000_ICR); - if (eicr & E1000_EIMS_OTHER) { - u32 icr = rd32(E1000_ICR); - /* reading ICR causes bit 31 of EICR to be cleared */ - 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(__IGB_DOWN, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies + 1); - } + /* reading ICR causes bit 31 of EICR to be cleared */ + 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(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); no_link_interrupt: wr32(E1000_IMS, E1000_IMS_LSC); - wr32(E1000_EIMS, E1000_EIMS_OTHER); + wr32(E1000_EIMS, adapter->eims_other); return IRQ_HANDLED; } @@ -3084,21 +3069,19 @@ static irqreturn_t igb_msix_rx(int irq, void *data) struct igb_adapter *adapter = rx_ring->adapter; struct e1000_hw *hw = &adapter->hw; - if (!rx_ring->itr_val) - wr32(E1000_EIMC, rx_ring->eims_value); + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ - if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) { - rx_ring->total_bytes = 0; - rx_ring->total_packets = 0; - rx_ring->no_itr_adjust = 0; - __netif_rx_schedule(adapter->netdev, &rx_ring->napi); - } else { - if (!rx_ring->no_itr_adjust) { - igb_lower_rx_eitr(adapter, rx_ring); - rx_ring->no_itr_adjust = 1; - } + if (adapter->set_itr) { + wr32(rx_ring->itr_register, + 1000000000 / (rx_ring->itr_val * 256)); + adapter->set_itr = 0; } + if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) + __netif_rx_schedule(adapter->netdev, &rx_ring->napi); + return IRQ_HANDLED; } @@ -3112,7 +3095,6 @@ static irqreturn_t igb_intr_msi(int irq, void *data) { struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); - struct napi_struct *napi = &adapter->napi; struct e1000_hw *hw = &adapter->hw; /* read ICR disables interrupts using IAM */ u32 icr = rd32(E1000_ICR); @@ -3121,25 +3103,17 @@ static irqreturn_t igb_intr_msi(int irq, void *data) * previous interrupt. */ if (adapter->set_itr) { - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); + wr32(E1000_ITR, 1000000000 / (adapter->itr * 256)); adapter->set_itr = 0; } - /* read ICR disables interrupts using IAM */ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { hw->mac.get_link_status = 1; if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, napi)) { - adapter->tx_ring->total_bytes = 0; - adapter->tx_ring->total_packets = 0; - adapter->rx_ring->total_bytes = 0; - adapter->rx_ring->total_packets = 0; - __netif_rx_schedule(netdev, napi); - } + netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3153,7 +3127,6 @@ static irqreturn_t igb_intr(int irq, void *data) { struct net_device *netdev = data; struct igb_adapter *adapter = netdev_priv(netdev); - struct napi_struct *napi = &adapter->napi; struct e1000_hw *hw = &adapter->hw; /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No * need for the IMC write */ @@ -3166,8 +3139,7 @@ static irqreturn_t igb_intr(int irq, void *data) * previous interrupt. */ if (adapter->set_itr) { - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); + wr32(E1000_ITR, 1000000000 / (adapter->itr * 256)); adapter->set_itr = 0; } @@ -3185,13 +3157,7 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, napi)) { - adapter->tx_ring->total_bytes = 0; - adapter->rx_ring->total_bytes = 0; - adapter->tx_ring->total_packets = 0; - adapter->rx_ring->total_packets = 0; - __netif_rx_schedule(netdev, napi); - } + netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3274,6 +3240,10 @@ quit_polling: else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH) igb_lower_rx_eitr(adapter, rx_ring); } + + if (!test_bit(__IGB_DOWN, &adapter->state)) + wr32(E1000_EIMS, rx_ring->eims_value); + return 0; } -- cgit v1.2.3-70-g09d2 From 661086df6cf35f62d0aec09ccb9164eb2baaaecd Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 8 Jul 2008 15:06:51 -0700 Subject: igb: Introduce multiple TX queues with infrastructure This code adds multiple Tx queue infrastructure much like we previously did in ixgbe. The MSI-X vector mapping is the bulk of the change. IAM can now be safely enabled and we've verified that it does work correctly. We can also eliminate the tx ring lock. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Mitch Williams Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 7 +- drivers/net/igb/igb_main.c | 160 ++++++++++++++++++++++++++++++--------------- 2 files changed, 114 insertions(+), 53 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 2c48eec17660..a1431c8797b9 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -62,6 +62,7 @@ struct igb_adapter; /* Transmit and receive queues */ #define IGB_MAX_RX_QUEUES 4 +#define IGB_MAX_TX_QUEUES 4 /* RX descriptor control thresholds. * PTHRESH - MAC will consider prefetch if it has fewer than this number of @@ -157,8 +158,6 @@ struct igb_ring { union { /* TX */ struct { - spinlock_t tx_clean_lock; - spinlock_t tx_lock; bool detect_tx_hung; }; /* RX */ @@ -277,6 +276,10 @@ struct igb_adapter { /* for ioport free */ int bars; int need_ioport; + +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; +#endif /* CONFIG_NETDEVICES_MULTIQUEUE */ }; enum e1000_state_t { diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index afd4ce3f7b53..e11a5dae668a 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -103,7 +103,7 @@ static irqreturn_t igb_msix_rx(int irq, void *); static irqreturn_t igb_msix_tx(int irq, void *); static int igb_clean_rx_ring_msix(struct napi_struct *, int); static bool igb_clean_tx_irq(struct igb_ring *); -static int igb_clean(struct napi_struct *, int); +static int igb_poll(struct napi_struct *, int); static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); static void igb_alloc_rx_buffers_adv(struct igb_ring *, int); static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); @@ -224,6 +224,11 @@ static int igb_alloc_queues(struct igb_adapter *adapter) return -ENOMEM; } + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = &(adapter->tx_ring[i]); + ring->adapter = adapter; + ring->queue_index = i; + } for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); ring->adapter = adapter; @@ -231,7 +236,7 @@ static int igb_alloc_queues(struct igb_adapter *adapter) ring->itr_register = E1000_ITR; /* set a default napi handler for each rx_ring */ - netif_napi_add(adapter->netdev, &ring->napi, igb_clean, 64); + netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64); } return 0; } @@ -412,8 +417,14 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter) /* If we can't do MSI-X, try MSI */ msi_only: adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; if (!pci_enable_msi(adapter->pdev)) adapter->msi_enabled = 1; + +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + /* Notify the stack of the (possibly) reduced Tx Queue count. */ + adapter->netdev->egress_subqueue_count = adapter->num_tx_queues; +#endif return; } @@ -693,6 +704,10 @@ void igb_down(struct igb_adapter *adapter) /* flush and sleep below */ netif_stop_queue(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < adapter->num_tx_queues; i++) + netif_stop_subqueue(netdev, i); +#endif /* disable transmits in the hardware */ tctl = rd32(E1000_TCTL); @@ -895,7 +910,11 @@ static int __devinit igb_probe(struct pci_dev *pdev, pci_save_state(pdev); err = -ENOMEM; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES); +#else netdev = alloc_etherdev(sizeof(struct igb_adapter)); +#endif /* CONFIG_NETDEVICES_MULTIQUEUE */ if (!netdev) goto err_alloc_etherdev; @@ -997,6 +1016,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netdev->features |= NETIF_F_MULTI_QUEUE; +#endif + netdev->features |= NETIF_F_LLTX; adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw); @@ -1097,6 +1120,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until igb_open() is called */ netif_carrier_off(netdev); netif_stop_queue(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < adapter->num_tx_queues; i++) + netif_stop_subqueue(netdev, i); +#endif strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); @@ -1223,9 +1250,15 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) /* Number of supported queues. */ /* Having more queues than CPUs doesn't make sense. */ + adapter->num_rx_queues = min((u32)IGB_MAX_RX_QUEUES, (u32)num_online_cpus()); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + adapter->num_tx_queues = min(IGB_MAX_TX_QUEUES, num_online_cpus()); +#else adapter->num_tx_queues = 1; - adapter->num_rx_queues = min(IGB_MAX_RX_QUEUES, num_online_cpus()); +#endif /* CONFIG_NET_MULTI_QUEUE_DEVICE */ + /* This call may decrease the number of queues depending on + * interrupt mode. */ igb_set_interrupt_capability(adapter); if (igb_alloc_queues(adapter)) { @@ -1386,8 +1419,6 @@ int igb_setup_tx_resources(struct igb_adapter *adapter, tx_ring->adapter = adapter; tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - spin_lock_init(&tx_ring->tx_clean_lock); - spin_lock_init(&tx_ring->tx_lock); return 0; err: @@ -1407,6 +1438,9 @@ err: static int igb_setup_all_tx_resources(struct igb_adapter *adapter) { int i, err = 0; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + int r_idx; +#endif for (i = 0; i < adapter->num_tx_queues; i++) { err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]); @@ -1419,6 +1453,12 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter) } } +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < IGB_MAX_TX_QUEUES; i++) { + r_idx = i % adapter->num_tx_queues; + adapter->multi_tx_table[i] = &adapter->tx_ring[r_idx]; + } +#endif return err; } @@ -2096,6 +2136,9 @@ static void igb_watchdog_task(struct work_struct *work) struct e1000_mac_info *mac = &adapter->hw.mac; u32 link; s32 ret_val; +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + int i; +#endif if ((netif_carrier_ok(netdev)) && (rd32(E1000_STATUS) & E1000_STATUS_LU)) @@ -2152,6 +2195,10 @@ static void igb_watchdog_task(struct work_struct *work) netif_carrier_on(netdev); netif_wake_queue(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < adapter->num_tx_queues; i++) + netif_wake_subqueue(netdev, i); +#endif if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -2164,6 +2211,10 @@ static void igb_watchdog_task(struct work_struct *work) dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); netif_carrier_off(netdev); netif_stop_queue(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + for (i = 0; i < adapter->num_tx_queues; i++) + netif_stop_subqueue(netdev, i); +#endif if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -2524,7 +2575,7 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); context_desc->seqnum_seed = 0; context_desc->mss_l4len_idx = - cpu_to_le32(tx_ring->eims_value >> 4); + cpu_to_le32(tx_ring->queue_index << 4); buffer_info->time_stamp = jiffies; buffer_info->dma = 0; @@ -2627,7 +2678,7 @@ static inline void igb_tx_queue_adv(struct igb_adapter *adapter, if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | IGB_TX_FLAGS_VLAN)) - olinfo_status |= tx_ring->eims_value >> 4; + olinfo_status |= tx_ring->queue_index << 4; olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT); @@ -2663,7 +2714,12 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netif_stop_subqueue(netdev, tx_ring->queue_index); +#else netif_stop_queue(netdev); +#endif + /* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); * but since that doesn't exist yet, just open code it. */ @@ -2675,7 +2731,11 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, return -EBUSY; /* A reprieve! */ - netif_start_queue(netdev); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netif_wake_subqueue(netdev, tx_ring->queue_index); +#else + netif_wake_queue(netdev); +#endif ++adapter->restart_queue; return 0; } @@ -2697,7 +2757,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_adapter *adapter = netdev_priv(netdev); unsigned int tx_flags = 0; unsigned int len; - unsigned long irq_flags; u8 hdr_len = 0; int tso = 0; @@ -2713,10 +2772,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } - if (!spin_trylock_irqsave(&tx_ring->tx_lock, irq_flags)) - /* Collision - tell upper layer to requeue */ - return NETDEV_TX_LOCKED; - /* need: 1 descriptor per page, * + 2 desc gap to keep tail from touching head, * + 1 desc for skb->data, @@ -2724,7 +2779,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, * otherwise try next time */ if (igb_maybe_stop_tx(netdev, tx_ring, skb_shinfo(skb)->nr_frags + 4)) { /* this is a hard error */ - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_BUSY; } @@ -2733,12 +2787,14 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); } + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IGB_TX_FLAGS_IPV4; + tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0; if (tso < 0) { dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_OK; } @@ -2748,9 +2804,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_PARTIAL) tx_flags |= IGB_TX_FLAGS_CSUM; - if (skb->protocol == htons(ETH_P_IP)) - tx_flags |= IGB_TX_FLAGS_IPV4; - igb_tx_queue_adv(adapter, tx_ring, tx_flags, igb_tx_map_adv(adapter, tx_ring, skb), skb->len, hdr_len); @@ -2760,14 +2813,22 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, /* Make sure there is space in the ring for the next send. */ igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); - spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); return NETDEV_TX_OK; } static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_ring *tx_ring = &adapter->tx_ring[0]; + struct igb_ring *tx_ring; + +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + int r_idx = 0; + r_idx = skb->queue_mapping & (IGB_MAX_TX_QUEUES - 1); + tx_ring = adapter->multi_tx_table[r_idx]; +#else + tx_ring = &adapter->tx_ring[0]; +#endif + /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively @@ -3035,7 +3096,7 @@ static irqreturn_t igb_msix_other(int irq, void *data) /* guard against interrupt when we're going down */ if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); - + no_link_interrupt: wr32(E1000_IMS, E1000_IMS_LSC); wr32(E1000_EIMS, adapter->eims_other); @@ -3054,12 +3115,15 @@ static irqreturn_t igb_msix_tx(int irq, void *data) tx_ring->total_bytes = 0; tx_ring->total_packets = 0; + + /* auto mask will automatically reenable the interrupt when we write + * EICS */ if (!igb_clean_tx_irq(tx_ring)) /* Ring was not completely cleaned, so fire another interrupt */ wr32(E1000_EICS, tx_ring->eims_value); - - if (!tx_ring->itr_val) + else wr32(E1000_EIMS, tx_ring->eims_value); + return IRQ_HANDLED; } @@ -3163,42 +3227,24 @@ static irqreturn_t igb_intr(int irq, void *data) } /** - * igb_clean - NAPI Rx polling callback - * @adapter: board private structure + * igb_poll - NAPI Rx polling callback + * @napi: napi polling structure + * @budget: count of how many packets we should handle **/ -static int igb_clean(struct napi_struct *napi, int budget) +static int igb_poll(struct napi_struct *napi, int budget) { - struct igb_adapter *adapter = container_of(napi, struct igb_adapter, - napi); + struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi); + struct igb_adapter *adapter = rx_ring->adapter; struct net_device *netdev = adapter->netdev; - int tx_clean_complete = 1, work_done = 0; - int i; + int tx_clean_complete, work_done = 0; - /* Must NOT use netdev_priv macro here. */ - adapter = netdev->priv; - - /* Keep link state information with original netdev */ - if (!netif_carrier_ok(netdev)) - goto quit_polling; - - /* igb_clean is called per-cpu. This lock protects tx_ring[i] from - * being cleaned by multiple cpus simultaneously. A failure obtaining - * the lock means tx_ring[i] is currently being cleaned anyway. */ - for (i = 0; i < adapter->num_tx_queues; i++) { - if (spin_trylock(&adapter->tx_ring[i].tx_clean_lock)) { - tx_clean_complete &= igb_clean_tx_irq(&adapter->tx_ring[i]); - spin_unlock(&adapter->tx_ring[i].tx_clean_lock); - } - } - - for (i = 0; i < adapter->num_rx_queues; i++) - igb_clean_rx_irq_adv(&adapter->rx_ring[i], &work_done, - adapter->rx_ring[i].napi.weight); + /* this poll routine only supports one tx and one rx queue */ + tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]); + igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ if ((tx_clean_complete && (work_done < budget)) || !netif_running(netdev)) { -quit_polling: if (adapter->itr_setting & 3) igb_set_itr(adapter, E1000_ITR, false); netif_rx_complete(netdev, napi); @@ -3327,11 +3373,19 @@ done_cleaning: * sees the new next_to_clean. */ smp_mb(); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && + !(test_bit(__IGB_DOWN, &adapter->state))) { + netif_wake_subqueue(netdev, tx_ring->queue_index); + ++adapter->restart_queue; + } +#else if (netif_queue_stopped(netdev) && !(test_bit(__IGB_DOWN, &adapter->state))) { netif_wake_queue(netdev); ++adapter->restart_queue; } +#endif } if (tx_ring->detect_tx_hung) { @@ -3368,7 +3422,11 @@ done_cleaning: tx_ring->buffer_info[i].time_stamp, jiffies, tx_desc->upper.fields.status); +#ifdef CONFIG_NETDEVICES_MULTIQUEUE + netif_stop_subqueue(netdev, tx_ring->queue_index); +#else netif_stop_queue(netdev); +#endif } } tx_ring->total_bytes += total_bytes; -- cgit v1.2.3-70-g09d2 From e21ed3538f1946ea623caf28f1c44ede50224275 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 8 Jul 2008 15:07:24 -0700 Subject: igb: update ethtool stats to support multiqueue Addesses problems seen earlier with igb driver not correctly reporting rx and tx stats. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 1 + drivers/net/igb/igb_ethtool.c | 13 +++++++++---- drivers/net/igb/igb_main.c | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index a1431c8797b9..5915efccbcab 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -158,6 +158,7 @@ struct igb_ring { union { /* TX */ struct { + struct igb_queue_stats tx_stats; bool detect_tx_hung; }; /* RX */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 0447f9bcd27a..ed756c12aba6 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -96,10 +96,8 @@ static const struct igb_stats igb_gstrings_stats[] = { }; #define IGB_QUEUE_STATS_LEN \ - ((((((struct igb_adapter *)netdev->priv)->num_rx_queues > 1) ? \ - ((struct igb_adapter *)netdev->priv)->num_rx_queues : 0) + \ - (((((struct igb_adapter *)netdev->priv)->num_tx_queues > 1) ? \ - ((struct igb_adapter *)netdev->priv)->num_tx_queues : 0))) * \ + ((((struct igb_adapter *)netdev->priv)->num_rx_queues + \ + ((struct igb_adapter *)netdev->priv)->num_tx_queues) * \ (sizeof(struct igb_queue_stats) / sizeof(u64))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) @@ -1842,6 +1840,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev, data[i] = (igb_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } + for (j = 0; j < adapter->num_tx_queues; j++) { + int k; + queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } for (j = 0; j < adapter->num_rx_queues; j++) { int k; queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e11a5dae668a..f975bfec2265 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3431,6 +3431,8 @@ done_cleaning: } tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; + tx_ring->tx_stats.bytes += total_bytes; + tx_ring->tx_stats.packets += total_packets; adapter->net_stats.tx_bytes += total_bytes; adapter->net_stats.tx_packets += total_packets; return retval; -- cgit v1.2.3-70-g09d2 From fe4506b6a2f9716ef62583020581ae2032573fed Mon Sep 17 00:00:00 2001 From: Jeb Cramer Date: Tue, 8 Jul 2008 15:07:55 -0700 Subject: igb: add DCA support Add DCA support in the similar method that it was added to the ixgbe driver recently. DCA allows the network device to put data in the CPU cache and notify the chipset of that event. This reduces cache misses during receives. Signed-off-by: Jeb Cramer Signed-off-by: Mitch Williams Signed-off-by: Auke Kok Signed-off-by: Shannon Nelson Signed-off-by: Jeff Garzik --- drivers/net/igb/e1000_82575.h | 11 +++ drivers/net/igb/e1000_regs.h | 2 + drivers/net/igb/igb.h | 4 +- drivers/net/igb/igb_main.c | 174 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 187 insertions(+), 4 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index d78ad33d32bf..02e57a8447cb 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -144,9 +144,20 @@ struct e1000_adv_tx_context_desc { #define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */ /* Direct Cache Access (DCA) definitions */ +#define E1000_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ +#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ +#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ +#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ +#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ +#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ +#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ +#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ +#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ +#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ #define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ + #endif diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index ff187b73c69e..d25e914df975 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -235,6 +235,8 @@ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ +#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ /* RSS registers */ diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 5915efccbcab..d4a042344728 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -271,7 +271,9 @@ struct igb_adapter { /* to not mess up cache alignment, always add to the bottom */ unsigned long state; unsigned int msi_enabled; - +#ifdef CONFIG_DCA + unsigned int dca_enabled; +#endif u32 eeprom_wol; /* for ioport free */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index f975bfec2265..e8ef5410591a 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -41,7 +41,9 @@ #include #include #include - +#ifdef CONFIG_DCA +#include +#endif #include "igb.h" #define DRV_VERSION "1.0.8-k2" @@ -102,6 +104,11 @@ static irqreturn_t igb_msix_other(int irq, void *); static irqreturn_t igb_msix_rx(int irq, void *); static irqreturn_t igb_msix_tx(int irq, void *); static int igb_clean_rx_ring_msix(struct napi_struct *, int); +#ifdef CONFIG_DCA +static void igb_update_rx_dca(struct igb_ring *); +static void igb_update_tx_dca(struct igb_ring *); +static void igb_setup_dca(struct igb_adapter *); +#endif /* CONFIG_DCA */ static bool igb_clean_tx_irq(struct igb_ring *); static int igb_poll(struct napi_struct *, int); static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); @@ -119,6 +126,14 @@ static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); #endif static void igb_shutdown(struct pci_dev *); +#ifdef CONFIG_DCA +static int igb_notify_dca(struct notifier_block *, unsigned long, void *); +static struct notifier_block dca_notifier = { + .notifier_call = igb_notify_dca, + .next = NULL, + .priority = 0 +}; +#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ @@ -183,6 +198,9 @@ static int __init igb_init_module(void) printk(KERN_INFO "%s\n", igb_copyright); ret = pci_register_driver(&igb_driver); +#ifdef CONFIG_DCA + dca_register_notify(&dca_notifier); +#endif return ret; } @@ -196,6 +214,9 @@ module_init(igb_init_module); **/ static void __exit igb_exit_module(void) { +#ifdef CONFIG_DCA + dca_unregister_notify(&dca_notifier); +#endif pci_unregister_driver(&igb_driver); } @@ -1130,6 +1151,17 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (err) goto err_register; +#ifdef CONFIG_DCA + if (dca_add_requester(&pdev->dev) == 0) { + adapter->dca_enabled = true; + dev_info(&pdev->dev, "DCA enabled\n"); + /* Always use CB2 mode, difference is masked + * in the CB driver. */ + wr32(E1000_DCA_CTRL, 2); + igb_setup_dca(adapter); + } +#endif + dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); /* print bus type/speed/width info */ dev_info(&pdev->dev, @@ -1193,6 +1225,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; /* flush_scheduled work may reschedule our watchdog task, so * explicitly disable watchdog tasks from being rescheduled */ @@ -1202,6 +1235,15 @@ static void __devexit igb_remove(struct pci_dev *pdev) flush_scheduled_work(); +#ifdef CONFIG_DCA + if (adapter->dca_enabled) { + dev_info(&pdev->dev, "DCA disabled\n"); + dca_remove_requester(&pdev->dev); + adapter->dca_enabled = false; + wr32(E1000_DCA_CTRL, 1); + } +#endif + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ igb_release_hw_control(adapter); @@ -3112,7 +3154,10 @@ static irqreturn_t igb_msix_tx(int irq, void *data) if (!tx_ring->itr_val) wr32(E1000_EIMC, tx_ring->eims_value); - +#ifdef CONFIG_DCA + if (adapter->dca_enabled) + igb_update_tx_dca(tx_ring); +#endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; @@ -3146,9 +3191,119 @@ static irqreturn_t igb_msix_rx(int irq, void *data) if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) __netif_rx_schedule(adapter->netdev, &rx_ring->napi); - return IRQ_HANDLED; +#ifdef CONFIG_DCA + if (adapter->dca_enabled) + igb_update_rx_dca(rx_ring); +#endif + return IRQ_HANDLED; +} + +#ifdef CONFIG_DCA +static void igb_update_rx_dca(struct igb_ring *rx_ring) +{ + u32 dca_rxctrl; + struct igb_adapter *adapter = rx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + int cpu = get_cpu(); + int q = rx_ring - adapter->rx_ring; + + if (rx_ring->cpu != cpu) { + dca_rxctrl = rd32(E1000_DCA_RXCTRL(q)); + dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK; + dca_rxctrl |= dca_get_tag(cpu); + dca_rxctrl |= E1000_DCA_RXCTRL_DESC_DCA_EN; + dca_rxctrl |= E1000_DCA_RXCTRL_HEAD_DCA_EN; + dca_rxctrl |= E1000_DCA_RXCTRL_DATA_DCA_EN; + wr32(E1000_DCA_RXCTRL(q), dca_rxctrl); + rx_ring->cpu = cpu; + } + put_cpu(); +} + +static void igb_update_tx_dca(struct igb_ring *tx_ring) +{ + u32 dca_txctrl; + struct igb_adapter *adapter = tx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + int cpu = get_cpu(); + int q = tx_ring - adapter->tx_ring; + + if (tx_ring->cpu != cpu) { + dca_txctrl = rd32(E1000_DCA_TXCTRL(q)); + dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK; + dca_txctrl |= dca_get_tag(cpu); + dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN; + wr32(E1000_DCA_TXCTRL(q), dca_txctrl); + tx_ring->cpu = cpu; + } + put_cpu(); +} + +static void igb_setup_dca(struct igb_adapter *adapter) +{ + int i; + + if (!(adapter->dca_enabled)) + return; + + for (i = 0; i < adapter->num_tx_queues; i++) { + adapter->tx_ring[i].cpu = -1; + igb_update_tx_dca(&adapter->tx_ring[i]); + } + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->rx_ring[i].cpu = -1; + igb_update_rx_dca(&adapter->rx_ring[i]); + } } +static int __igb_notify_dca(struct device *dev, void *data) +{ + struct net_device *netdev = dev_get_drvdata(dev); + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + unsigned long event = *(unsigned long *)data; + + switch (event) { + case DCA_PROVIDER_ADD: + /* if already enabled, don't do it again */ + if (adapter->dca_enabled) + break; + adapter->dca_enabled = true; + /* Always use CB2 mode, difference is masked + * in the CB driver. */ + wr32(E1000_DCA_CTRL, 2); + if (dca_add_requester(dev) == 0) { + dev_info(&adapter->pdev->dev, "DCA enabled\n"); + igb_setup_dca(adapter); + break; + } + /* Fall Through since DCA is disabled. */ + case DCA_PROVIDER_REMOVE: + if (adapter->dca_enabled) { + /* without this a class_device is left + * hanging around in the sysfs model */ + dca_remove_requester(dev); + dev_info(&adapter->pdev->dev, "DCA disabled\n"); + adapter->dca_enabled = false; + wr32(E1000_DCA_CTRL, 1); + } + break; + } + + return 0; +} + +static int igb_notify_dca(struct notifier_block *nb, unsigned long event, + void *p) +{ + int ret_val; + + ret_val = driver_for_each_device(&igb_driver.driver, NULL, &event, + __igb_notify_dca); + + return ret_val ? NOTIFY_BAD : NOTIFY_DONE; +} +#endif /* CONFIG_DCA */ /** * igb_intr_msi - Interrupt Handler @@ -3239,7 +3394,16 @@ static int igb_poll(struct napi_struct *napi, int budget) int tx_clean_complete, work_done = 0; /* this poll routine only supports one tx and one rx queue */ +#ifdef CONFIG_DCA + if (adapter->dca_enabled) + igb_update_tx_dca(&adapter->tx_ring[0]); +#endif tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]); + +#ifdef CONFIG_DCA + if (adapter->dca_enabled) + igb_update_rx_dca(&adapter->rx_ring[0]); +#endif igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ @@ -3268,6 +3432,10 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) if (!netif_carrier_ok(netdev)) goto quit_polling; +#ifdef CONFIG_DCA + if (adapter->dca_enabled) + igb_update_rx_dca(rx_ring); +#endif igb_clean_rx_irq_adv(rx_ring, &work_done, budget); -- cgit v1.2.3-70-g09d2 From 7dfc16fab1186769d7d0086830ab3fbc8fddfcba Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 8 Jul 2008 15:10:46 -0700 Subject: igb: Add support for quad port WOL and feature flags Change igb from using a series of boolean operators to using a single flags value that contains a number of different bit flags for all the different features of the adapter. This patch also adds WOL support for quad port adapters. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 13 ++++-- drivers/net/igb/igb_ethtool.c | 12 +++++- drivers/net/igb/igb_main.c | 92 +++++++++++++++++++++++++++++-------------- 3 files changed, 81 insertions(+), 36 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index d4a042344728..ee08010d2c4f 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -270,10 +270,7 @@ struct igb_adapter { /* to not mess up cache alignment, always add to the bottom */ unsigned long state; - unsigned int msi_enabled; -#ifdef CONFIG_DCA - unsigned int dca_enabled; -#endif + unsigned int flags; u32 eeprom_wol; /* for ioport free */ @@ -285,6 +282,14 @@ struct igb_adapter { #endif /* CONFIG_NETDEVICES_MULTIQUEUE */ }; +#define IGB_FLAG_HAS_MSI (1 << 0) +#define IGB_FLAG_MSI_ENABLE (1 << 1) +#define IGB_FLAG_HAS_DCA (1 << 2) +#define IGB_FLAG_DCA_ENABLED (1 << 3) +#define IGB_FLAG_IN_NETPOLL (1 << 5) +#define IGB_FLAG_QUAD_PORT_A (1 << 6) +#define IGB_FLAG_NEED_CTX_IDX (1 << 7) + enum e1000_state_t { __IGB_TESTING, __IGB_RESETTING, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index e27d5a533b4f..ef209b5cd390 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1097,7 +1097,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) if (adapter->msix_entries) { /* NOTE: we don't test MSI-X interrupts here, yet */ return 0; - } else if (adapter->msi_enabled) { + } else if (adapter->flags & IGB_FLAG_HAS_MSI) { shared_int = false; if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) { *data = 1; @@ -1727,7 +1727,6 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, switch (hw->device_id) { case E1000_DEV_ID_82575GB_QUAD_COPPER: - case E1000_DEV_ID_82576_QUAD_COPPER: /* WoL not supported */ wol->supported = 0; break; @@ -1742,6 +1741,15 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, /* return success for non excluded adapter ports */ retval = 0; break; + case E1000_DEV_ID_82576_QUAD_COPPER: + /* quad port adapters only support WoL on port A */ + if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) { + wol->supported = 0; + break; + } + /* return success for non excluded adapter ports */ + retval = 0; + break; default: /* dual port cards only support WoL on port A from now on * unless it was enabled in the eeprom for port B diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index ba043c4e1ca2..68a4fef3df9a 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -53,7 +53,6 @@ static const char igb_driver_string[] = "Intel(R) Gigabit Ethernet Network Driver"; static const char igb_copyright[] = "Copyright (c) 2008 Intel Corporation."; - static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, }; @@ -170,6 +169,8 @@ static struct pci_driver igb_driver = { .err_handler = &igb_err_handler }; +static int global_quad_port_a; /* global quad port a indication */ + MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); MODULE_LICENSE("GPL"); @@ -201,6 +202,8 @@ static int __init igb_init_module(void) printk(KERN_INFO "%s\n", igb_copyright); + global_quad_port_a = 0; + ret = pci_register_driver(&igb_driver); #ifdef CONFIG_DCA dca_register_notify(&dca_notifier); @@ -471,7 +474,7 @@ static void igb_reset_interrupt_capability(struct igb_adapter *adapter) pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; - } else if (adapter->msi_enabled) + } else if (adapter->flags & IGB_FLAG_HAS_MSI) pci_disable_msi(adapter->pdev); return; } @@ -510,7 +513,7 @@ msi_only: adapter->num_rx_queues = 1; adapter->num_tx_queues = 1; if (!pci_enable_msi(adapter->pdev)) - adapter->msi_enabled = 1; + adapter->flags |= IGB_FLAG_HAS_MSI; #ifdef CONFIG_NETDEVICES_MULTIQUEUE /* Notify the stack of the (possibly) reduced Tx Queue count. */ @@ -538,7 +541,7 @@ static int igb_request_irq(struct igb_adapter *adapter) /* fall back to MSI */ igb_reset_interrupt_capability(adapter); if (!pci_enable_msi(adapter->pdev)) - adapter->msi_enabled = 1; + adapter->flags |= IGB_FLAG_HAS_MSI; igb_free_all_tx_resources(adapter); igb_free_all_rx_resources(adapter); adapter->num_rx_queues = 1; @@ -557,14 +560,14 @@ static int igb_request_irq(struct igb_adapter *adapter) } } - if (adapter->msi_enabled) { + if (adapter->flags & IGB_FLAG_HAS_MSI) { err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0, netdev->name, netdev); if (!err) goto request_done; /* fall back to legacy interrupts */ igb_reset_interrupt_capability(adapter); - adapter->msi_enabled = 0; + adapter->flags &= ~IGB_FLAG_HAS_MSI; } err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED, @@ -1097,6 +1100,17 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_get_bus_info_pcie(hw); + /* set flags */ + switch (hw->mac.type) { + case e1000_82576: + case e1000_82575: + adapter->flags |= IGB_FLAG_HAS_DCA; + adapter->flags |= IGB_FLAG_NEED_CTX_IDX; + break; + default: + break; + } + hw->phy.autoneg_wait_to_complete = false; hw->mac.adaptive_ifs = true; @@ -1209,7 +1223,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, * lan on a particular port */ switch (pdev->device) { case E1000_DEV_ID_82575GB_QUAD_COPPER: - case E1000_DEV_ID_82576_QUAD_COPPER: adapter->eeprom_wol = 0; break; case E1000_DEV_ID_82575EB_FIBER_SERDES: @@ -1220,6 +1233,16 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) adapter->eeprom_wol = 0; break; + case E1000_DEV_ID_82576_QUAD_COPPER: + /* if quad port adapter, disable WoL on all but port A */ + if (global_quad_port_a != 0) + adapter->eeprom_wol = 0; + else + adapter->flags |= IGB_FLAG_QUAD_PORT_A; + /* Reset for multiple quad port adapters */ + if (++global_quad_port_a == 4) + global_quad_port_a = 0; + break; } /* initialize the wol settings based on the eeprom settings */ @@ -1246,8 +1269,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, goto err_register; #ifdef CONFIG_DCA - if (dca_add_requester(&pdev->dev) == 0) { - adapter->dca_enabled = true; + if ((adapter->flags & IGB_FLAG_HAS_DCA) && + (dca_add_requester(&pdev->dev) == 0)) { + adapter->flags |= IGB_FLAG_DCA_ENABLED; dev_info(&pdev->dev, "DCA enabled\n"); /* Always use CB2 mode, difference is masked * in the CB driver. */ @@ -1276,7 +1300,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Using %s interrupts. %d rx queue(s), %d tx queue(s)\n", adapter->msix_entries ? "MSI-X" : - adapter->msi_enabled ? "MSI" : "legacy", + (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy", adapter->num_rx_queues, adapter->num_tx_queues); return 0; @@ -1330,10 +1354,10 @@ static void __devexit igb_remove(struct pci_dev *pdev) flush_scheduled_work(); #ifdef CONFIG_DCA - if (adapter->dca_enabled) { + if (adapter->flags & IGB_FLAG_DCA_ENABLED) { dev_info(&pdev->dev, "DCA disabled\n"); dca_remove_requester(&pdev->dev); - adapter->dca_enabled = false; + adapter->flags &= ~IGB_FLAG_DCA_ENABLED; wr32(E1000_DCA_CTRL, 1); } #endif @@ -2650,9 +2674,9 @@ static inline int igb_tso_adv(struct igb_adapter *adapter, mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT); mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT); - /* Context index must be unique per ring. Luckily, so is the interrupt - * mask value. */ - mss_l4len_idx |= tx_ring->eims_value >> 4; + /* Context index must be unique per ring. */ + if (adapter->flags & IGB_FLAG_NEED_CTX_IDX) + mss_l4len_idx |= tx_ring->queue_index << 4; context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); context_desc->seqnum_seed = 0; @@ -2716,8 +2740,9 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); context_desc->seqnum_seed = 0; - context_desc->mss_l4len_idx = - cpu_to_le32(tx_ring->queue_index << 4); + if (adapter->flags & IGB_FLAG_NEED_CTX_IDX) + context_desc->mss_l4len_idx = + cpu_to_le32(tx_ring->queue_index << 4); buffer_info->time_stamp = jiffies; buffer_info->dma = 0; @@ -2818,8 +2843,9 @@ static inline void igb_tx_queue_adv(struct igb_adapter *adapter, olinfo_status |= E1000_TXD_POPTS_TXSM << 8; } - if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | - IGB_TX_FLAGS_VLAN)) + if ((adapter->flags & IGB_FLAG_NEED_CTX_IDX) && + (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | + IGB_TX_FLAGS_VLAN))) olinfo_status |= tx_ring->queue_index << 4; olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT); @@ -3255,7 +3281,7 @@ static irqreturn_t igb_msix_tx(int irq, void *data) if (!tx_ring->itr_val) wr32(E1000_EIMC, tx_ring->eims_value); #ifdef CONFIG_DCA - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_tx_dca(tx_ring); #endif tx_ring->total_bytes = 0; @@ -3292,7 +3318,7 @@ static irqreturn_t igb_msix_rx(int irq, void *data) __netif_rx_schedule(adapter->netdev, &rx_ring->napi); #ifdef CONFIG_DCA - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif return IRQ_HANDLED; @@ -3355,7 +3381,7 @@ static void igb_setup_dca(struct igb_adapter *adapter) { int i; - if (!(adapter->dca_enabled)) + if (!(adapter->flags & IGB_FLAG_DCA_ENABLED)) return; for (i = 0; i < adapter->num_tx_queues; i++) { @@ -3375,12 +3401,15 @@ static int __igb_notify_dca(struct device *dev, void *data) struct e1000_hw *hw = &adapter->hw; unsigned long event = *(unsigned long *)data; + if (!(adapter->flags & IGB_FLAG_HAS_DCA)) + goto out; + switch (event) { case DCA_PROVIDER_ADD: /* if already enabled, don't do it again */ - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) break; - adapter->dca_enabled = true; + adapter->flags |= IGB_FLAG_DCA_ENABLED; /* Always use CB2 mode, difference is masked * in the CB driver. */ wr32(E1000_DCA_CTRL, 2); @@ -3391,17 +3420,17 @@ static int __igb_notify_dca(struct device *dev, void *data) } /* Fall Through since DCA is disabled. */ case DCA_PROVIDER_REMOVE: - if (adapter->dca_enabled) { + if (adapter->flags & IGB_FLAG_DCA_ENABLED) { /* without this a class_device is left * hanging around in the sysfs model */ dca_remove_requester(dev); dev_info(&adapter->pdev->dev, "DCA disabled\n"); - adapter->dca_enabled = false; + adapter->flags &= ~IGB_FLAG_DCA_ENABLED; wr32(E1000_DCA_CTRL, 1); } break; } - +out: return 0; } @@ -3507,13 +3536,13 @@ static int igb_poll(struct napi_struct *napi, int budget) /* this poll routine only supports one tx and one rx queue */ #ifdef CONFIG_DCA - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_tx_dca(&adapter->tx_ring[0]); #endif tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]); #ifdef CONFIG_DCA - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(&adapter->rx_ring[0]); #endif igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget); @@ -3545,7 +3574,7 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) goto quit_polling; #ifdef CONFIG_DCA - if (adapter->dca_enabled) + if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif igb_clean_rx_irq_adv(rx_ring, &work_done, budget); @@ -4350,6 +4379,8 @@ static void igb_netpoll(struct net_device *netdev) int work_done = 0; igb_irq_disable(adapter); + adapter->flags |= IGB_FLAG_IN_NETPOLL; + for (i = 0; i < adapter->num_tx_queues; i++) igb_clean_tx_irq(&adapter->tx_ring[i]); @@ -4358,6 +4389,7 @@ static void igb_netpoll(struct net_device *netdev) &work_done, adapter->rx_ring[i].napi.weight); + adapter->flags &= ~IGB_FLAG_IN_NETPOLL; igb_irq_enable(adapter); } #endif /* CONFIG_NET_POLL_CONTROLLER */ -- cgit v1.2.3-70-g09d2 From bf36c1a0040cc6ccd63cdd1cec25d2085f2df964 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 8 Jul 2008 15:11:40 -0700 Subject: igb: add page recycling support This patch adds support for page recycling by splitting the page into two usable portions and tracking the reference count. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 4 +- drivers/net/igb/igb_main.c | 138 ++++++++++++++++++++------------------------- 2 files changed, 63 insertions(+), 79 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index ee08010d2c4f..f41b9996d2ed 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -125,6 +125,7 @@ struct igb_buffer { struct { struct page *page; u64 page_dma; + unsigned int page_offset; }; }; }; @@ -163,9 +164,6 @@ struct igb_ring { }; /* RX */ struct { - /* arrays of page information for packet split */ - struct sk_buff *pending_skb; - int pending_skb_page; int no_itr_adjust; struct igb_queue_stats rx_stats; struct napi_struct napi; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 68a4fef3df9a..660a78653287 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1725,7 +1725,6 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; - rx_ring->pending_skb = NULL; rx_ring->adapter = adapter; @@ -1817,15 +1816,6 @@ static void igb_setup_rctl(struct igb_adapter *adapter) rctl |= E1000_RCTL_SZ_2048; rctl &= ~E1000_RCTL_BSEX; break; - case IGB_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096; - break; - case IGB_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192; - break; - case IGB_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384; - break; } } else { rctl &= ~E1000_RCTL_BSEX; @@ -1843,10 +1833,8 @@ static void igb_setup_rctl(struct igb_adapter *adapter) * so only enable packet split for jumbo frames */ if (rctl & E1000_RCTL_LPE) { adapter->rx_ps_hdr_size = IGB_RXBUFFER_128; - srrctl = adapter->rx_ps_hdr_size << + srrctl |= adapter->rx_ps_hdr_size << E1000_SRRCTL_BSIZEHDRSIZE_SHIFT; - /* buffer size is ALWAYS one page */ - srrctl |= PAGE_SIZE >> E1000_SRRCTL_BSIZEPKT_SHIFT; srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; } else { adapter->rx_ps_hdr_size = 0; @@ -2151,20 +2139,17 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring) buffer_info->skb = NULL; } if (buffer_info->page) { - pci_unmap_page(pdev, buffer_info->page_dma, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (buffer_info->page_dma) + pci_unmap_page(pdev, buffer_info->page_dma, + PAGE_SIZE / 2, + PCI_DMA_FROMDEVICE); put_page(buffer_info->page); buffer_info->page = NULL; buffer_info->page_dma = 0; + buffer_info->page_offset = 0; } } - /* there also may be some cached data from a chained receive */ - if (rx_ring->pending_skb) { - dev_kfree_skb(rx_ring->pending_skb); - rx_ring->pending_skb = NULL; - } - size = sizeof(struct igb_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); @@ -3091,7 +3076,11 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) else if (max_frame <= IGB_RXBUFFER_2048) adapter->rx_buffer_len = IGB_RXBUFFER_2048; else - adapter->rx_buffer_len = IGB_RXBUFFER_4096; +#if (PAGE_SIZE / 2) > IGB_RXBUFFER_16384 + adapter->rx_buffer_len = IGB_RXBUFFER_16384; +#else + adapter->rx_buffer_len = PAGE_SIZE / 2; +#endif /* adjust allocation if LPE protects us, and we aren't using SBP */ if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)) @@ -3796,7 +3785,7 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, union e1000_adv_rx_desc *rx_desc , *next_rxd; struct igb_buffer *buffer_info , *next_buffer; struct sk_buff *skb; - unsigned int i, j; + unsigned int i; u32 length, hlen, staterr; bool cleaned = false; int cleaned_count = 0; @@ -3826,61 +3815,46 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, cleaned = true; cleaned_count++; - if (rx_ring->pending_skb != NULL) { - skb = rx_ring->pending_skb; - rx_ring->pending_skb = NULL; - j = rx_ring->pending_skb_page; - } else { - skb = buffer_info->skb; - prefetch(skb->data - NET_IP_ALIGN); - buffer_info->skb = NULL; - if (hlen) { - pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_ps_hdr_size + - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); - skb_put(skb, hlen); - } else { - pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_buffer_len + - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); - skb_put(skb, length); - goto send_up; - } - j = 0; + skb = buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + buffer_info->skb = NULL; + if (!adapter->rx_ps_hdr_size) { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, length); + goto send_up; + } + + if (!skb_shinfo(skb)->nr_frags) { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_hdr_size + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, hlen); } - while (length) { + if (length) { pci_unmap_page(pdev, buffer_info->page_dma, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); buffer_info->page_dma = 0; - skb_fill_page_desc(skb, j, buffer_info->page, - 0, length); - buffer_info->page = NULL; + + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++, + buffer_info->page, + buffer_info->page_offset, + length); + + if ((adapter->rx_buffer_len > (PAGE_SIZE / 2)) || + (page_count(buffer_info->page) != 1)) + buffer_info->page = NULL; + else + get_page(buffer_info->page); skb->len += length; skb->data_len += length; - skb->truesize += length; - rx_desc->wb.upper.status_error = 0; - if (staterr & E1000_RXD_STAT_EOP) - break; - - j++; - cleaned_count++; - i++; - if (i == rx_ring->count) - i = 0; - buffer_info = &rx_ring->buffer_info[i]; - rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); - staterr = le32_to_cpu(rx_desc->wb.upper.status_error); - length = le16_to_cpu(rx_desc->wb.upper.length); - if (!(staterr & E1000_RXD_STAT_DD)) { - rx_ring->pending_skb = skb; - rx_ring->pending_skb_page = j; - goto out; - } + skb->truesize += length; } send_up: i++; @@ -3890,6 +3864,12 @@ send_up: prefetch(next_rxd); next_buffer = &rx_ring->buffer_info[i]; + if (!(staterr & E1000_RXD_STAT_EOP)) { + buffer_info->skb = xchg(&next_buffer->skb, skb); + buffer_info->dma = xchg(&next_buffer->dma, 0); + goto next_desc; + } + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { dev_kfree_skb_irq(skb); goto next_desc; @@ -3922,7 +3902,7 @@ next_desc: staterr = le32_to_cpu(rx_desc->wb.upper.status_error); } -out: + rx_ring->next_to_clean = i; cleaned_count = IGB_DESC_UNUSED(rx_ring); @@ -3960,16 +3940,22 @@ static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, while (cleaned_count--) { rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); - if (adapter->rx_ps_hdr_size && !buffer_info->page) { - buffer_info->page = alloc_page(GFP_ATOMIC); + if (adapter->rx_ps_hdr_size && !buffer_info->page_dma) { if (!buffer_info->page) { - adapter->alloc_rx_buff_failed++; - goto no_buffers; + buffer_info->page = alloc_page(GFP_ATOMIC); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + buffer_info->page_offset = 0; + } else { + buffer_info->page_offset ^= PAGE_SIZE / 2; } buffer_info->page_dma = pci_map_page(pdev, buffer_info->page, - 0, PAGE_SIZE, + buffer_info->page_offset, + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); } -- cgit v1.2.3-70-g09d2 From d3352520273426e4c16e91d189aa8aa7ee5e96c5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 8 Jul 2008 15:12:13 -0700 Subject: igb: add support for in kernel LRO This patch adds support for the use of the inet_lro module to provide software LRO support. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 9 ++++ drivers/net/igb/e1000_82575.h | 2 + drivers/net/igb/igb.h | 16 ++++++ drivers/net/igb/igb_ethtool.c | 17 +++++++ drivers/net/igb/igb_main.c | 112 ++++++++++++++++++++++++++++++++++++++---- 5 files changed, 147 insertions(+), 9 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 21414177ee1e..44d1c835128a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2018,6 +2018,15 @@ config IGB To compile this driver as a module, choose M here. The module will be called igb. +config IGB_LRO + bool "Use software LRO" + depends on IGB && INET + select INET_LRO + ---help--- + Say Y here if you want to use large receive offload. + + If in doubt, say N. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index d273236c7764..2f848e578a24 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -99,6 +99,8 @@ union e1000_adv_rx_desc { /* RSS Hash results */ /* RSS Packet Types as indicated in the receive descriptor */ +#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */ +#define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ /* Transmit Descriptor - Advanced */ union e1000_adv_tx_desc { diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index f41b9996d2ed..c25ca17d3228 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -36,6 +36,12 @@ struct igb_adapter; +#ifdef CONFIG_IGB_LRO +#include +#define MAX_LRO_AGGR 32 +#define MAX_LRO_DESCRIPTORS 8 +#endif + /* Interrupt defines */ #define IGB_MAX_TX_CLEAN 72 @@ -167,6 +173,10 @@ struct igb_ring { int no_itr_adjust; struct igb_queue_stats rx_stats; struct napi_struct napi; +#ifdef CONFIG_IGB_LRO + struct net_lro_mgr lro_mgr; + bool lro_used; +#endif }; }; @@ -278,6 +288,12 @@ struct igb_adapter { #ifdef CONFIG_NETDEVICES_MULTIQUEUE struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; #endif /* CONFIG_NETDEVICES_MULTIQUEUE */ +#ifdef CONFIG_IGB_LRO + unsigned int lro_max_aggr; + unsigned int lro_aggregated; + unsigned int lro_flushed; + unsigned int lro_no_desc; +#endif }; #define IGB_FLAG_HAS_MSI (1 << 0) diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index ef209b5cd390..7db183093768 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -93,6 +93,11 @@ static const struct igb_stats igb_gstrings_stats[] = { { "tx_smbus", IGB_STAT(stats.mgptc) }, { "rx_smbus", IGB_STAT(stats.mgprc) }, { "dropped_smbus", IGB_STAT(stats.mgpdc) }, +#ifdef CONFIG_IGB_LRO + { "lro_aggregated", IGB_STAT(lro_aggregated) }, + { "lro_flushed", IGB_STAT(lro_flushed) }, + { "lro_no_desc", IGB_STAT(lro_no_desc) }, +#endif }; #define IGB_QUEUE_STATS_LEN \ @@ -1917,6 +1922,18 @@ static void igb_get_ethtool_stats(struct net_device *netdev, int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); int j; int i; +#ifdef CONFIG_IGB_LRO + int aggregated = 0, flushed = 0, no_desc = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated; + flushed += adapter->rx_ring[i].lro_mgr.stats.flushed; + no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc; + } + adapter->lro_aggregated = aggregated; + adapter->lro_flushed = flushed; + adapter->lro_no_desc = no_desc; +#endif igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 660a78653287..89416ebda9ef 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -116,6 +116,9 @@ static bool igb_clean_tx_irq(struct igb_ring *); static int igb_poll(struct napi_struct *, int); static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); static void igb_alloc_rx_buffers_adv(struct igb_ring *, int); +#ifdef CONFIG_IGB_LRO +static int igb_get_skb_hdr(struct sk_buff *skb, void **, void **, u64 *, void *); +#endif static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); static void igb_tx_timeout(struct net_device *); static void igb_reset_task(struct work_struct *); @@ -1134,6 +1137,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; +#ifdef CONFIG_IGB_LRO + netdev->features |= NETIF_F_LRO; +#endif + netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_HW_CSUM; @@ -1705,6 +1712,14 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, struct pci_dev *pdev = adapter->pdev; int size, desc_len; +#ifdef CONFIG_IGB_LRO + size = sizeof(struct net_lro_desc) * MAX_LRO_DESCRIPTORS; + rx_ring->lro_mgr.lro_arr = vmalloc(size); + if (!rx_ring->lro_mgr.lro_arr) + goto err; + memset(rx_ring->lro_mgr.lro_arr, 0, size); +#endif + size = sizeof(struct igb_buffer) * rx_ring->count; rx_ring->buffer_info = vmalloc(size); if (!rx_ring->buffer_info) @@ -1731,6 +1746,10 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, return 0; err: +#ifdef CONFIG_IGB_LRO + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; +#endif vfree(rx_ring->buffer_info); dev_err(&adapter->pdev->dev, "Unable to allocate memory for " "the receive descriptor ring\n"); @@ -1894,6 +1913,16 @@ static void igb_configure_rx(struct igb_adapter *adapter) rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; wr32(E1000_RXDCTL(i), rxdctl); +#ifdef CONFIG_IGB_LRO + /* Intitial LRO Settings */ + ring->lro_mgr.max_aggr = MAX_LRO_AGGR; + ring->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; + ring->lro_mgr.get_skb_header = igb_get_skb_hdr; + ring->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + ring->lro_mgr.dev = adapter->netdev; + ring->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + ring->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; +#endif } if (adapter->num_rx_queues > 1) { @@ -2085,6 +2114,11 @@ static void igb_free_rx_resources(struct igb_ring *rx_ring) vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; +#ifdef CONFIG_IGB_LRO + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; +#endif + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); rx_ring->desc = NULL; @@ -3735,22 +3769,75 @@ done_cleaning: return retval; } +#ifdef CONFIG_IGB_LRO + /** + * igb_get_skb_hdr - helper function for LRO header processing + * @skb: pointer to sk_buff to be added to LRO packet + * @iphdr: pointer to ip header structure + * @tcph: pointer to tcp header structure + * @hdr_flags: pointer to header flags + * @priv: pointer to the receive descriptor for the current sk_buff + **/ +static int igb_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, + u64 *hdr_flags, void *priv) +{ + union e1000_adv_rx_desc *rx_desc = priv; + u16 pkt_type = rx_desc->wb.lower.lo_dword.pkt_info & + (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP); + + /* Verify that this is a valid IPv4 TCP packet */ + if (pkt_type != (E1000_RXDADV_PKTTYPE_IPV4 | + E1000_RXDADV_PKTTYPE_TCP)) + return -1; + + /* Set network headers */ + skb_reset_network_header(skb); + skb_set_transport_header(skb, ip_hdrlen(skb)); + *iphdr = ip_hdr(skb); + *tcph = tcp_hdr(skb); + *hdr_flags = LRO_IPV4 | LRO_TCP; + + return 0; + +} +#endif /* CONFIG_IGB_LRO */ /** * igb_receive_skb - helper function to handle rx indications - * @adapter: board private structure + * @ring: pointer to receive ring receving this packet * @status: descriptor status field as written by hardware * @vlan: descriptor vlan field as written by hardware (no le/be conversion) * @skb: pointer to sk_buff to be indicated to stack **/ -static void igb_receive_skb(struct igb_adapter *adapter, u8 status, __le16 vlan, - struct sk_buff *skb) +static void igb_receive_skb(struct igb_ring *ring, u8 status, + union e1000_adv_rx_desc * rx_desc, + struct sk_buff *skb) { - if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(vlan)); - else - netif_receive_skb(skb); + struct igb_adapter * adapter = ring->adapter; + bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); + +#ifdef CONFIG_IGB_LRO + if (adapter->netdev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (vlan_extracted) + lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, + adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan), + rx_desc); + else + lro_receive_skb(&ring->lro_mgr,skb, rx_desc); + ring->lro_used = 1; + } else { +#endif + if (vlan_extracted) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan)); + else + + netif_receive_skb(skb); +#ifdef CONFIG_IGB_LRO + } +#endif } @@ -3883,7 +3970,7 @@ send_up: skb->protocol = eth_type_trans(skb, netdev); - igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb); + igb_receive_skb(rx_ring, staterr, rx_desc, skb); netdev->last_rx = jiffies; @@ -3906,6 +3993,13 @@ next_desc: rx_ring->next_to_clean = i; cleaned_count = IGB_DESC_UNUSED(rx_ring); +#ifdef CONFIG_IGB_LRO + if (rx_ring->lro_used) { + lro_flush_all(&rx_ring->lro_mgr); + rx_ring->lro_used = 0; + } +#endif + if (cleaned_count) igb_alloc_rx_buffers_adv(rx_ring, cleaned_count); -- cgit v1.2.3-70-g09d2 From 6eb5a7f1dbd56883680290f6a0bd2d8d15f8ff58 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 8 Jul 2008 15:14:44 -0700 Subject: igb: Improve multiqueue AIM support Improve multiqueue performance Change itr_val to reflect ITR timer value instead of ints/sec Cleaned up AIM algorithms in general Based on work by Mitch Williams Signed-off-by: Alexander Duyck Acked-by: Mitch Williams Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/igb/igb.h | 8 +- drivers/net/igb/igb_ethtool.c | 17 +++-- drivers/net/igb/igb_main.c | 169 ++++++++++++++++++++++++------------------ 3 files changed, 113 insertions(+), 81 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index c25ca17d3228..56de7ec15b46 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -47,7 +47,9 @@ struct igb_adapter; #define IGB_MIN_DYN_ITR 3000 #define IGB_MAX_DYN_ITR 96000 -#define IGB_START_ITR 6000 + +/* ((1000000000ns / (6000ints/s * 1024ns)) << 2 = 648 */ +#define IGB_START_ITR 648 #define IGB_DYN_ITR_PACKET_THRESHOLD 2 #define IGB_DYN_ITR_LENGTH_LOW 200 @@ -170,9 +172,10 @@ struct igb_ring { }; /* RX */ struct { - int no_itr_adjust; struct igb_queue_stats rx_stats; struct napi_struct napi; + int set_itr; + struct igb_ring *buddy; #ifdef CONFIG_IGB_LRO struct net_lro_mgr lro_mgr; bool lro_used; @@ -219,7 +222,6 @@ struct igb_adapter { u32 itr_setting; u16 tx_itr; u16 rx_itr; - int set_itr; struct work_struct reset_task; struct work_struct watchdog_task; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 7db183093768..11aee1309951 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1861,6 +1861,8 @@ static int igb_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int i; if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || ((ec->rx_coalesce_usecs > 3) && @@ -1869,13 +1871,16 @@ static int igb_set_coalesce(struct net_device *netdev, return -EINVAL; /* convert to rate of irq's per second */ - if (ec->rx_coalesce_usecs <= 3) + if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) { adapter->itr_setting = ec->rx_coalesce_usecs; - else - adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs); + adapter->itr = IGB_START_ITR; + } else { + adapter->itr_setting = ec->rx_coalesce_usecs << 2; + adapter->itr = adapter->itr_setting; + } - if (netif_running(netdev)) - igb_reinit_locked(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + wr32(adapter->rx_ring[i].itr_register, adapter->itr); return 0; } @@ -1888,7 +1893,7 @@ static int igb_get_coalesce(struct net_device *netdev, if (adapter->itr_setting <= 3) ec->rx_coalesce_usecs = adapter->itr_setting; else - ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + ec->rx_coalesce_usecs = adapter->itr_setting >> 2; return 0; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2a5303c311bc..aaed129f4ca0 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -255,6 +255,8 @@ static int igb_alloc_queues(struct igb_adapter *adapter) return -ENOMEM; } + adapter->rx_ring->buddy = adapter->tx_ring; + for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); ring->adapter = adapter; @@ -375,7 +377,7 @@ static void igb_configure_msix(struct igb_adapter *adapter) igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++); adapter->eims_enable_mask |= tx_ring->eims_value; if (tx_ring->itr_val) - writel(1000000000 / (tx_ring->itr_val * 256), + writel(tx_ring->itr_val, hw->hw_addr + tx_ring->itr_register); else writel(1, hw->hw_addr + tx_ring->itr_register); @@ -383,10 +385,11 @@ static void igb_configure_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *rx_ring = &adapter->rx_ring[i]; + rx_ring->buddy = 0; igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++); adapter->eims_enable_mask |= rx_ring->eims_value; if (rx_ring->itr_val) - writel(1000000000 / (rx_ring->itr_val * 256), + writel(rx_ring->itr_val, hw->hw_addr + rx_ring->itr_register); else writel(1, hw->hw_addr + rx_ring->itr_register); @@ -449,7 +452,7 @@ static int igb_request_msix(struct igb_adapter *adapter) if (err) goto out; ring->itr_register = E1000_EITR(0) + (vector << 2); - ring->itr_val = adapter->itr; + ring->itr_val = 976; /* ~4000 ints/sec */ vector++; } for (i = 0; i < adapter->num_rx_queues; i++) { @@ -1898,8 +1901,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) mdelay(10); if (adapter->itr_setting > 3) - wr32(E1000_ITR, - 1000000000 / (adapter->itr * 256)); + wr32(E1000_ITR, adapter->itr); /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ @@ -2463,38 +2465,60 @@ enum latency_range { }; -static void igb_lower_rx_eitr(struct igb_adapter *adapter, - struct igb_ring *rx_ring) +/** + * igb_update_ring_itr - update the dynamic ITR value based on packet size + * + * Stores a new ITR value based on strictly on packet size. This + * algorithm is less sophisticated than that used in igb_update_itr, + * due to the difficulty of synchronizing statistics across multiple + * receive rings. The divisors and thresholds used by this fuction + * were determined based on theoretical maximum wire speed and testing + * data, in order to minimize response time while increasing bulk + * throughput. + * This functionality is controlled by the InterruptThrottleRate module + * parameter (see igb_param.c) + * NOTE: This function is called only when operating in a multiqueue + * receive environment. + * @rx_ring: pointer to ring + **/ +static void igb_update_ring_itr(struct igb_ring *rx_ring) { - struct e1000_hw *hw = &adapter->hw; - int new_val; + int new_val = rx_ring->itr_val; + int avg_wire_size = 0; + struct igb_adapter *adapter = rx_ring->adapter; - new_val = rx_ring->itr_val / 2; - if (new_val < IGB_MIN_DYN_ITR) - new_val = IGB_MIN_DYN_ITR; + if (!rx_ring->total_packets) + goto clear_counts; /* no packets, so don't do anything */ - if (new_val != rx_ring->itr_val) { - rx_ring->itr_val = new_val; - wr32(rx_ring->itr_register, - 1000000000 / (new_val * 256)); + /* For non-gigabit speeds, just fix the interrupt rate at 4000 + * ints/sec - ITR timer value of 120 ticks. + */ + if (adapter->link_speed != SPEED_1000) { + new_val = 120; + goto set_itr_val; } -} + avg_wire_size = rx_ring->total_bytes / rx_ring->total_packets; -static void igb_raise_rx_eitr(struct igb_adapter *adapter, - struct igb_ring *rx_ring) -{ - struct e1000_hw *hw = &adapter->hw; - int new_val; + /* Add 24 bytes to size to account for CRC, preamble, and gap */ + avg_wire_size += 24; + + /* Don't starve jumbo frames */ + avg_wire_size = min(avg_wire_size, 3000); - new_val = rx_ring->itr_val * 2; - if (new_val > IGB_MAX_DYN_ITR) - new_val = IGB_MAX_DYN_ITR; + /* Give a little boost to mid-size frames */ + if ((avg_wire_size > 300) && (avg_wire_size < 1200)) + new_val = avg_wire_size / 3; + else + new_val = avg_wire_size / 2; +set_itr_val: if (new_val != rx_ring->itr_val) { rx_ring->itr_val = new_val; - wr32(rx_ring->itr_register, - 1000000000 / (new_val * 256)); + rx_ring->set_itr = 1; } +clear_counts: + rx_ring->total_bytes = 0; + rx_ring->total_packets = 0; } /** @@ -2561,8 +2585,7 @@ update_itr_done: return retval; } -static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, - int rx_only) +static void igb_set_itr(struct igb_adapter *adapter) { u16 current_itr; u32 new_itr = adapter->itr; @@ -2578,26 +2601,23 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, adapter->rx_itr, adapter->rx_ring->total_packets, adapter->rx_ring->total_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; - if (!rx_only) { + if (adapter->rx_ring->buddy) { adapter->tx_itr = igb_update_itr(adapter, adapter->tx_itr, adapter->tx_ring->total_packets, adapter->tx_ring->total_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; current_itr = max(adapter->rx_itr, adapter->tx_itr); } else { current_itr = adapter->rx_itr; } + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && + current_itr == lowest_latency) + current_itr = low_latency; + switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: @@ -2614,6 +2634,13 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, } set_itr_now: + adapter->rx_ring->total_bytes = 0; + adapter->rx_ring->total_packets = 0; + if (adapter->rx_ring->buddy) { + adapter->rx_ring->buddy->total_bytes = 0; + adapter->rx_ring->buddy->total_packets = 0; + } + if (new_itr != adapter->itr) { /* this attempts to bias the interrupt rate towards Bulk * by adding intermediate steps when interrupt rate is @@ -2628,7 +2655,8 @@ set_itr_now: * ends up being correct. */ adapter->itr = new_itr; - adapter->set_itr = 1; + adapter->rx_ring->itr_val = 1000000000 / (new_itr * 256); + adapter->rx_ring->set_itr = 1; } return; @@ -2979,6 +3007,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, /* this is a hard error */ return NETDEV_TX_BUSY; } + skb_orphan(skb); if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= IGB_TX_FLAGS_VLAN; @@ -3312,8 +3341,6 @@ static irqreturn_t igb_msix_tx(int irq, void *data) struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; - if (!tx_ring->itr_val) - wr32(E1000_EIMC, tx_ring->eims_value); #ifdef CONFIG_DCA if (adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_tx_dca(tx_ring); @@ -3332,21 +3359,36 @@ static irqreturn_t igb_msix_tx(int irq, void *data) return IRQ_HANDLED; } +static void igb_write_itr(struct igb_ring *ring) +{ + struct e1000_hw *hw = &ring->adapter->hw; + if ((ring->adapter->itr_setting & 3) && ring->set_itr) { + switch (hw->mac.type) { + case e1000_82576: + wr32(ring->itr_register, + ring->itr_val | + 0x80000000); + break; + default: + wr32(ring->itr_register, + ring->itr_val | + (ring->itr_val << 16)); + break; + } + ring->set_itr = 0; + } +} + static irqreturn_t igb_msix_rx(int irq, void *data) { struct igb_ring *rx_ring = data; struct igb_adapter *adapter = rx_ring->adapter; - struct e1000_hw *hw = &adapter->hw; /* Write the ITR value calculated at the end of the * previous interrupt. */ - if (adapter->set_itr) { - wr32(rx_ring->itr_register, - 1000000000 / (rx_ring->itr_val * 256)); - adapter->set_itr = 0; - } + igb_write_itr(rx_ring); if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) __netif_rx_schedule(adapter->netdev, &rx_ring->napi); @@ -3493,13 +3535,7 @@ static irqreturn_t igb_intr_msi(int irq, void *data) /* read ICR disables interrupts using IAM */ u32 icr = rd32(E1000_ICR); - /* Write the ITR value calculated at the end of the - * previous interrupt. - */ - if (adapter->set_itr) { - wr32(E1000_ITR, 1000000000 / (adapter->itr * 256)); - adapter->set_itr = 0; - } + igb_write_itr(adapter->rx_ring); if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { hw->mac.get_link_status = 1; @@ -3529,13 +3565,7 @@ static irqreturn_t igb_intr(int irq, void *data) if (!icr) return IRQ_NONE; /* Not our interrupt */ - /* Write the ITR value calculated at the end of the - * previous interrupt. - */ - if (adapter->set_itr) { - wr32(E1000_ITR, 1000000000 / (adapter->itr * 256)); - adapter->set_itr = 0; - } + igb_write_itr(adapter->rx_ring); /* 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 */ @@ -3585,7 +3615,7 @@ static int igb_poll(struct napi_struct *napi, int budget) if ((tx_clean_complete && (work_done < budget)) || !netif_running(netdev)) { if (adapter->itr_setting & 3) - igb_set_itr(adapter, E1000_ITR, false); + igb_set_itr(adapter); netif_rx_complete(netdev, napi); if (!test_bit(__IGB_DOWN, &adapter->state)) igb_irq_enable(adapter); @@ -3619,15 +3649,11 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) quit_polling: netif_rx_complete(netdev, napi); - wr32(E1000_EIMS, rx_ring->eims_value); - if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust && - (rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) { - int mean_size = rx_ring->total_bytes / - rx_ring->total_packets; - if (mean_size < IGB_DYN_ITR_LENGTH_LOW) - igb_raise_rx_eitr(adapter, rx_ring); - else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH) - igb_lower_rx_eitr(adapter, rx_ring); + if (adapter->itr_setting & 3) { + if (adapter->num_rx_queues == 1) + igb_set_itr(adapter); + else + igb_update_ring_itr(rx_ring); } if (!test_bit(__IGB_DOWN, &adapter->state)) @@ -3972,7 +3998,6 @@ send_up: dev_kfree_skb_irq(skb); goto next_desc; } - rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT); total_bytes += skb->len; total_packets++; -- cgit v1.2.3-70-g09d2 From 070825b3840a743e21ebcc44f8279708a4fed977 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 17 Jul 2008 01:50:11 -0700 Subject: igb: Kill CONFIG_NETDEVICES_MULTIQUEUE references, no longer exists. Signed-off-by: David S. Miller --- drivers/net/igb/igb.h | 2 -- drivers/net/igb/igb_main.c | 51 ---------------------------------------------- 2 files changed, 53 deletions(-) (limited to 'drivers/net/igb/igb.h') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 56de7ec15b46..4ff6f0567f3f 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -287,9 +287,7 @@ struct igb_adapter { int bars; int need_ioport; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; -#endif /* CONFIG_NETDEVICES_MULTIQUEUE */ #ifdef CONFIG_IGB_LRO unsigned int lro_max_aggr; unsigned int lro_aggregated; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 74dc43e29261..64a150a16f39 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -532,10 +532,8 @@ msi_only: if (!pci_enable_msi(adapter->pdev)) adapter->flags |= IGB_FLAG_HAS_MSI; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE /* Notify the stack of the (possibly) reduced Tx Queue count. */ adapter->netdev->egress_subqueue_count = adapter->num_tx_queues; -#endif return; } @@ -824,10 +822,8 @@ void igb_down(struct igb_adapter *adapter) /* flush and sleep below */ netif_stop_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < adapter->num_tx_queues; i++) netif_stop_subqueue(netdev, i); -#endif /* disable transmits in the hardware */ tctl = rd32(E1000_TCTL); @@ -1042,11 +1038,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, pci_save_state(pdev); err = -ENOMEM; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES); -#else - netdev = alloc_etherdev(sizeof(struct igb_adapter)); -#endif /* CONFIG_NETDEVICES_MULTIQUEUE */ if (!netdev) goto err_alloc_etherdev; @@ -1163,9 +1155,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netdev->features |= NETIF_F_MULTI_QUEUE; -#endif netdev->features |= NETIF_F_LLTX; adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw); @@ -1279,10 +1269,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until igb_open() is called */ netif_carrier_off(netdev); netif_stop_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < adapter->num_tx_queues; i++) netif_stop_subqueue(netdev, i); -#endif strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); @@ -1432,11 +1420,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) /* Number of supported queues. */ /* Having more queues than CPUs doesn't make sense. */ adapter->num_rx_queues = min((u32)IGB_MAX_RX_QUEUES, (u32)num_online_cpus()); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE adapter->num_tx_queues = min(IGB_MAX_TX_QUEUES, num_online_cpus()); -#else - adapter->num_tx_queues = 1; -#endif /* CONFIG_NET_MULTI_QUEUE_DEVICE */ /* This call may decrease the number of queues depending on * interrupt mode. */ @@ -1619,9 +1603,7 @@ err: static int igb_setup_all_tx_resources(struct igb_adapter *adapter) { int i, err = 0; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE int r_idx; -#endif for (i = 0; i < adapter->num_tx_queues; i++) { err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]); @@ -1634,12 +1616,10 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter) } } -#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < IGB_MAX_TX_QUEUES; i++) { r_idx = i % adapter->num_tx_queues; adapter->multi_tx_table[i] = &adapter->tx_ring[r_idx]; } -#endif return err; } @@ -2337,9 +2317,7 @@ static void igb_watchdog_task(struct work_struct *work) struct e1000_mac_info *mac = &adapter->hw.mac; u32 link; s32 ret_val; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE int i; -#endif if ((netif_carrier_ok(netdev)) && (rd32(E1000_STATUS) & E1000_STATUS_LU)) @@ -2396,10 +2374,8 @@ static void igb_watchdog_task(struct work_struct *work) netif_carrier_on(netdev); netif_wake_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < adapter->num_tx_queues; i++) netif_wake_subqueue(netdev, i); -#endif if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -2412,10 +2388,8 @@ static void igb_watchdog_task(struct work_struct *work) dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); netif_carrier_off(netdev); netif_stop_queue(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < adapter->num_tx_queues; i++) netif_stop_subqueue(netdev, i); -#endif if (!test_bit(__IGB_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -2943,11 +2917,7 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(netdev, tx_ring->queue_index); -#else - netif_stop_queue(netdev); -#endif /* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); @@ -2960,11 +2930,7 @@ static int __igb_maybe_stop_tx(struct net_device *netdev, return -EBUSY; /* A reprieve! */ -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_wake_subqueue(netdev, tx_ring->queue_index); -#else - netif_wake_queue(netdev); -#endif ++adapter->restart_queue; return 0; } @@ -3051,14 +3017,9 @@ static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) struct igb_adapter *adapter = netdev_priv(netdev); struct igb_ring *tx_ring; -#ifdef CONFIG_NETDEVICES_MULTIQUEUE int r_idx = 0; r_idx = skb->queue_mapping & (IGB_MAX_TX_QUEUES - 1); tx_ring = adapter->multi_tx_table[r_idx]; -#else - tx_ring = &adapter->tx_ring[0]; -#endif - /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively @@ -3745,19 +3706,11 @@ done_cleaning: * sees the new next_to_clean. */ smp_mb(); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !(test_bit(__IGB_DOWN, &adapter->state))) { netif_wake_subqueue(netdev, tx_ring->queue_index); ++adapter->restart_queue; } -#else - if (netif_queue_stopped(netdev) && - !(test_bit(__IGB_DOWN, &adapter->state))) { - netif_wake_queue(netdev); - ++adapter->restart_queue; - } -#endif } if (tx_ring->detect_tx_hung) { @@ -3793,11 +3746,7 @@ done_cleaning: tx_ring->buffer_info[i].time_stamp, jiffies, tx_desc->upper.fields.status); -#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(netdev, tx_ring->queue_index); -#else - netif_stop_queue(netdev); -#endif } } tx_ring->total_bytes += total_bytes; -- cgit v1.2.3-70-g09d2