aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-09-05 03:43:04 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-16 16:50:36 -0400
commit9e393b3060ec4ed7e7c7c5de154e08e48c98f623 (patch)
tree94951da6c8fadeab0265aa825f6b95266a6ded60 /drivers/net/ethernet/sfc
parenta0c4faf5484b1fe38952d5b975f19e9f4b8f0f2b (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/sfc')
-rw-r--r--drivers/net/ethernet/sfc/efx.c20
-rw-r--r--drivers/net/ethernet/sfc/efx.h5
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c17
-rw-r--r--drivers/net/ethernet/sfc/falcon.c2
-rw-r--r--drivers/net/ethernet/sfc/nic.h3
-rw-r--r--drivers/net/ethernet/sfc/siena.c2
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 */
1569void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, 1570int 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
1588void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, 1602void 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 */
113extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); 113extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
114extern void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, 114extern 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);
116extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, 117extern 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);
204extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); 204extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id);
205extern void falcon_irq_ack_a1(struct efx_nic *efx); 205extern 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 */
210extern int efx_nic_flush_queues(struct efx_nic *efx); 211extern 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,