提交 6eb5a7f1 编写于 作者: A Alexander Duyck 提交者: Jeff Garzik

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: NAlexander Duyck <alexander.h.duyck@intel.com>
Acked-by: NMitch Williams <mitch.a.williams@intel.com>
Signed-off-by: NJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: NJeff Garzik <jgarzik@redhat.com>
上级 9280fa52
...@@ -47,7 +47,9 @@ struct igb_adapter; ...@@ -47,7 +47,9 @@ struct igb_adapter;
#define IGB_MIN_DYN_ITR 3000 #define IGB_MIN_DYN_ITR 3000
#define IGB_MAX_DYN_ITR 96000 #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_PACKET_THRESHOLD 2
#define IGB_DYN_ITR_LENGTH_LOW 200 #define IGB_DYN_ITR_LENGTH_LOW 200
...@@ -170,9 +172,10 @@ struct igb_ring { ...@@ -170,9 +172,10 @@ struct igb_ring {
}; };
/* RX */ /* RX */
struct { struct {
int no_itr_adjust;
struct igb_queue_stats rx_stats; struct igb_queue_stats rx_stats;
struct napi_struct napi; struct napi_struct napi;
int set_itr;
struct igb_ring *buddy;
#ifdef CONFIG_IGB_LRO #ifdef CONFIG_IGB_LRO
struct net_lro_mgr lro_mgr; struct net_lro_mgr lro_mgr;
bool lro_used; bool lro_used;
...@@ -219,7 +222,6 @@ struct igb_adapter { ...@@ -219,7 +222,6 @@ struct igb_adapter {
u32 itr_setting; u32 itr_setting;
u16 tx_itr; u16 tx_itr;
u16 rx_itr; u16 rx_itr;
int set_itr;
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct watchdog_task; struct work_struct watchdog_task;
......
...@@ -1861,6 +1861,8 @@ static int igb_set_coalesce(struct net_device *netdev, ...@@ -1861,6 +1861,8 @@ static int igb_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec) struct ethtool_coalesce *ec)
{ {
struct igb_adapter *adapter = netdev_priv(netdev); struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
int i;
if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) ||
((ec->rx_coalesce_usecs > 3) && ((ec->rx_coalesce_usecs > 3) &&
...@@ -1869,13 +1871,16 @@ static int igb_set_coalesce(struct net_device *netdev, ...@@ -1869,13 +1871,16 @@ static int igb_set_coalesce(struct net_device *netdev,
return -EINVAL; return -EINVAL;
/* convert to rate of irq's per second */ /* 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; adapter->itr_setting = ec->rx_coalesce_usecs;
else adapter->itr = IGB_START_ITR;
adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs); } else {
adapter->itr_setting = ec->rx_coalesce_usecs << 2;
adapter->itr = adapter->itr_setting;
}
if (netif_running(netdev)) for (i = 0; i < adapter->num_rx_queues; i++)
igb_reinit_locked(adapter); wr32(adapter->rx_ring[i].itr_register, adapter->itr);
return 0; return 0;
} }
...@@ -1888,7 +1893,7 @@ static int igb_get_coalesce(struct net_device *netdev, ...@@ -1888,7 +1893,7 @@ static int igb_get_coalesce(struct net_device *netdev,
if (adapter->itr_setting <= 3) if (adapter->itr_setting <= 3)
ec->rx_coalesce_usecs = adapter->itr_setting; ec->rx_coalesce_usecs = adapter->itr_setting;
else else
ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; ec->rx_coalesce_usecs = adapter->itr_setting >> 2;
return 0; return 0;
} }
......
...@@ -255,6 +255,8 @@ static int igb_alloc_queues(struct igb_adapter *adapter) ...@@ -255,6 +255,8 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
return -ENOMEM; return -ENOMEM;
} }
adapter->rx_ring->buddy = adapter->tx_ring;
for (i = 0; i < adapter->num_tx_queues; i++) { for (i = 0; i < adapter->num_tx_queues; i++) {
struct igb_ring *ring = &(adapter->tx_ring[i]); struct igb_ring *ring = &(adapter->tx_ring[i]);
ring->adapter = adapter; ring->adapter = adapter;
...@@ -375,7 +377,7 @@ static void igb_configure_msix(struct igb_adapter *adapter) ...@@ -375,7 +377,7 @@ static void igb_configure_msix(struct igb_adapter *adapter)
igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++); igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++);
adapter->eims_enable_mask |= tx_ring->eims_value; adapter->eims_enable_mask |= tx_ring->eims_value;
if (tx_ring->itr_val) if (tx_ring->itr_val)
writel(1000000000 / (tx_ring->itr_val * 256), writel(tx_ring->itr_val,
hw->hw_addr + tx_ring->itr_register); hw->hw_addr + tx_ring->itr_register);
else else
writel(1, hw->hw_addr + tx_ring->itr_register); writel(1, hw->hw_addr + tx_ring->itr_register);
...@@ -383,10 +385,11 @@ static void igb_configure_msix(struct igb_adapter *adapter) ...@@ -383,10 +385,11 @@ static void igb_configure_msix(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++) { for (i = 0; i < adapter->num_rx_queues; i++) {
struct igb_ring *rx_ring = &adapter->rx_ring[i]; struct igb_ring *rx_ring = &adapter->rx_ring[i];
rx_ring->buddy = 0;
igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++); igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++);
adapter->eims_enable_mask |= rx_ring->eims_value; adapter->eims_enable_mask |= rx_ring->eims_value;
if (rx_ring->itr_val) if (rx_ring->itr_val)
writel(1000000000 / (rx_ring->itr_val * 256), writel(rx_ring->itr_val,
hw->hw_addr + rx_ring->itr_register); hw->hw_addr + rx_ring->itr_register);
else else
writel(1, hw->hw_addr + rx_ring->itr_register); writel(1, hw->hw_addr + rx_ring->itr_register);
...@@ -449,7 +452,7 @@ static int igb_request_msix(struct igb_adapter *adapter) ...@@ -449,7 +452,7 @@ static int igb_request_msix(struct igb_adapter *adapter)
if (err) if (err)
goto out; goto out;
ring->itr_register = E1000_EITR(0) + (vector << 2); ring->itr_register = E1000_EITR(0) + (vector << 2);
ring->itr_val = adapter->itr; ring->itr_val = 976; /* ~4000 ints/sec */
vector++; vector++;
} }
for (i = 0; i < adapter->num_rx_queues; i++) { for (i = 0; i < adapter->num_rx_queues; i++) {
...@@ -1898,8 +1901,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) ...@@ -1898,8 +1901,7 @@ static void igb_configure_rx(struct igb_adapter *adapter)
mdelay(10); mdelay(10);
if (adapter->itr_setting > 3) if (adapter->itr_setting > 3)
wr32(E1000_ITR, wr32(E1000_ITR, adapter->itr);
1000000000 / (adapter->itr * 256));
/* Setup the HW Rx Head and Tail Descriptor Pointers and /* Setup the HW Rx Head and Tail Descriptor Pointers and
* the Base and Length of the Rx Descriptor Ring */ * the Base and Length of the Rx Descriptor Ring */
...@@ -2463,38 +2465,60 @@ enum latency_range { ...@@ -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 = rx_ring->itr_val;
int new_val; int avg_wire_size = 0;
struct igb_adapter *adapter = rx_ring->adapter;
new_val = rx_ring->itr_val / 2; if (!rx_ring->total_packets)
if (new_val < IGB_MIN_DYN_ITR) goto clear_counts; /* no packets, so don't do anything */
new_val = IGB_MIN_DYN_ITR;
if (new_val != rx_ring->itr_val) { /* For non-gigabit speeds, just fix the interrupt rate at 4000
rx_ring->itr_val = new_val; * ints/sec - ITR timer value of 120 ticks.
wr32(rx_ring->itr_register, */
1000000000 / (new_val * 256)); 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, /* Add 24 bytes to size to account for CRC, preamble, and gap */
struct igb_ring *rx_ring) avg_wire_size += 24;
{
struct e1000_hw *hw = &adapter->hw; /* Don't starve jumbo frames */
int new_val; avg_wire_size = min(avg_wire_size, 3000);
new_val = rx_ring->itr_val * 2; /* Give a little boost to mid-size frames */
if (new_val > IGB_MAX_DYN_ITR) if ((avg_wire_size > 300) && (avg_wire_size < 1200))
new_val = IGB_MAX_DYN_ITR; new_val = avg_wire_size / 3;
else
new_val = avg_wire_size / 2;
set_itr_val:
if (new_val != rx_ring->itr_val) { if (new_val != rx_ring->itr_val) {
rx_ring->itr_val = new_val; rx_ring->itr_val = new_val;
wr32(rx_ring->itr_register, rx_ring->set_itr = 1;
1000000000 / (new_val * 256));
} }
clear_counts:
rx_ring->total_bytes = 0;
rx_ring->total_packets = 0;
} }
/** /**
...@@ -2561,8 +2585,7 @@ static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting, ...@@ -2561,8 +2585,7 @@ static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting,
return retval; return retval;
} }
static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, static void igb_set_itr(struct igb_adapter *adapter)
int rx_only)
{ {
u16 current_itr; u16 current_itr;
u32 new_itr = adapter->itr; u32 new_itr = adapter->itr;
...@@ -2578,26 +2601,23 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, ...@@ -2578,26 +2601,23 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register,
adapter->rx_itr, adapter->rx_itr,
adapter->rx_ring->total_packets, adapter->rx_ring->total_packets,
adapter->rx_ring->total_bytes); 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 = igb_update_itr(adapter,
adapter->tx_itr, adapter->tx_itr,
adapter->tx_ring->total_packets, adapter->tx_ring->total_packets,
adapter->tx_ring->total_bytes); 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); current_itr = max(adapter->rx_itr, adapter->tx_itr);
} else { } else {
current_itr = adapter->rx_itr; 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) { switch (current_itr) {
/* counts and packets in update_itr are dependent on these numbers */ /* counts and packets in update_itr are dependent on these numbers */
case lowest_latency: case lowest_latency:
...@@ -2614,6 +2634,13 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, ...@@ -2614,6 +2634,13 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register,
} }
set_itr_now: 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) { if (new_itr != adapter->itr) {
/* this attempts to bias the interrupt rate towards Bulk /* this attempts to bias the interrupt rate towards Bulk
* by adding intermediate steps when interrupt rate is * by adding intermediate steps when interrupt rate is
...@@ -2628,7 +2655,8 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, ...@@ -2628,7 +2655,8 @@ static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register,
* ends up being correct. * ends up being correct.
*/ */
adapter->itr = new_itr; adapter->itr = new_itr;
adapter->set_itr = 1; adapter->rx_ring->itr_val = 1000000000 / (new_itr * 256);
adapter->rx_ring->set_itr = 1;
} }
return; return;
...@@ -2979,6 +3007,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, ...@@ -2979,6 +3007,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
/* this is a hard error */ /* this is a hard error */
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
skb_orphan(skb);
if (adapter->vlgrp && vlan_tx_tag_present(skb)) { if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
tx_flags |= IGB_TX_FLAGS_VLAN; tx_flags |= IGB_TX_FLAGS_VLAN;
...@@ -3312,8 +3341,6 @@ static irqreturn_t igb_msix_tx(int irq, void *data) ...@@ -3312,8 +3341,6 @@ static irqreturn_t igb_msix_tx(int irq, void *data)
struct igb_adapter *adapter = tx_ring->adapter; struct igb_adapter *adapter = tx_ring->adapter;
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
if (!tx_ring->itr_val)
wr32(E1000_EIMC, tx_ring->eims_value);
#ifdef CONFIG_DCA #ifdef CONFIG_DCA
if (adapter->flags & IGB_FLAG_DCA_ENABLED) if (adapter->flags & IGB_FLAG_DCA_ENABLED)
igb_update_tx_dca(tx_ring); igb_update_tx_dca(tx_ring);
...@@ -3332,21 +3359,36 @@ static irqreturn_t igb_msix_tx(int irq, void *data) ...@@ -3332,21 +3359,36 @@ static irqreturn_t igb_msix_tx(int irq, void *data)
return IRQ_HANDLED; 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) static irqreturn_t igb_msix_rx(int irq, void *data)
{ {
struct igb_ring *rx_ring = data; struct igb_ring *rx_ring = data;
struct igb_adapter *adapter = rx_ring->adapter; struct igb_adapter *adapter = rx_ring->adapter;
struct e1000_hw *hw = &adapter->hw;
/* Write the ITR value calculated at the end of the /* Write the ITR value calculated at the end of the
* previous interrupt. * previous interrupt.
*/ */
if (adapter->set_itr) { igb_write_itr(rx_ring);
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)) if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi))
__netif_rx_schedule(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) ...@@ -3493,13 +3535,7 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
/* read ICR disables interrupts using IAM */ /* read ICR disables interrupts using IAM */
u32 icr = rd32(E1000_ICR); u32 icr = rd32(E1000_ICR);
/* Write the ITR value calculated at the end of the igb_write_itr(adapter->rx_ring);
* previous interrupt.
*/
if (adapter->set_itr) {
wr32(E1000_ITR, 1000000000 / (adapter->itr * 256));
adapter->set_itr = 0;
}
if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
hw->mac.get_link_status = 1; hw->mac.get_link_status = 1;
...@@ -3529,13 +3565,7 @@ static irqreturn_t igb_intr(int irq, void *data) ...@@ -3529,13 +3565,7 @@ static irqreturn_t igb_intr(int irq, void *data)
if (!icr) if (!icr)
return IRQ_NONE; /* Not our interrupt */ return IRQ_NONE; /* Not our interrupt */
/* Write the ITR value calculated at the end of the igb_write_itr(adapter->rx_ring);
* previous interrupt.
*/
if (adapter->set_itr) {
wr32(E1000_ITR, 1000000000 / (adapter->itr * 256));
adapter->set_itr = 0;
}
/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is /* 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 */ * not set, then the adapter didn't send an interrupt */
...@@ -3585,7 +3615,7 @@ static int igb_poll(struct napi_struct *napi, int budget) ...@@ -3585,7 +3615,7 @@ static int igb_poll(struct napi_struct *napi, int budget)
if ((tx_clean_complete && (work_done < budget)) || if ((tx_clean_complete && (work_done < budget)) ||
!netif_running(netdev)) { !netif_running(netdev)) {
if (adapter->itr_setting & 3) if (adapter->itr_setting & 3)
igb_set_itr(adapter, E1000_ITR, false); igb_set_itr(adapter);
netif_rx_complete(netdev, napi); netif_rx_complete(netdev, napi);
if (!test_bit(__IGB_DOWN, &adapter->state)) if (!test_bit(__IGB_DOWN, &adapter->state))
igb_irq_enable(adapter); igb_irq_enable(adapter);
...@@ -3619,15 +3649,11 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) ...@@ -3619,15 +3649,11 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget)
quit_polling: quit_polling:
netif_rx_complete(netdev, napi); netif_rx_complete(netdev, napi);
wr32(E1000_EIMS, rx_ring->eims_value); if (adapter->itr_setting & 3) {
if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust && if (adapter->num_rx_queues == 1)
(rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) { igb_set_itr(adapter);
int mean_size = rx_ring->total_bytes / else
rx_ring->total_packets; igb_update_ring_itr(rx_ring);
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 (!test_bit(__IGB_DOWN, &adapter->state)) if (!test_bit(__IGB_DOWN, &adapter->state))
...@@ -3972,7 +3998,6 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, ...@@ -3972,7 +3998,6 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
goto next_desc; goto next_desc;
} }
rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT);
total_bytes += skb->len; total_bytes += skb->len;
total_packets++; total_packets++;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册