diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2006-01-13 00:50:41 (GMT) |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-17 12:40:11 (GMT) |
commit | 7bfa48162d4924e8cc7fb8eccc8c8f66cc111eb4 (patch) | |
tree | 906365b7e1c17f15fa470dbad448cafa3310f011 /drivers/net | |
parent | f56799ea39a85a6f3760a134aa0e6d1c17eea369 (diff) | |
download | linux-7bfa48162d4924e8cc7fb8eccc8c8f66cc111eb4.tar.xz |
[PATCH] e1000: Fix mulitple queues
Fixed stats when using multiple queues.
When multiple queues are enabled, log a message in syslog.
Fixed memory allocation for multiple queues.
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: John Ronciak <john.ronciak@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000/e1000.h | 26 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_ethtool.c | 65 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_main.c | 47 |
3 files changed, 120 insertions, 18 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 5940f7a..0a084e9 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -72,10 +72,6 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> -#ifdef CONFIG_E1000_MQ -#include <linux/cpu.h> -#include <linux/smp.h> -#endif #define BAR_0 0 #define BAR_1 1 @@ -87,6 +83,10 @@ struct e1000_adapter; #include "e1000_hw.h" +#ifdef CONFIG_E1000_MQ +#include <linux/cpu.h> +#include <linux/smp.h> +#endif #ifdef DBG #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) @@ -169,6 +169,13 @@ struct e1000_buffer { uint16_t next_to_watch; }; +#ifdef CONFIG_E1000_MQ +struct e1000_queue_stats { + uint64_t packets; + uint64_t bytes; +}; +#endif + struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; @@ -194,6 +201,9 @@ struct e1000_tx_ring { boolean_t last_tx_tso; +#ifdef CONFIG_E1000_MQ + struct e1000_queue_stats tx_stats; +#endif }; struct e1000_rx_ring { @@ -223,6 +233,9 @@ struct e1000_rx_ring { uint16_t rdh; uint16_t rdt; +#ifdef CONFIG_E1000_MQ + struct e1000_queue_stats rx_stats; +#endif }; #define E1000_DESC_UNUSED(R) \ @@ -255,6 +268,9 @@ struct e1000_adapter { uint16_t link_speed; uint16_t link_duplex; spinlock_t stats_lock; +#ifdef CONFIG_E1000_NAPI + spinlock_t tx_queue_lock; +#endif atomic_t irq_sem; struct work_struct tx_timeout_task; struct work_struct watchdog_task; @@ -302,7 +318,7 @@ struct e1000_adapter { #ifdef CONFIG_E1000_MQ struct net_device **cpu_netdev; /* per-cpu */ struct call_async_data_struct rx_sched_call_data; - int cpu_for_queue[4]; + cpumask_t cpumask; #endif int num_tx_queues; int num_rx_queues; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index fa9a465..ffdf76b 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -96,8 +96,18 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_header_split", E1000_STAT(rx_hdr_split) }, { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, }; -#define E1000_STATS_LEN \ + +#ifdef CONFIG_E1000_MQ +#define E1000_QUEUE_STATS_LEN \ + (((struct e1000_adapter *)netdev->priv)->num_tx_queues + \ + ((struct e1000_adapter *)netdev->priv)->num_rx_queues) \ + * (sizeof(struct e1000_queue_stats) / sizeof(uint64_t)) +#else +#define E1000_QUEUE_STATS_LEN 0 +#endif +#define E1000_GLOBAL_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN) static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", @@ -1746,19 +1756,43 @@ e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct e1000_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_E1000_MQ + uint64_t *queue_stat; + int stat_count = sizeof(struct e1000_queue_stats) / sizeof(uint64_t); + int j, k; +#endif int i; e1000_update_stats(adapter); - for(i = 0; i < E1000_STATS_LEN; i++) { - char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; - data[i] = (e1000_gstrings_stats[i].sizeof_stat == + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } +#ifdef CONFIG_E1000_MQ + for (j = 0; j < adapter->num_tx_queues; j++) { + queue_stat = (uint64_t *)&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++) { + queue_stat = (uint64_t *)&adapter->rx_ring[j].rx_stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +#endif +/* BUG_ON(i != E1000_STATS_LEN); */ } static void e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) { +#ifdef CONFIG_E1000_MQ + struct e1000_adapter *adapter = netdev_priv(netdev); +#endif + uint8_t *p = data; int i; switch(stringset) { @@ -1767,11 +1801,26 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) E1000_TEST_LEN*ETH_GSTRING_LEN); break; case ETH_SS_STATS: - for (i=0; i < E1000_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - e1000_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + memcpy(p, e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } +#ifdef CONFIG_E1000_MQ + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(p, "tx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; } + for (i = 0; i < adapter->num_rx_queues; i++) { + sprintf(p, "rx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +#endif +/* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */ break; } } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 540c856..4016264 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -433,6 +433,12 @@ e1000_up(struct e1000_adapter *adapter) return err; } +#ifdef CONFIG_E1000_MQ + e1000_setup_queue_mapping(adapter); +#endif + + adapter->tx_queue_len = netdev->tx_queue_len; + mod_timer(&adapter->watchdog_timer, jiffies); #ifdef CONFIG_E1000_NAPI @@ -467,6 +473,7 @@ e1000_down(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI netif_poll_disable(netdev); #endif + netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); @@ -989,6 +996,15 @@ e1000_sw_init(struct e1000_adapter *adapter) } adapter->num_rx_queues = min(adapter->num_rx_queues, num_online_cpus()); adapter->num_tx_queues = min(adapter->num_tx_queues, num_online_cpus()); + DPRINTK(DRV, INFO, "Multiqueue Enabled: Rx Queue count = %u %s\n", + adapter->num_rx_queues, + ((adapter->num_rx_queues == 1) + ? ((num_online_cpus() > 1) + ? "(due to unsupported feature in current adapter)" + : "(due to unsupported system configuration)") + : "")); + DPRINTK(DRV, INFO, "Multiqueue Enabled: Tx Queue count = %u\n", + adapter->num_tx_queues); #else adapter->num_tx_queues = 1; adapter->num_rx_queues = 1; @@ -1007,10 +1023,7 @@ e1000_sw_init(struct e1000_adapter *adapter) dev_hold(&adapter->polling_netdev[i]); set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); } -#endif - -#ifdef CONFIG_E1000_MQ - e1000_setup_queue_mapping(adapter); + spin_lock_init(&adapter->tx_queue_lock); #endif atomic_set(&adapter->irq_sem, 1); @@ -1058,6 +1071,14 @@ e1000_alloc_queues(struct e1000_adapter *adapter) memset(adapter->polling_netdev, 0, size); #endif +#ifdef CONFIG_E1000_MQ + adapter->rx_sched_call_data.func = e1000_rx_schedule; + adapter->rx_sched_call_data.info = adapter->netdev; + + adapter->cpu_netdev = alloc_percpu(struct net_device *); + adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); +#endif + return E1000_SUCCESS; } @@ -1084,7 +1105,8 @@ e1000_setup_queue_mapping(struct e1000_adapter *adapter) */ if (i < adapter->num_rx_queues) { *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; - adapter->cpu_for_queue[i] = cpu; + adapter->rx_ring[i].cpu = cpu; + cpu_set(cpu, adapter->cpumask); } else *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; @@ -3337,6 +3359,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, if(unlikely(++i == tx_ring->count)) i = 0; } +#ifdef CONFIG_E1000_MQ + tx_ring->tx_stats.packets++; +#endif + eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); } @@ -3365,6 +3391,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" + " Tx Queue <%lu>\n" " TDH <%x>\n" " TDT <%x>\n" " next_to_use <%x>\n" @@ -3375,6 +3402,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, " next_to_watch <%x>\n" " jiffies <%lx>\n" " next_to_watch.status <%x>\n", + (unsigned long)((tx_ring - adapter->tx_ring) / + sizeof(struct e1000_tx_ring)), readl(adapter->hw.hw_addr + tx_ring->tdh), readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, @@ -3541,6 +3570,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +#ifdef CONFIG_E1000_MQ + rx_ring->rx_stats.packets++; + rx_ring->rx_stats.bytes += length; +#endif next_desc: rx_desc->status = 0; @@ -3671,6 +3704,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +#ifdef CONFIG_E1000_MQ + rx_ring->rx_stats.packets++; + rx_ring->rx_stats.bytes += length; +#endif next_desc: rx_desc->wb.middle.status_error &= ~0xFF; |