diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-03-20 09:30:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-21 22:06:58 -0400 |
commit | 6fb70fd1b57707a5c7b9fb167b7790b2cba13f04 (patch) | |
tree | 311192bd4de07e1da571f1a6ac6a3ad123ab3f50 /drivers/net/sfc/efx.c | |
parent | 85451a951b9511605475fadcc0a8d3aeccefded8 (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/sfc/efx.c')
-rw-r--r-- | drivers/net/sfc/efx.c | 46 |
1 files changed, 44 insertions, 2 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; | |||
133 | module_param(phy_flash_cfg, int, 0644); | 133 | module_param(phy_flash_cfg, int, 0644); |
134 | MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); | 134 | MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); |
135 | 135 | ||
136 | static unsigned irq_adapt_low_thresh = 10000; | ||
137 | module_param(irq_adapt_low_thresh, uint, 0644); | ||
138 | MODULE_PARM_DESC(irq_adapt_low_thresh, | ||
139 | "Threshold score for reducing IRQ moderation"); | ||
140 | |||
141 | static unsigned irq_adapt_high_thresh = 20000; | ||
142 | module_param(irq_adapt_high_thresh, uint, 0644); | ||
143 | MODULE_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 */ |
1191 | void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs) | 1230 | void 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 | } |