Commit 7bfa4816 authored by Jeff Kirsher's avatar Jeff Kirsher Committed by Jeff Garzik

[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: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarJohn Ronciak <john.ronciak@intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent f56799ea
...@@ -72,10 +72,6 @@ ...@@ -72,10 +72,6 @@
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.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_0 0
#define BAR_1 1 #define BAR_1 1
...@@ -87,6 +83,10 @@ ...@@ -87,6 +83,10 @@
struct e1000_adapter; struct e1000_adapter;
#include "e1000_hw.h" #include "e1000_hw.h"
#ifdef CONFIG_E1000_MQ
#include <linux/cpu.h>
#include <linux/smp.h>
#endif
#ifdef DBG #ifdef DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
...@@ -169,6 +169,13 @@ struct e1000_buffer { ...@@ -169,6 +169,13 @@ struct e1000_buffer {
uint16_t next_to_watch; 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 { struct page *ps_page[PS_PAGE_BUFFERS]; };
struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; };
...@@ -194,6 +201,9 @@ struct e1000_tx_ring { ...@@ -194,6 +201,9 @@ struct e1000_tx_ring {
boolean_t last_tx_tso; boolean_t last_tx_tso;
#ifdef CONFIG_E1000_MQ
struct e1000_queue_stats tx_stats;
#endif
}; };
struct e1000_rx_ring { struct e1000_rx_ring {
...@@ -223,6 +233,9 @@ struct e1000_rx_ring { ...@@ -223,6 +233,9 @@ struct e1000_rx_ring {
uint16_t rdh; uint16_t rdh;
uint16_t rdt; uint16_t rdt;
#ifdef CONFIG_E1000_MQ
struct e1000_queue_stats rx_stats;
#endif
}; };
#define E1000_DESC_UNUSED(R) \ #define E1000_DESC_UNUSED(R) \
...@@ -255,6 +268,9 @@ struct e1000_adapter { ...@@ -255,6 +268,9 @@ struct e1000_adapter {
uint16_t link_speed; uint16_t link_speed;
uint16_t link_duplex; uint16_t link_duplex;
spinlock_t stats_lock; spinlock_t stats_lock;
#ifdef CONFIG_E1000_NAPI
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem; atomic_t irq_sem;
struct work_struct tx_timeout_task; struct work_struct tx_timeout_task;
struct work_struct watchdog_task; struct work_struct watchdog_task;
...@@ -302,7 +318,7 @@ struct e1000_adapter { ...@@ -302,7 +318,7 @@ struct e1000_adapter {
#ifdef CONFIG_E1000_MQ #ifdef CONFIG_E1000_MQ
struct net_device **cpu_netdev; /* per-cpu */ struct net_device **cpu_netdev; /* per-cpu */
struct call_async_data_struct rx_sched_call_data; struct call_async_data_struct rx_sched_call_data;
int cpu_for_queue[4]; cpumask_t cpumask;
#endif #endif
int num_tx_queues; int num_tx_queues;
int num_rx_queues; int num_rx_queues;
......
...@@ -96,8 +96,18 @@ static const struct e1000_stats e1000_gstrings_stats[] = { ...@@ -96,8 +96,18 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_header_split", E1000_STAT(rx_hdr_split) }, { "rx_header_split", E1000_STAT(rx_hdr_split) },
{ "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, { "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) 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] = { static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
"Register test (offline)", "Eeprom test (offline)", "Register test (offline)", "Eeprom test (offline)",
"Interrupt test (offline)", "Loopback test (offline)", "Interrupt test (offline)", "Loopback test (offline)",
...@@ -1746,19 +1756,43 @@ e1000_get_ethtool_stats(struct net_device *netdev, ...@@ -1746,19 +1756,43 @@ e1000_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data) struct ethtool_stats *stats, uint64_t *data)
{ {
struct e1000_adapter *adapter = netdev_priv(netdev); 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; int i;
e1000_update_stats(adapter); e1000_update_stats(adapter);
for(i = 0; i < E1000_STATS_LEN; i++) { for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
data[i] = (e1000_gstrings_stats[i].sizeof_stat == data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; 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 static void
e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) 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; int i;
switch(stringset) { switch(stringset) {
...@@ -1767,11 +1801,26 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) ...@@ -1767,11 +1801,26 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
E1000_TEST_LEN*ETH_GSTRING_LEN); E1000_TEST_LEN*ETH_GSTRING_LEN);
break; break;
case ETH_SS_STATS: case ETH_SS_STATS:
for (i=0; i < E1000_STATS_LEN; i++) { for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
memcpy(data + i * ETH_GSTRING_LEN, memcpy(p, e1000_gstrings_stats[i].stat_string,
e1000_gstrings_stats[i].stat_string,
ETH_GSTRING_LEN); 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; break;
} }
} }
......
...@@ -433,6 +433,12 @@ e1000_up(struct e1000_adapter *adapter) ...@@ -433,6 +433,12 @@ e1000_up(struct e1000_adapter *adapter)
return err; 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); mod_timer(&adapter->watchdog_timer, jiffies);
#ifdef CONFIG_E1000_NAPI #ifdef CONFIG_E1000_NAPI
...@@ -467,6 +473,7 @@ e1000_down(struct e1000_adapter *adapter) ...@@ -467,6 +473,7 @@ e1000_down(struct e1000_adapter *adapter)
#ifdef CONFIG_E1000_NAPI #ifdef CONFIG_E1000_NAPI
netif_poll_disable(netdev); netif_poll_disable(netdev);
#endif #endif
netdev->tx_queue_len = adapter->tx_queue_len;
adapter->link_speed = 0; adapter->link_speed = 0;
adapter->link_duplex = 0; adapter->link_duplex = 0;
netif_carrier_off(netdev); netif_carrier_off(netdev);
...@@ -989,6 +996,15 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -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_rx_queues = min(adapter->num_rx_queues, num_online_cpus());
adapter->num_tx_queues = min(adapter->num_tx_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 #else
adapter->num_tx_queues = 1; adapter->num_tx_queues = 1;
adapter->num_rx_queues = 1; adapter->num_rx_queues = 1;
...@@ -1007,10 +1023,7 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -1007,10 +1023,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
dev_hold(&adapter->polling_netdev[i]); dev_hold(&adapter->polling_netdev[i]);
set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
} }
#endif spin_lock_init(&adapter->tx_queue_lock);
#ifdef CONFIG_E1000_MQ
e1000_setup_queue_mapping(adapter);
#endif #endif
atomic_set(&adapter->irq_sem, 1); atomic_set(&adapter->irq_sem, 1);
...@@ -1058,6 +1071,14 @@ e1000_alloc_queues(struct e1000_adapter *adapter) ...@@ -1058,6 +1071,14 @@ e1000_alloc_queues(struct e1000_adapter *adapter)
memset(adapter->polling_netdev, 0, size); memset(adapter->polling_netdev, 0, size);
#endif #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; return E1000_SUCCESS;
} }
...@@ -1084,7 +1105,8 @@ e1000_setup_queue_mapping(struct e1000_adapter *adapter) ...@@ -1084,7 +1105,8 @@ e1000_setup_queue_mapping(struct e1000_adapter *adapter)
*/ */
if (i < adapter->num_rx_queues) { if (i < adapter->num_rx_queues) {
*per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; *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 } else
*per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL;
...@@ -3337,6 +3359,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, ...@@ -3337,6 +3359,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
if(unlikely(++i == tx_ring->count)) i = 0; 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 = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop); eop_desc = E1000_TX_DESC(*tx_ring, eop);
} }
...@@ -3365,6 +3391,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, ...@@ -3365,6 +3391,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
eop = tx_ring->buffer_info[i].next_to_watch; eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop); eop_desc = E1000_TX_DESC(*tx_ring, eop);
DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
" Tx Queue <%lu>\n"
" TDH <%x>\n" " TDH <%x>\n"
" TDT <%x>\n" " TDT <%x>\n"
" next_to_use <%x>\n" " next_to_use <%x>\n"
...@@ -3375,6 +3402,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, ...@@ -3375,6 +3402,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
" next_to_watch <%x>\n" " next_to_watch <%x>\n"
" jiffies <%lx>\n" " jiffies <%lx>\n"
" next_to_watch.status <%x>\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->tdh),
readl(adapter->hw.hw_addr + tx_ring->tdt), readl(adapter->hw.hw_addr + tx_ring->tdt),
tx_ring->next_to_use, tx_ring->next_to_use,
...@@ -3541,6 +3570,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, ...@@ -3541,6 +3570,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
} }
#endif /* CONFIG_E1000_NAPI */ #endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies; netdev->last_rx = jiffies;
#ifdef CONFIG_E1000_MQ
rx_ring->rx_stats.packets++;
rx_ring->rx_stats.bytes += length;
#endif
next_desc: next_desc:
rx_desc->status = 0; rx_desc->status = 0;
...@@ -3671,6 +3704,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, ...@@ -3671,6 +3704,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
} }
#endif /* CONFIG_E1000_NAPI */ #endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies; netdev->last_rx = jiffies;
#ifdef CONFIG_E1000_MQ
rx_ring->rx_stats.packets++;
rx_ring->rx_stats.bytes += length;
#endif
next_desc: next_desc:
rx_desc->wb.middle.status_error &= ~0xFF; rx_desc->wb.middle.status_error &= ~0xFF;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment