diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2011-12-08 14:51:47 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-01-26 19:10:50 -0500 |
commit | cc180b69c009ec52f67a56d96b9073b9f774b323 (patch) | |
tree | 2d20225099a9a08d3471aeb3cd8ce4295417e5e6 /drivers/net/ethernet/sfc/efx.c | |
parent | 6aa9c7f625e8ce07060467051b68fc068118ee64 (diff) |
sfc: Correct interrupt timer quantum for Siena (normal and turbo mode)
We currently assume that the timer quantum for Siena is 5 us, the same
as for Falcon. This is not correct; timer ticks are generated on a
rota which takes a minimum of 768 cycles (each event delivery or other
timer change will delay it by 3 cycles). The timer quantum should be
6.144 or 3.072 us depending on whether turbo mode is active.
Replace EFX_IRQ_MOD_RESOLUTION with a timer_quantum_ns field in struct
efx_nic, initialised by the efx_nic_type::probe function.
While we're at it, replace EFX_IRQ_MOD_MAX with a timer_period_max
field in struct efx_nic_type.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/efx.c')
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index de162474c3c5..9d4ab5e5e1fa 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -1513,13 +1513,13 @@ static void efx_remove_all(struct efx_nic *efx) | |||
1513 | * | 1513 | * |
1514 | **************************************************************************/ | 1514 | **************************************************************************/ |
1515 | 1515 | ||
1516 | static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int resolution) | 1516 | static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int quantum_ns) |
1517 | { | 1517 | { |
1518 | if (usecs == 0) | 1518 | if (usecs == 0) |
1519 | return 0; | 1519 | return 0; |
1520 | if (usecs < resolution) | 1520 | if (usecs * 1000 < quantum_ns) |
1521 | return 1; /* never round down to 0 */ | 1521 | return 1; /* never round down to 0 */ |
1522 | return usecs / resolution; | 1522 | return usecs * 1000 / quantum_ns; |
1523 | } | 1523 | } |
1524 | 1524 | ||
1525 | /* Set interrupt moderation parameters */ | 1525 | /* Set interrupt moderation parameters */ |
@@ -1528,14 +1528,20 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | |||
1528 | bool rx_may_override_tx) | 1528 | bool rx_may_override_tx) |
1529 | { | 1529 | { |
1530 | struct efx_channel *channel; | 1530 | struct efx_channel *channel; |
1531 | unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); | 1531 | unsigned int irq_mod_max = DIV_ROUND_UP(efx->type->timer_period_max * |
1532 | unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); | 1532 | efx->timer_quantum_ns, |
1533 | 1000); | ||
1534 | unsigned int tx_ticks; | ||
1535 | unsigned int rx_ticks; | ||
1533 | 1536 | ||
1534 | EFX_ASSERT_RESET_SERIALISED(efx); | 1537 | EFX_ASSERT_RESET_SERIALISED(efx); |
1535 | 1538 | ||
1536 | if (tx_ticks > EFX_IRQ_MOD_MAX || rx_ticks > EFX_IRQ_MOD_MAX) | 1539 | if (tx_usecs > irq_mod_max || rx_usecs > irq_mod_max) |
1537 | return -EINVAL; | 1540 | return -EINVAL; |
1538 | 1541 | ||
1542 | tx_ticks = irq_mod_ticks(tx_usecs, efx->timer_quantum_ns); | ||
1543 | rx_ticks = irq_mod_ticks(rx_usecs, efx->timer_quantum_ns); | ||
1544 | |||
1539 | if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 && | 1545 | if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 && |
1540 | !rx_may_override_tx) { | 1546 | !rx_may_override_tx) { |
1541 | netif_err(efx, drv, efx->net_dev, "Channels are shared. " | 1547 | netif_err(efx, drv, efx->net_dev, "Channels are shared. " |
@@ -1558,8 +1564,14 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | |||
1558 | void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, | 1564 | void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, |
1559 | unsigned int *rx_usecs, bool *rx_adaptive) | 1565 | unsigned int *rx_usecs, bool *rx_adaptive) |
1560 | { | 1566 | { |
1567 | /* We must round up when converting ticks to microseconds | ||
1568 | * because we round down when converting the other way. | ||
1569 | */ | ||
1570 | |||
1561 | *rx_adaptive = efx->irq_rx_adaptive; | 1571 | *rx_adaptive = efx->irq_rx_adaptive; |
1562 | *rx_usecs = efx->irq_rx_moderation * EFX_IRQ_MOD_RESOLUTION; | 1572 | *rx_usecs = DIV_ROUND_UP(efx->irq_rx_moderation * |
1573 | efx->timer_quantum_ns, | ||
1574 | 1000); | ||
1563 | 1575 | ||
1564 | /* If channels are shared between RX and TX, so is IRQ | 1576 | /* If channels are shared between RX and TX, so is IRQ |
1565 | * moderation. Otherwise, IRQ moderation is the same for all | 1577 | * moderation. Otherwise, IRQ moderation is the same for all |
@@ -1568,9 +1580,10 @@ void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, | |||
1568 | if (efx->tx_channel_offset == 0) | 1580 | if (efx->tx_channel_offset == 0) |
1569 | *tx_usecs = *rx_usecs; | 1581 | *tx_usecs = *rx_usecs; |
1570 | else | 1582 | else |
1571 | *tx_usecs = | 1583 | *tx_usecs = DIV_ROUND_UP( |
1572 | efx->channel[efx->tx_channel_offset]->irq_moderation * | 1584 | efx->channel[efx->tx_channel_offset]->irq_moderation * |
1573 | EFX_IRQ_MOD_RESOLUTION; | 1585 | efx->timer_quantum_ns, |
1586 | 1000); | ||
1574 | } | 1587 | } |
1575 | 1588 | ||
1576 | /************************************************************************** | 1589 | /************************************************************************** |