aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-03-20 09:30:37 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-21 22:06:58 -0400
commit6fb70fd1b57707a5c7b9fb167b7790b2cba13f04 (patch)
tree311192bd4de07e1da571f1a6ac6a3ad123ab3f50 /drivers/net
parent85451a951b9511605475fadcc0a8d3aeccefded8 (diff)
sfc: Implement adaptive IRQ moderation
Calculate a score for each 1000 IRQs: - TX completions are worth 1 point - RX completions are worth 4 if merged using LRO or 2 otherwise Reduce moderation if the score is less than 10000, down to a minimum of 5 us. Increase moderation if the score is more than 20000, up to the specified maximum. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/sfc/efx.c46
-rw-r--r--drivers/net/sfc/efx.h2
-rw-r--r--drivers/net/sfc/ethtool.c19
-rw-r--r--drivers/net/sfc/falcon.c16
-rw-r--r--drivers/net/sfc/falcon.h2
-rw-r--r--drivers/net/sfc/net_driver.h9
6 files changed, 73 insertions, 21 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 8fa68d82c022..6eff9ca6c6c8 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -133,6 +133,16 @@ static int phy_flash_cfg;
133module_param(phy_flash_cfg, int, 0644); 133module_param(phy_flash_cfg, int, 0644);
134MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); 134MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
135 135
136static unsigned irq_adapt_low_thresh = 10000;
137module_param(irq_adapt_low_thresh, uint, 0644);
138MODULE_PARM_DESC(irq_adapt_low_thresh,
139 "Threshold score for reducing IRQ moderation");
140
141static unsigned irq_adapt_high_thresh = 20000;
142module_param(irq_adapt_high_thresh, uint, 0644);
143MODULE_PARM_DESC(irq_adapt_high_thresh,
144 "Threshold score for increasing IRQ moderation");
145
136/************************************************************************** 146/**************************************************************************
137 * 147 *
138 * Utility functions and prototypes 148 * Utility functions and prototypes
@@ -223,6 +233,35 @@ static int efx_poll(struct napi_struct *napi, int budget)
223 rx_packets = efx_process_channel(channel, budget); 233 rx_packets = efx_process_channel(channel, budget);
224 234
225 if (rx_packets < budget) { 235 if (rx_packets < budget) {
236 struct efx_nic *efx = channel->efx;
237
238 if (channel->used_flags & EFX_USED_BY_RX &&
239 efx->irq_rx_adaptive &&
240 unlikely(++channel->irq_count == 1000)) {
241 unsigned old_irq_moderation = channel->irq_moderation;
242
243 if (unlikely(channel->irq_mod_score <
244 irq_adapt_low_thresh)) {
245 channel->irq_moderation =
246 max_t(int,
247 channel->irq_moderation -
248 FALCON_IRQ_MOD_RESOLUTION,
249 FALCON_IRQ_MOD_RESOLUTION);
250 } else if (unlikely(channel->irq_mod_score >
251 irq_adapt_high_thresh)) {
252 channel->irq_moderation =
253 min(channel->irq_moderation +
254 FALCON_IRQ_MOD_RESOLUTION,
255 efx->irq_rx_moderation);
256 }
257
258 if (channel->irq_moderation != old_irq_moderation)
259 falcon_set_int_moderation(channel);
260
261 channel->irq_count = 0;
262 channel->irq_mod_score = 0;
263 }
264
226 /* There is no race here; although napi_disable() will 265 /* There is no race here; although napi_disable() will
227 * only wait for napi_complete(), this isn't a problem 266 * only wait for napi_complete(), this isn't a problem
228 * since efx_channel_processed() will have no effect if 267 * since efx_channel_processed() will have no effect if
@@ -991,7 +1030,7 @@ static int efx_probe_nic(struct efx_nic *efx)
991 efx_set_channels(efx); 1030 efx_set_channels(efx);
992 1031
993 /* Initialise the interrupt moderation settings */ 1032 /* Initialise the interrupt moderation settings */
994 efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec); 1033 efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true);
995 1034
996 return 0; 1035 return 0;
997} 1036}
@@ -1188,7 +1227,8 @@ void efx_flush_queues(struct efx_nic *efx)
1188 **************************************************************************/ 1227 **************************************************************************/
1189 1228
1190/* Set interrupt moderation parameters */ 1229/* Set interrupt moderation parameters */
1191void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs) 1230void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
1231 bool rx_adaptive)
1192{ 1232{
1193 struct efx_tx_queue *tx_queue; 1233 struct efx_tx_queue *tx_queue;
1194 struct efx_rx_queue *rx_queue; 1234 struct efx_rx_queue *rx_queue;
@@ -1198,6 +1238,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
1198 efx_for_each_tx_queue(tx_queue, efx) 1238 efx_for_each_tx_queue(tx_queue, efx)
1199 tx_queue->channel->irq_moderation = tx_usecs; 1239 tx_queue->channel->irq_moderation = tx_usecs;
1200 1240
1241 efx->irq_rx_adaptive = rx_adaptive;
1242 efx->irq_rx_moderation = rx_usecs;
1201 efx_for_each_rx_queue(rx_queue, efx) 1243 efx_for_each_rx_queue(rx_queue, efx)
1202 rx_queue->channel->irq_moderation = rx_usecs; 1244 rx_queue->channel->irq_moderation = rx_usecs;
1203} 1245}
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 8bde1d2a21db..da157aa74b83 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -52,7 +52,7 @@ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
52extern void efx_suspend(struct efx_nic *efx); 52extern void efx_suspend(struct efx_nic *efx);
53extern void efx_resume(struct efx_nic *efx); 53extern void efx_resume(struct efx_nic *efx);
54extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, 54extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
55 int rx_usecs); 55 int rx_usecs, bool rx_adaptive);
56extern int efx_request_power(struct efx_nic *efx, int mw, const char *name); 56extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
57extern void efx_hex_dump(const u8 *, unsigned int, const char *); 57extern void efx_hex_dump(const u8 *, unsigned int, const char *);
58 58
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 589d13292969..64309f4e8b19 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -604,7 +604,6 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
604{ 604{
605 struct efx_nic *efx = netdev_priv(net_dev); 605 struct efx_nic *efx = netdev_priv(net_dev);
606 struct efx_tx_queue *tx_queue; 606 struct efx_tx_queue *tx_queue;
607 struct efx_rx_queue *rx_queue;
608 struct efx_channel *channel; 607 struct efx_channel *channel;
609 608
610 memset(coalesce, 0, sizeof(*coalesce)); 609 memset(coalesce, 0, sizeof(*coalesce));
@@ -622,14 +621,8 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
622 } 621 }
623 } 622 }
624 623
625 /* Find lowest IRQ moderation across all used RX queues */ 624 coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
626 coalesce->rx_coalesce_usecs_irq = ~((u32) 0); 625 coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
627 efx_for_each_rx_queue(rx_queue, efx) {
628 channel = rx_queue->channel;
629 if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
630 coalesce->rx_coalesce_usecs_irq =
631 channel->irq_moderation;
632 }
633 626
634 return 0; 627 return 0;
635} 628}
@@ -643,10 +636,9 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
643 struct efx_nic *efx = netdev_priv(net_dev); 636 struct efx_nic *efx = netdev_priv(net_dev);
644 struct efx_channel *channel; 637 struct efx_channel *channel;
645 struct efx_tx_queue *tx_queue; 638 struct efx_tx_queue *tx_queue;
646 unsigned tx_usecs, rx_usecs; 639 unsigned tx_usecs, rx_usecs, adaptive;
647 640
648 if (coalesce->use_adaptive_rx_coalesce || 641 if (coalesce->use_adaptive_tx_coalesce)
649 coalesce->use_adaptive_tx_coalesce)
650 return -EOPNOTSUPP; 642 return -EOPNOTSUPP;
651 643
652 if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) { 644 if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
@@ -657,6 +649,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
657 649
658 rx_usecs = coalesce->rx_coalesce_usecs_irq; 650 rx_usecs = coalesce->rx_coalesce_usecs_irq;
659 tx_usecs = coalesce->tx_coalesce_usecs_irq; 651 tx_usecs = coalesce->tx_coalesce_usecs_irq;
652 adaptive = coalesce->use_adaptive_rx_coalesce;
660 653
661 /* If the channel is shared only allow RX parameters to be set */ 654 /* If the channel is shared only allow RX parameters to be set */
662 efx_for_each_tx_queue(tx_queue, efx) { 655 efx_for_each_tx_queue(tx_queue, efx) {
@@ -668,7 +661,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
668 } 661 }
669 } 662 }
670 663
671 efx_init_irq_moderation(efx, tx_usecs, rx_usecs); 664 efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
672 665
673 /* Reset channel to pick up new moderation value. Note that 666 /* Reset channel to pick up new moderation value. Note that
674 * this may change the value of the irq_moderation field 667 * this may change the value of the irq_moderation field
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index f42fc60d1df4..23a1b148d5b2 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -729,6 +729,9 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
729 tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR); 729 tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
730 tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL); 730 tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
731 tx_queue = &efx->tx_queue[tx_ev_q_label]; 731 tx_queue = &efx->tx_queue[tx_ev_q_label];
732 channel->irq_mod_score +=
733 (tx_ev_desc_ptr - tx_queue->read_count) &
734 efx->type->txd_ring_mask;
732 efx_xmit_done(tx_queue, tx_ev_desc_ptr); 735 efx_xmit_done(tx_queue, tx_ev_desc_ptr);
733 } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) { 736 } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
734 /* Rewrite the FIFO write pointer */ 737 /* Rewrite the FIFO write pointer */
@@ -898,6 +901,8 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
898 discard = true; 901 discard = true;
899 } 902 }
900 903
904 channel->irq_mod_score += 2;
905
901 /* Handle received packet */ 906 /* Handle received packet */
902 efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, 907 efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
903 checksummed, discard); 908 checksummed, discard);
@@ -1075,14 +1080,15 @@ void falcon_set_int_moderation(struct efx_channel *channel)
1075 * program is based at 0. So actual interrupt moderation 1080 * program is based at 0. So actual interrupt moderation
1076 * achieved is ((x + 1) * res). 1081 * achieved is ((x + 1) * res).
1077 */ 1082 */
1078 unsigned int res = 5; 1083 channel->irq_moderation -= (channel->irq_moderation %
1079 channel->irq_moderation -= (channel->irq_moderation % res); 1084 FALCON_IRQ_MOD_RESOLUTION);
1080 if (channel->irq_moderation < res) 1085 if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION)
1081 channel->irq_moderation = res; 1086 channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION;
1082 EFX_POPULATE_DWORD_2(timer_cmd, 1087 EFX_POPULATE_DWORD_2(timer_cmd,
1083 TIMER_MODE, TIMER_MODE_INT_HLDOFF, 1088 TIMER_MODE, TIMER_MODE_INT_HLDOFF,
1084 TIMER_VAL, 1089 TIMER_VAL,
1085 (channel->irq_moderation / res) - 1); 1090 channel->irq_moderation /
1091 FALCON_IRQ_MOD_RESOLUTION - 1);
1086 } else { 1092 } else {
1087 EFX_POPULATE_DWORD_2(timer_cmd, 1093 EFX_POPULATE_DWORD_2(timer_cmd,
1088 TIMER_MODE, TIMER_MODE_DIS, 1094 TIMER_MODE, TIMER_MODE_DIS,
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 7869c3d74383..77f2e0db7ca1 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -85,6 +85,8 @@ extern void falcon_set_int_moderation(struct efx_channel *channel);
85extern void falcon_disable_interrupts(struct efx_nic *efx); 85extern void falcon_disable_interrupts(struct efx_nic *efx);
86extern void falcon_fini_interrupt(struct efx_nic *efx); 86extern void falcon_fini_interrupt(struct efx_nic *efx);
87 87
88#define FALCON_IRQ_MOD_RESOLUTION 5
89
88/* Global Resources */ 90/* Global Resources */
89extern int falcon_probe_nic(struct efx_nic *efx); 91extern int falcon_probe_nic(struct efx_nic *efx);
90extern int falcon_probe_resources(struct efx_nic *efx); 92extern int falcon_probe_resources(struct efx_nic *efx);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index b81fc727dfff..e169e5dcd1e6 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -336,6 +336,8 @@ enum efx_rx_alloc_method {
336 * @eventq_read_ptr: Event queue read pointer 336 * @eventq_read_ptr: Event queue read pointer
337 * @last_eventq_read_ptr: Last event queue read pointer value. 337 * @last_eventq_read_ptr: Last event queue read pointer value.
338 * @eventq_magic: Event queue magic value for driver-generated test events 338 * @eventq_magic: Event queue magic value for driver-generated test events
339 * @irq_count: Number of IRQs since last adaptive moderation decision
340 * @irq_mod_score: IRQ moderation score
339 * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors 341 * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
340 * and diagnostic counters 342 * and diagnostic counters
341 * @rx_alloc_push_pages: RX allocation method currently in use for pushing 343 * @rx_alloc_push_pages: RX allocation method currently in use for pushing
@@ -364,6 +366,9 @@ struct efx_channel {
364 unsigned int last_eventq_read_ptr; 366 unsigned int last_eventq_read_ptr;
365 unsigned int eventq_magic; 367 unsigned int eventq_magic;
366 368
369 unsigned int irq_count;
370 unsigned int irq_mod_score;
371
367 int rx_alloc_level; 372 int rx_alloc_level;
368 int rx_alloc_push_pages; 373 int rx_alloc_push_pages;
369 374
@@ -703,6 +708,8 @@ union efx_multicast_hash {
703 * @membase: Memory BAR value 708 * @membase: Memory BAR value
704 * @biu_lock: BIU (bus interface unit) lock 709 * @biu_lock: BIU (bus interface unit) lock
705 * @interrupt_mode: Interrupt mode 710 * @interrupt_mode: Interrupt mode
711 * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
712 * @irq_rx_moderation: IRQ moderation time for RX event queues
706 * @i2c_adap: I2C adapter 713 * @i2c_adap: I2C adapter
707 * @board_info: Board-level information 714 * @board_info: Board-level information
708 * @state: Device state flag. Serialised by the rtnl_lock. 715 * @state: Device state flag. Serialised by the rtnl_lock.
@@ -784,6 +791,8 @@ struct efx_nic {
784 void __iomem *membase; 791 void __iomem *membase;
785 spinlock_t biu_lock; 792 spinlock_t biu_lock;
786 enum efx_int_mode interrupt_mode; 793 enum efx_int_mode interrupt_mode;
794 bool irq_rx_adaptive;
795 unsigned int irq_rx_moderation;
787 796
788 struct i2c_adapter i2c_adap; 797 struct i2c_adapter i2c_adap;
789 struct efx_board board_info; 798 struct efx_board board_info;