aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/sfc/efx.c18
-rw-r--r--drivers/net/ethernet/sfc/efx.h2
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c67
3 files changed, 53 insertions, 34 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 097ed8b4a79a..e0157c03d313 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1585,6 +1585,24 @@ void efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
1585 } 1585 }
1586} 1586}
1587 1587
1588void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
1589 unsigned int *rx_usecs, bool *rx_adaptive)
1590{
1591 *rx_adaptive = efx->irq_rx_adaptive;
1592 *rx_usecs = efx->irq_rx_moderation * EFX_IRQ_MOD_RESOLUTION;
1593
1594 /* If channels are shared between RX and TX, so is IRQ
1595 * moderation. Otherwise, IRQ moderation is the same for all
1596 * TX channels and is not adaptive.
1597 */
1598 if (efx->tx_channel_offset == 0)
1599 *tx_usecs = *rx_usecs;
1600 else
1601 *tx_usecs =
1602 efx->channel[efx->tx_channel_offset]->irq_moderation *
1603 EFX_IRQ_MOD_RESOLUTION;
1604}
1605
1588/************************************************************************** 1606/**************************************************************************
1589 * 1607 *
1590 * Hardware monitor 1608 * Hardware monitor
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 8f5acae431b9..8ca68631fce5 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -113,6 +113,8 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
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 void 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);
116extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
117 unsigned int *rx_usecs, bool *rx_adaptive);
116 118
117/* Dummy PHY ops for PHY drivers */ 119/* Dummy PHY ops for PHY drivers */
118extern int efx_port_dummy_op_int(struct efx_nic *efx); 120extern int efx_port_dummy_op_int(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index dedaa2c97e3c..1cb6ed0a255c 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -586,40 +586,37 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev)
586 return mdio45_nway_restart(&efx->mdio); 586 return mdio45_nway_restart(&efx->mdio);
587} 587}
588 588
589/*
590 * Each channel has a single IRQ and moderation timer, started by any
591 * completion (or other event). Unless the module parameter
592 * separate_tx_channels is set, IRQs and moderation are therefore
593 * shared between RX and TX completions. In this case, when RX IRQ
594 * moderation is explicitly changed then TX IRQ moderation is
595 * automatically changed too, but otherwise we fail if the two values
596 * are requested to be different.
597 *
598 * We implement adaptive IRQ moderation, but use a different algorithm
599 * from that assumed in the definition of struct ethtool_coalesce.
600 * Therefore we do not use any of the adaptive moderation parameters
601 * in it.
602 */
603
589static int efx_ethtool_get_coalesce(struct net_device *net_dev, 604static int efx_ethtool_get_coalesce(struct net_device *net_dev,
590 struct ethtool_coalesce *coalesce) 605 struct ethtool_coalesce *coalesce)
591{ 606{
592 struct efx_nic *efx = netdev_priv(net_dev); 607 struct efx_nic *efx = netdev_priv(net_dev);
593 struct efx_channel *channel; 608 unsigned int tx_usecs, rx_usecs;
594 609 bool rx_adaptive;
595 memset(coalesce, 0, sizeof(*coalesce));
596
597 /* Find lowest IRQ moderation across all used TX queues */
598 coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
599 efx_for_each_channel(channel, efx) {
600 if (!efx_channel_has_tx_queues(channel))
601 continue;
602 if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
603 if (channel->channel < efx->n_rx_channels)
604 coalesce->tx_coalesce_usecs_irq =
605 channel->irq_moderation;
606 else
607 coalesce->tx_coalesce_usecs_irq = 0;
608 }
609 }
610 610
611 coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; 611 efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);
612 coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
613 612
614 coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; 613 coalesce->tx_coalesce_usecs_irq = tx_usecs;
615 coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; 614 coalesce->rx_coalesce_usecs_irq = rx_usecs;
615 coalesce->use_adaptive_rx_coalesce = rx_adaptive;
616 616
617 return 0; 617 return 0;
618} 618}
619 619
620/* Set coalescing parameters
621 * The difficulties occur for shared channels
622 */
623static int efx_ethtool_set_coalesce(struct net_device *net_dev, 620static int efx_ethtool_set_coalesce(struct net_device *net_dev,
624 struct ethtool_coalesce *coalesce) 621 struct ethtool_coalesce *coalesce)
625{ 622{
@@ -637,20 +634,22 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
637 return -EINVAL; 634 return -EINVAL;
638 } 635 }
639 636
637 efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);
638
640 rx_usecs = coalesce->rx_coalesce_usecs_irq; 639 rx_usecs = coalesce->rx_coalesce_usecs_irq;
641 tx_usecs = coalesce->tx_coalesce_usecs_irq;
642 adaptive = coalesce->use_adaptive_rx_coalesce; 640 adaptive = coalesce->use_adaptive_rx_coalesce;
643 641
644 /* If the channel is shared only allow RX parameters to be set */ 642 /* If channels are shared, TX IRQ moderation can be quietly
645 efx_for_each_channel(channel, efx) { 643 * overridden unless it is changed from its old value.
646 if (efx_channel_has_rx_queue(channel) && 644 */
647 efx_channel_has_tx_queues(channel) && 645 if (efx->tx_channel_offset == 0 &&
648 tx_usecs) { 646 coalesce->tx_coalesce_usecs_irq != tx_usecs &&
649 netif_err(efx, drv, efx->net_dev, "Channel is shared. " 647 coalesce->tx_coalesce_usecs_irq != rx_usecs) {
650 "Only RX coalescing may be set\n"); 648 netif_err(efx, drv, efx->net_dev, "Channels are shared. "
651 return -EINVAL; 649 "RX and TX IRQ moderation must be equal\n");
652 } 650 return -EINVAL;
653 } 651 }
652 tx_usecs = coalesce->tx_coalesce_usecs_irq;
654 653
655 efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); 654 efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
656 efx_for_each_channel(channel, efx) 655 efx_for_each_channel(channel, efx)