Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b82ee71a authored by Igor Russkikh's avatar Igor Russkikh Committed by David S. Miller
Browse files

net: aquantia: Enable coalescing management via ethtool interface



Aquantia NIC allows both TX and RX interrupt throttle rate (ITR)
management, but this was used in a very limited way via predefined
values. This patch allows to setup ITR default values via module
command line arguments and via standard ethtool coalescing settings.

Signed-off-by: default avatarPavel Belous <pavel.belous@aquantia.com>
Signed-off-by: default avatarIgor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6849540a
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -22,8 +22,12 @@

#define AQ_CFG_FORCE_LEGACY_INT 0U

#define AQ_CFG_IS_INTERRUPT_MODERATION_DEF   1U
#define AQ_CFG_INTERRUPT_MODERATION_RATE_DEF 0xFFFFU
#define AQ_CFG_INTERRUPT_MODERATION_OFF		0
#define AQ_CFG_INTERRUPT_MODERATION_ON		1
#define AQ_CFG_INTERRUPT_MODERATION_AUTO	0xFFFFU

#define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2)

#define AQ_CFG_IRQ_MASK                      0x1FFU

#define AQ_CFG_VECS_MAX   8U
+65 −0
Original line number Diff line number Diff line
@@ -221,6 +221,69 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev,
	return err;
}

int aq_ethtool_get_coalesce(struct net_device *ndev,
			    struct ethtool_coalesce *coal)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);

	if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON ||
	    cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) {
		coal->rx_coalesce_usecs = cfg->rx_itr;
		coal->tx_coalesce_usecs = cfg->tx_itr;
		coal->rx_max_coalesced_frames = 0;
		coal->tx_max_coalesced_frames = 0;
	} else {
		coal->rx_coalesce_usecs = 0;
		coal->tx_coalesce_usecs = 0;
		coal->rx_max_coalesced_frames = 1;
		coal->tx_max_coalesced_frames = 1;
	}
	return 0;
}

int aq_ethtool_set_coalesce(struct net_device *ndev,
			    struct ethtool_coalesce *coal)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);

	/* This is not yet supported
	 */
	if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce)
		return -EOPNOTSUPP;

	/* Atlantic only supports timing based coalescing
	 */
	if (coal->rx_max_coalesced_frames > 1 ||
	    coal->rx_coalesce_usecs_irq ||
	    coal->rx_max_coalesced_frames_irq)
		return -EOPNOTSUPP;

	if (coal->tx_max_coalesced_frames > 1 ||
	    coal->tx_coalesce_usecs_irq ||
	    coal->tx_max_coalesced_frames_irq)
		return -EOPNOTSUPP;

	/* We do not support frame counting. Check this
	 */
	if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs))
		return -EOPNOTSUPP;
	if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs))
		return -EOPNOTSUPP;

	if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX ||
	    coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX)
		return -EINVAL;

	cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON;

	cfg->rx_itr = coal->rx_coalesce_usecs;
	cfg->tx_itr = coal->tx_coalesce_usecs;

	return aq_nic_update_interrupt_moderation_settings(aq_nic);
}

const struct ethtool_ops aq_ethtool_ops = {
	.get_link            = aq_ethtool_get_link,
	.get_regs_len        = aq_ethtool_get_regs_len,
@@ -235,4 +298,6 @@ const struct ethtool_ops aq_ethtool_ops = {
	.get_ethtool_stats   = aq_ethtool_stats,
	.get_link_ksettings  = aq_ethtool_get_link_ksettings,
	.set_link_ksettings  = aq_ethtool_set_link_ksettings,
	.get_coalesce	     = aq_ethtool_get_coalesce,
	.set_coalesce	     = aq_ethtool_set_coalesce,
};
+1 −2
Original line number Diff line number Diff line
@@ -151,8 +151,7 @@ struct aq_hw_ops {
				     [ETH_ALEN],
				     u32 count);

	int (*hw_interrupt_moderation_set)(struct aq_hw_s *self,
					   bool itr_enabled);
	int (*hw_interrupt_moderation_set)(struct aq_hw_s *self);

	int (*hw_rss_set)(struct aq_hw_s *self,
			  struct aq_rss_parameters *rss_params);
+26 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "aq_pci_func.h"
#include "aq_nic_internal.h"

#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/timer.h>
@@ -24,6 +25,18 @@
#include <linux/tcp.h>
#include <net/ip.h>

static unsigned int aq_itr = AQ_CFG_INTERRUPT_MODERATION_AUTO;
module_param_named(aq_itr, aq_itr, uint, 0644);
MODULE_PARM_DESC(aq_itr, "Interrupt throttling mode");

static unsigned int aq_itr_tx;
module_param_named(aq_itr_tx, aq_itr_tx, uint, 0644);
MODULE_PARM_DESC(aq_itr_tx, "TX interrupt throttle rate");

static unsigned int aq_itr_rx;
module_param_named(aq_itr_rx, aq_itr_rx, uint, 0644);
MODULE_PARM_DESC(aq_itr_rx, "RX interrupt throttle rate");

static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues)
{
	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
@@ -61,9 +74,9 @@ static void aq_nic_cfg_init_defaults(struct aq_nic_s *self)

	cfg->is_polling = AQ_CFG_IS_POLLING_DEF;

	cfg->is_interrupt_moderation = AQ_CFG_IS_INTERRUPT_MODERATION_DEF;
	cfg->itr = cfg->is_interrupt_moderation ?
		AQ_CFG_INTERRUPT_MODERATION_RATE_DEF : 0U;
	cfg->itr = aq_itr;
	cfg->tx_itr = aq_itr_tx;
	cfg->rx_itr = aq_itr_rx;

	cfg->is_rss = AQ_CFG_IS_RSS_DEF;
	cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF;
@@ -126,10 +139,12 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
	if (err)
		return err;

	if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps)
	if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) {
		pr_info("%s: link change old %d new %d\n",
			AQ_CFG_DRV_NAME, self->link_status.mbps,
			self->aq_hw->aq_link_status.mbps);
		aq_nic_update_interrupt_moderation_settings(self);
	}

	self->link_status = self->aq_hw->aq_link_status;
	if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) {
@@ -164,9 +179,6 @@ static void aq_nic_service_timer_cb(unsigned long param)
	if (err)
		goto err_exit;

	self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
		    self->aq_nic_cfg.is_interrupt_moderation);

	if (self->aq_hw_ops.hw_update_stats)
		self->aq_hw_ops.hw_update_stats(self->aq_hw);

@@ -425,9 +437,8 @@ int aq_nic_start(struct aq_nic_s *self)
	if (err < 0)
		goto err_exit;

	err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
			    self->aq_nic_cfg.is_interrupt_moderation);
	if (err < 0)
	err = aq_nic_update_interrupt_moderation_settings(self);
	if (err)
		goto err_exit;
	setup_timer(&self->service_timer, &aq_nic_service_timer_cb,
		    (unsigned long)self);
@@ -649,6 +660,11 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)
	return err;
}

int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self)
{
	return self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw);
}

int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
{
	int err = 0;
+3 −1
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ struct aq_nic_cfg_s {
	u32 vecs;		/* vecs==allocated irqs */
	u32 irq_type;
	u32 itr;
	u16 rx_itr;
	u16 tx_itr;
	u32 num_rss_queues;
	u32 mtu;
	u32 ucp_0x364;
@@ -49,7 +51,6 @@ struct aq_nic_cfg_s {
	u16 is_mc_list_enabled;
	u16 mc_list_count;
	bool is_autoneg;
	bool is_interrupt_moderation;
	bool is_polling;
	bool is_rss;
	bool is_lro;
@@ -104,5 +105,6 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);

#endif /* AQ_NIC_H */
Loading