sfc: Maintain interrupt moderation values in ticks, not microseconds
authorBen Hutchings <bhutchings@solarflare.com>
Fri, 23 Oct 2009 08:32:13 +0000 (08:32 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 24 Oct 2009 11:27:15 +0000 (04:27 -0700)
This simplifies the implementation a lot.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/sfc/efx.c
drivers/net/sfc/ethtool.c
drivers/net/sfc/falcon.c
drivers/net/sfc/net_driver.h

index 862e483..30951fb 100644 (file)
@@ -228,26 +228,20 @@ static int efx_poll(struct napi_struct *napi, int budget)
                if (channel->used_flags & EFX_USED_BY_RX &&
                    efx->irq_rx_adaptive &&
                    unlikely(++channel->irq_count == 1000)) {
-                       unsigned old_irq_moderation = channel->irq_moderation;
-
                        if (unlikely(channel->irq_mod_score <
                                     irq_adapt_low_thresh)) {
-                               channel->irq_moderation =
-                                       max_t(int,
-                                             channel->irq_moderation -
-                                             FALCON_IRQ_MOD_RESOLUTION,
-                                             FALCON_IRQ_MOD_RESOLUTION);
+                               if (channel->irq_moderation > 1) {
+                                       channel->irq_moderation -= 1;
+                                       falcon_set_int_moderation(channel);
+                               }
                        } else if (unlikely(channel->irq_mod_score >
                                            irq_adapt_high_thresh)) {
-                               channel->irq_moderation =
-                                       min(channel->irq_moderation +
-                                           FALCON_IRQ_MOD_RESOLUTION,
-                                           efx->irq_rx_moderation);
+                               if (channel->irq_moderation <
+                                   efx->irq_rx_moderation) {
+                                       channel->irq_moderation += 1;
+                                       falcon_set_int_moderation(channel);
+                               }
                        }
-
-                       if (channel->irq_moderation != old_irq_moderation)
-                               falcon_set_int_moderation(channel);
-
                        channel->irq_count = 0;
                        channel->irq_mod_score = 0;
                }
@@ -1220,22 +1214,33 @@ void efx_flush_queues(struct efx_nic *efx)
  *
  **************************************************************************/
 
+static unsigned irq_mod_ticks(int usecs, int resolution)
+{
+       if (usecs <= 0)
+               return 0; /* cannot receive interrupts ahead of time :-) */
+       if (usecs < resolution)
+               return 1; /* never round down to 0 */
+       return usecs / resolution;
+}
+
 /* Set interrupt moderation parameters */
 void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
                             bool rx_adaptive)
 {
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
+       unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION);
+       unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION);
 
        EFX_ASSERT_RESET_SERIALISED(efx);
 
        efx_for_each_tx_queue(tx_queue, efx)
-               tx_queue->channel->irq_moderation = tx_usecs;
+               tx_queue->channel->irq_moderation = tx_ticks;
 
        efx->irq_rx_adaptive = rx_adaptive;
-       efx->irq_rx_moderation = rx_usecs;
+       efx->irq_rx_moderation = rx_ticks;
        efx_for_each_rx_queue(rx_queue, efx)
-               rx_queue->channel->irq_moderation = rx_usecs;
+               rx_queue->channel->irq_moderation = rx_ticks;
 }
 
 /**************************************************************************
index 45018f2..a313b61 100644 (file)
@@ -618,6 +618,9 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
        coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
        coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
 
+       coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
+       coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
+
        return 0;
 }
 
@@ -656,11 +659,6 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
        }
 
        efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
-
-       /* Reset channel to pick up new moderation value.  Note that
-        * this may change the value of the irq_moderation field
-        * (e.g. to allow for hardware timer granularity).
-        */
        efx_for_each_channel(channel, efx)
                falcon_set_int_moderation(channel);
 
index 1582df7..e3c33fa 100644 (file)
@@ -1063,20 +1063,11 @@ void falcon_set_int_moderation(struct efx_channel *channel)
 
        /* Set timer register */
        if (channel->irq_moderation) {
-               /* Round to resolution supported by hardware.  The value we
-                * program is based at 0.  So actual interrupt moderation
-                * achieved is ((x + 1) * res).
-                */
-               channel->irq_moderation -= (channel->irq_moderation %
-                                           FALCON_IRQ_MOD_RESOLUTION);
-               if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION)
-                       channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION;
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     FRF_AB_TC_TIMER_MODE,
                                     FFE_BB_TIMER_MODE_INT_HLDOFF,
                                     FRF_AB_TC_TIMER_VAL,
-                                    channel->irq_moderation /
-                                    FALCON_IRQ_MOD_RESOLUTION - 1);
+                                    channel->irq_moderation - 1);
        } else {
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     FRF_AB_TC_TIMER_MODE,
index 25b7933..c8b6998 100644 (file)
@@ -327,7 +327,7 @@ enum efx_rx_alloc_method {
  * @used_flags: Channel is used by net driver
  * @enabled: Channel enabled indicator
  * @irq: IRQ number (MSI and MSI-X only)
- * @irq_moderation: IRQ moderation value (in us)
+ * @irq_moderation: IRQ moderation value (in hardware ticks)
  * @napi_dev: Net device used with NAPI
  * @napi_str: NAPI control structure
  * @reset_work: Scheduled reset work thread