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/falcon.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/falcon.c')
-rw-r--r-- | drivers/net/sfc/falcon.c | 16 |
1 files changed, 11 insertions, 5 deletions
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, |