diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2011-09-05 03:43:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-09-16 16:50:36 -0400 |
commit | 9e393b3060ec4ed7e7c7c5de154e08e48c98f623 (patch) | |
tree | 94951da6c8fadeab0265aa825f6b95266a6ded60 /drivers/net/ethernet | |
parent | a0c4faf5484b1fe38952d5b975f19e9f4b8f0f2b (diff) |
sfc: Validate IRQ moderation parameters in efx_init_irq_moderation()
Add a range check, and move the check that RX and TX are consistent
from efx_ethtool_set_coalesce().
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 2 |
6 files changed, 34 insertions, 15 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index e0157c03d313..76dcadfaaa43 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -1357,7 +1357,8 @@ static int efx_probe_nic(struct efx_nic *efx) | |||
1357 | netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); | 1357 | netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); |
1358 | 1358 | ||
1359 | /* Initialise the interrupt moderation settings */ | 1359 | /* Initialise the interrupt moderation settings */ |
1360 | efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true); | 1360 | efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true, |
1361 | true); | ||
1361 | 1362 | ||
1362 | return 0; | 1363 | return 0; |
1363 | 1364 | ||
@@ -1566,8 +1567,9 @@ static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int resolution) | |||
1566 | } | 1567 | } |
1567 | 1568 | ||
1568 | /* Set interrupt moderation parameters */ | 1569 | /* Set interrupt moderation parameters */ |
1569 | void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | 1570 | int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, |
1570 | unsigned int rx_usecs, bool rx_adaptive) | 1571 | unsigned int rx_usecs, bool rx_adaptive, |
1572 | bool rx_may_override_tx) | ||
1571 | { | 1573 | { |
1572 | struct efx_channel *channel; | 1574 | struct efx_channel *channel; |
1573 | unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); | 1575 | unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); |
@@ -1575,6 +1577,16 @@ void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | |||
1575 | 1577 | ||
1576 | EFX_ASSERT_RESET_SERIALISED(efx); | 1578 | EFX_ASSERT_RESET_SERIALISED(efx); |
1577 | 1579 | ||
1580 | if (tx_ticks > EFX_IRQ_MOD_MAX || rx_ticks > EFX_IRQ_MOD_MAX) | ||
1581 | return -EINVAL; | ||
1582 | |||
1583 | if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 && | ||
1584 | !rx_may_override_tx) { | ||
1585 | netif_err(efx, drv, efx->net_dev, "Channels are shared. " | ||
1586 | "RX and TX IRQ moderation must be equal\n"); | ||
1587 | return -EINVAL; | ||
1588 | } | ||
1589 | |||
1578 | efx->irq_rx_adaptive = rx_adaptive; | 1590 | efx->irq_rx_adaptive = rx_adaptive; |
1579 | efx->irq_rx_moderation = rx_ticks; | 1591 | efx->irq_rx_moderation = rx_ticks; |
1580 | efx_for_each_channel(channel, efx) { | 1592 | efx_for_each_channel(channel, efx) { |
@@ -1583,6 +1595,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | |||
1583 | else if (efx_channel_has_tx_queues(channel)) | 1595 | else if (efx_channel_has_tx_queues(channel)) |
1584 | channel->irq_moderation = tx_ticks; | 1596 | channel->irq_moderation = tx_ticks; |
1585 | } | 1597 | } |
1598 | |||
1599 | return 0; | ||
1586 | } | 1600 | } |
1587 | 1601 | ||
1588 | void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, | 1602 | void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, |
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 8ca68631fce5..442f4d0c247d 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h | |||
@@ -111,8 +111,9 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); | |||
111 | 111 | ||
112 | /* Global */ | 112 | /* Global */ |
113 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); | 113 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); |
114 | extern void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, | 114 | extern int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, |
115 | unsigned int rx_usecs, bool rx_adaptive); | 115 | unsigned int rx_usecs, bool rx_adaptive, |
116 | bool rx_may_override_tx); | ||
116 | extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, | 117 | extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, |
117 | unsigned int *rx_usecs, bool *rx_adaptive); | 118 | unsigned int *rx_usecs, bool *rx_adaptive); |
118 | 119 | ||
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 1cb6ed0a255c..98b363bb4a75 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c | |||
@@ -623,7 +623,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, | |||
623 | struct efx_nic *efx = netdev_priv(net_dev); | 623 | struct efx_nic *efx = netdev_priv(net_dev); |
624 | struct efx_channel *channel; | 624 | struct efx_channel *channel; |
625 | unsigned int tx_usecs, rx_usecs; | 625 | unsigned int tx_usecs, rx_usecs; |
626 | bool adaptive; | 626 | bool adaptive, rx_may_override_tx; |
627 | int rc; | ||
627 | 628 | ||
628 | if (coalesce->use_adaptive_tx_coalesce) | 629 | if (coalesce->use_adaptive_tx_coalesce) |
629 | return -EINVAL; | 630 | return -EINVAL; |
@@ -642,16 +643,14 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, | |||
642 | /* If channels are shared, TX IRQ moderation can be quietly | 643 | /* If channels are shared, TX IRQ moderation can be quietly |
643 | * overridden unless it is changed from its old value. | 644 | * overridden unless it is changed from its old value. |
644 | */ | 645 | */ |
645 | if (efx->tx_channel_offset == 0 && | 646 | rx_may_override_tx = coalesce->tx_coalesce_usecs_irq == tx_usecs; |
646 | coalesce->tx_coalesce_usecs_irq != tx_usecs && | ||
647 | coalesce->tx_coalesce_usecs_irq != rx_usecs) { | ||
648 | netif_err(efx, drv, efx->net_dev, "Channels are shared. " | ||
649 | "RX and TX IRQ moderation must be equal\n"); | ||
650 | return -EINVAL; | ||
651 | } | ||
652 | tx_usecs = coalesce->tx_coalesce_usecs_irq; | 647 | tx_usecs = coalesce->tx_coalesce_usecs_irq; |
653 | 648 | ||
654 | efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); | 649 | rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive, |
650 | rx_may_override_tx); | ||
651 | if (rc != 0) | ||
652 | return rc; | ||
653 | |||
655 | efx_for_each_channel(channel, efx) | 654 | efx_for_each_channel(channel, efx) |
656 | efx->type->push_irq_moderation(channel); | 655 | efx->type->push_irq_moderation(channel); |
657 | 656 | ||
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 94bf4aaf984d..4dd1748a19c6 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c | |||
@@ -104,6 +104,8 @@ static void falcon_push_irq_moderation(struct efx_channel *channel) | |||
104 | efx_dword_t timer_cmd; | 104 | efx_dword_t timer_cmd; |
105 | struct efx_nic *efx = channel->efx; | 105 | struct efx_nic *efx = channel->efx; |
106 | 106 | ||
107 | BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_AB_TC_TIMER_VAL_WIDTH)); | ||
108 | |||
107 | /* Set timer register */ | 109 | /* Set timer register */ |
108 | if (channel->irq_moderation) { | 110 | if (channel->irq_moderation) { |
109 | EFX_POPULATE_DWORD_2(timer_cmd, | 111 | EFX_POPULATE_DWORD_2(timer_cmd, |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 4bd1f2839dfe..b5b288628c6b 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -204,7 +204,8 @@ extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); | |||
204 | extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); | 204 | extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); |
205 | extern void falcon_irq_ack_a1(struct efx_nic *efx); | 205 | extern void falcon_irq_ack_a1(struct efx_nic *efx); |
206 | 206 | ||
207 | #define EFX_IRQ_MOD_RESOLUTION 5 | 207 | #define EFX_IRQ_MOD_RESOLUTION 5 |
208 | #define EFX_IRQ_MOD_MAX 0x1000 | ||
208 | 209 | ||
209 | /* Global Resources */ | 210 | /* Global Resources */ |
210 | extern int efx_nic_flush_queues(struct efx_nic *efx); | 211 | extern int efx_nic_flush_queues(struct efx_nic *efx); |
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 5735e84c69de..4fdd148747b2 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c | |||
@@ -36,6 +36,8 @@ static void siena_push_irq_moderation(struct efx_channel *channel) | |||
36 | { | 36 | { |
37 | efx_dword_t timer_cmd; | 37 | efx_dword_t timer_cmd; |
38 | 38 | ||
39 | BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_CZ_TC_TIMER_VAL_WIDTH)); | ||
40 | |||
39 | if (channel->irq_moderation) | 41 | if (channel->irq_moderation) |
40 | EFX_POPULATE_DWORD_2(timer_cmd, | 42 | EFX_POPULATE_DWORD_2(timer_cmd, |
41 | FRF_CZ_TC_TIMER_MODE, | 43 | FRF_CZ_TC_TIMER_MODE, |