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 | |
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>
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 31 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 13 |
5 files changed, 40 insertions, 17 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 | /************************************************************************** |
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index fe21c7e349b6..0b7880b0b8fc 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c | |||
@@ -103,8 +103,6 @@ static void falcon_push_irq_moderation(struct efx_channel *channel) | |||
103 | efx_dword_t timer_cmd; | 103 | efx_dword_t timer_cmd; |
104 | struct efx_nic *efx = channel->efx; | 104 | struct efx_nic *efx = channel->efx; |
105 | 105 | ||
106 | BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_AB_TC_TIMER_VAL_WIDTH)); | ||
107 | |||
108 | /* Set timer register */ | 106 | /* Set timer register */ |
109 | if (channel->irq_moderation) { | 107 | if (channel->irq_moderation) { |
110 | EFX_POPULATE_DWORD_2(timer_cmd, | 108 | EFX_POPULATE_DWORD_2(timer_cmd, |
@@ -1471,6 +1469,8 @@ static int falcon_probe_nic(struct efx_nic *efx) | |||
1471 | goto fail5; | 1469 | goto fail5; |
1472 | } | 1470 | } |
1473 | 1471 | ||
1472 | efx->timer_quantum_ns = 4968; /* 621 cycles */ | ||
1473 | |||
1474 | /* Initialise I2C adapter */ | 1474 | /* Initialise I2C adapter */ |
1475 | board = falcon_board(efx); | 1475 | board = falcon_board(efx); |
1476 | board->i2c_adap.owner = THIS_MODULE; | 1476 | board->i2c_adap.owner = THIS_MODULE; |
@@ -1785,6 +1785,7 @@ const struct efx_nic_type falcon_a1_nic_type = { | |||
1785 | .rx_buffer_padding = 0x24, | 1785 | .rx_buffer_padding = 0x24, |
1786 | .max_interrupt_mode = EFX_INT_MODE_MSI, | 1786 | .max_interrupt_mode = EFX_INT_MODE_MSI, |
1787 | .phys_addr_channels = 4, | 1787 | .phys_addr_channels = 4, |
1788 | .timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH, | ||
1788 | .tx_dc_base = 0x130000, | 1789 | .tx_dc_base = 0x130000, |
1789 | .rx_dc_base = 0x100000, | 1790 | .rx_dc_base = 0x100000, |
1790 | .offload_features = NETIF_F_IP_CSUM, | 1791 | .offload_features = NETIF_F_IP_CSUM, |
@@ -1836,6 +1837,7 @@ const struct efx_nic_type falcon_b0_nic_type = { | |||
1836 | .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy | 1837 | .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy |
1837 | * interrupt handler only supports 32 | 1838 | * interrupt handler only supports 32 |
1838 | * channels */ | 1839 | * channels */ |
1840 | .timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH, | ||
1839 | .tx_dc_base = 0x130000, | 1841 | .tx_dc_base = 0x130000, |
1840 | .rx_dc_base = 0x100000, | 1842 | .rx_dc_base = 0x100000, |
1841 | .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, | 1843 | .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 4cbd997e378b..8ce4d068bba5 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -624,6 +624,7 @@ struct efx_filter_state; | |||
624 | * @membase_phys: Memory BAR value as physical address | 624 | * @membase_phys: Memory BAR value as physical address |
625 | * @membase: Memory BAR value | 625 | * @membase: Memory BAR value |
626 | * @interrupt_mode: Interrupt mode | 626 | * @interrupt_mode: Interrupt mode |
627 | * @timer_quantum_ns: Interrupt timer quantum, in nanoseconds | ||
627 | * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues | 628 | * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues |
628 | * @irq_rx_moderation: IRQ moderation time for RX event queues | 629 | * @irq_rx_moderation: IRQ moderation time for RX event queues |
629 | * @msg_enable: Log message enable flags | 630 | * @msg_enable: Log message enable flags |
@@ -706,6 +707,7 @@ struct efx_nic { | |||
706 | void __iomem *membase; | 707 | void __iomem *membase; |
707 | 708 | ||
708 | enum efx_int_mode interrupt_mode; | 709 | enum efx_int_mode interrupt_mode; |
710 | unsigned int timer_quantum_ns; | ||
709 | bool irq_rx_adaptive; | 711 | bool irq_rx_adaptive; |
710 | unsigned int irq_rx_moderation; | 712 | unsigned int irq_rx_moderation; |
711 | u32 msg_enable; | 713 | u32 msg_enable; |
@@ -845,6 +847,7 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) | |||
845 | * from &enum efx_init_mode. | 847 | * from &enum efx_init_mode. |
846 | * @phys_addr_channels: Number of channels with physically addressed | 848 | * @phys_addr_channels: Number of channels with physically addressed |
847 | * descriptors | 849 | * descriptors |
850 | * @timer_period_max: Maximum period of interrupt timer (in ticks) | ||
848 | * @tx_dc_base: Base address in SRAM of TX queue descriptor caches | 851 | * @tx_dc_base: Base address in SRAM of TX queue descriptor caches |
849 | * @rx_dc_base: Base address in SRAM of RX queue descriptor caches | 852 | * @rx_dc_base: Base address in SRAM of RX queue descriptor caches |
850 | * @offload_features: net_device feature flags for protocol offload | 853 | * @offload_features: net_device feature flags for protocol offload |
@@ -889,6 +892,7 @@ struct efx_nic_type { | |||
889 | unsigned int rx_buffer_padding; | 892 | unsigned int rx_buffer_padding; |
890 | unsigned int max_interrupt_mode; | 893 | unsigned int max_interrupt_mode; |
891 | unsigned int phys_addr_channels; | 894 | unsigned int phys_addr_channels; |
895 | unsigned int timer_period_max; | ||
892 | unsigned int tx_dc_base; | 896 | unsigned int tx_dc_base; |
893 | unsigned int rx_dc_base; | 897 | unsigned int rx_dc_base; |
894 | netdev_features_t offload_features; | 898 | netdev_features_t offload_features; |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index cfda6ded24fe..a3ccd0b9d78d 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -205,9 +205,6 @@ extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); | |||
205 | extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); | 205 | extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); |
206 | extern void falcon_irq_ack_a1(struct efx_nic *efx); | 206 | extern void falcon_irq_ack_a1(struct efx_nic *efx); |
207 | 207 | ||
208 | #define EFX_IRQ_MOD_RESOLUTION 5 | ||
209 | #define EFX_IRQ_MOD_MAX 0x1000 | ||
210 | |||
211 | /* Global Resources */ | 208 | /* Global Resources */ |
212 | extern int efx_nic_flush_queues(struct efx_nic *efx); | 209 | extern int efx_nic_flush_queues(struct efx_nic *efx); |
213 | extern void falcon_start_nic_stats(struct efx_nic *efx); | 210 | extern void falcon_start_nic_stats(struct efx_nic *efx); |
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 65cb5e4f4264..f05425842b31 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c | |||
@@ -35,8 +35,6 @@ static void siena_push_irq_moderation(struct efx_channel *channel) | |||
35 | { | 35 | { |
36 | efx_dword_t timer_cmd; | 36 | efx_dword_t timer_cmd; |
37 | 37 | ||
38 | BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_CZ_TC_TIMER_VAL_WIDTH)); | ||
39 | |||
40 | if (channel->irq_moderation) | 38 | if (channel->irq_moderation) |
41 | EFX_POPULATE_DWORD_2(timer_cmd, | 39 | EFX_POPULATE_DWORD_2(timer_cmd, |
42 | FRF_CZ_TC_TIMER_MODE, | 40 | FRF_CZ_TC_TIMER_MODE, |
@@ -216,7 +214,15 @@ static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) | |||
216 | 214 | ||
217 | static int siena_probe_nvconfig(struct efx_nic *efx) | 215 | static int siena_probe_nvconfig(struct efx_nic *efx) |
218 | { | 216 | { |
219 | return efx_mcdi_get_board_cfg(efx, efx->net_dev->perm_addr, NULL, NULL); | 217 | u32 caps = 0; |
218 | int rc; | ||
219 | |||
220 | rc = efx_mcdi_get_board_cfg(efx, efx->net_dev->perm_addr, NULL, &caps); | ||
221 | |||
222 | efx->timer_quantum_ns = | ||
223 | (caps & (1 << MC_CMD_CAPABILITIES_TURBO_ACTIVE_LBN)) ? | ||
224 | 3072 : 6144; /* 768 cycles */ | ||
225 | return rc; | ||
220 | } | 226 | } |
221 | 227 | ||
222 | static int siena_probe_nic(struct efx_nic *efx) | 228 | static int siena_probe_nic(struct efx_nic *efx) |
@@ -644,6 +650,7 @@ const struct efx_nic_type siena_a0_nic_type = { | |||
644 | .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy | 650 | .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy |
645 | * interrupt handler only supports 32 | 651 | * interrupt handler only supports 32 |
646 | * channels */ | 652 | * channels */ |
653 | .timer_period_max = 1 << FRF_CZ_TC_TIMER_VAL_WIDTH, | ||
647 | .tx_dc_base = 0x88000, | 654 | .tx_dc_base = 0x88000, |
648 | .rx_dc_base = 0x68000, | 655 | .rx_dc_base = 0x68000, |
649 | .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | 656 | .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |