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

Commit 44a4c469 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'aquantia-various-ethtool-ops-implementation'



Igor Russkikh says:

====================
net: aquantia: various ethtool ops implementation

In this patchset Anton Mikaev and I added some useful ethtool operations:
- ring size changes
- link renegotioation
- flow control management

The patch also improves init/deinit sequence.

V3 changes:
- After review and analysis it is clear that rtnl lock (which is
  captured by default on ethtool ops) is enough to secure possible
  overlapping of dev open/close. Thus, just dropping internal mutex.

V2 changes:
- using mutex to secure simultaneous dev close/open
- using state var to store/restore dev state
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c18a9c09 1d1c2122
Loading
Loading
Loading
Loading
+117 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include "aq_ethtool.h"
#include "aq_nic.h"
#include "aq_vec.h"

static void aq_ethtool_get_regs(struct net_device *ndev,
				struct ethtool_regs *regs, void *p)
@@ -284,6 +285,117 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
	return aq_nic_update_interrupt_moderation_settings(aq_nic);
}

static int aq_ethtool_nway_reset(struct net_device *ndev)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);

	if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
		return -EOPNOTSUPP;

	if (netif_running(ndev))
		return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);

	return 0;
}

static void aq_ethtool_get_pauseparam(struct net_device *ndev,
				      struct ethtool_pauseparam *pause)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);

	pause->autoneg = 0;

	if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
		pause->rx_pause = 1;
	if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
		pause->tx_pause = 1;
}

static int aq_ethtool_set_pauseparam(struct net_device *ndev,
				     struct ethtool_pauseparam *pause)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	int err = 0;

	if (!aq_nic->aq_fw_ops->set_flow_control)
		return -EOPNOTSUPP;

	if (pause->autoneg == AUTONEG_ENABLE)
		return -EOPNOTSUPP;

	if (pause->rx_pause)
		aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
	else
		aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;

	if (pause->tx_pause)
		aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
	else
		aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;

	err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);

	return err;
}

static void aq_get_ringparam(struct net_device *ndev,
			     struct ethtool_ringparam *ring)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);

	ring->rx_pending = aq_nic_cfg->rxds;
	ring->tx_pending = aq_nic_cfg->txds;

	ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
	ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
}

static int aq_set_ringparam(struct net_device *ndev,
			    struct ethtool_ringparam *ring)
{
	int err = 0;
	bool ndev_running = false;
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
	const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;

	if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
		err = -EOPNOTSUPP;
		goto err_exit;
	}

	if (netif_running(ndev)) {
		ndev_running = true;
		dev_close(ndev);
	}

	aq_nic_free_vectors(aq_nic);

	aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
	aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
	aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);

	aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
	aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
	aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);

	for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
	     aq_nic->aq_vecs++) {
		aq_nic->aq_vec[aq_nic->aq_vecs] =
		    aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
		if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
			err = -ENOMEM;
			goto err_exit;
		}
	}
	if (ndev_running)
		err = dev_open(ndev);

err_exit:
	return err;
}

const struct ethtool_ops aq_ethtool_ops = {
	.get_link            = aq_ethtool_get_link,
	.get_regs_len        = aq_ethtool_get_regs_len,
@@ -291,6 +403,11 @@ const struct ethtool_ops aq_ethtool_ops = {
	.get_drvinfo         = aq_ethtool_get_drvinfo,
	.get_strings         = aq_ethtool_get_strings,
	.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
	.nway_reset          = aq_ethtool_nway_reset,
	.get_ringparam       = aq_get_ringparam,
	.set_ringparam       = aq_set_ringparam,
	.get_pauseparam      = aq_ethtool_get_pauseparam,
	.set_pauseparam      = aq_ethtool_set_pauseparam,
	.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
	.get_rxfh            = aq_ethtool_get_rss,
	.get_rxnfc           = aq_ethtool_get_rxnfc,
+15 −5
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ struct aq_hw_caps_s {
	u64 link_speed_msk;
	unsigned int hw_priv_flags;
	u32 media_type;
	u32 rxds;
	u32 txds;
	u32 rxds_max;
	u32 txds_max;
	u32 rxds_min;
	u32 txds_min;
	u32 txhwb_alignment;
	u32 irq_mask;
	u32 vecs;
@@ -98,6 +100,9 @@ struct aq_stats_s {
#define AQ_HW_MEDIA_TYPE_TP    1U
#define AQ_HW_MEDIA_TYPE_FIBRE 2U

#define AQ_HW_TXD_MULTIPLE 8U
#define AQ_HW_RXD_MULTIPLE 8U

struct aq_hw_s {
	atomic_t flags;
	u8 rbl_enabled:1;
@@ -197,25 +202,30 @@ struct aq_hw_ops {

	int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);

	int (*hw_deinit)(struct aq_hw_s *self);

	int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
};

struct aq_fw_ops {
	int (*init)(struct aq_hw_s *self);

	int (*deinit)(struct aq_hw_s *self);

	int (*reset)(struct aq_hw_s *self);

	int (*renegotiate)(struct aq_hw_s *self);

	int (*get_mac_permanent)(struct aq_hw_s *self, u8 *mac);

	int (*set_link_speed)(struct aq_hw_s *self, u32 speed);

	int (*set_state)(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state);
	int (*set_state)(struct aq_hw_s *self,
			 enum hal_atl_utils_fw_state_e state);

	int (*update_link_status)(struct aq_hw_s *self);

	int (*update_stats)(struct aq_hw_s *self);

	int (*set_flow_control)(struct aq_hw_s *self);
};

#endif /* AQ_HW_H */
+8 −4
Original line number Diff line number Diff line
@@ -89,8 +89,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
	aq_nic_rss_init(self, cfg->num_rss_queues);

	/*descriptors */
	cfg->rxds = min(cfg->aq_hw_caps->rxds, AQ_CFG_RXDS_DEF);
	cfg->txds = min(cfg->aq_hw_caps->txds, AQ_CFG_TXDS_DEF);
	cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF);
	cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF);

	/*rss rings */
	cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF);
@@ -761,10 +761,14 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     100baseT_Full);

	if (self->aq_nic_cfg.flow_control)
	if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     Pause);

	if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     Asym_Pause);

	if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
	else
@@ -879,7 +883,7 @@ void aq_nic_deinit(struct aq_nic_s *self)
		aq_vec_deinit(aq_vec);

	if (self->power_state == AQ_HW_POWER_STATE_D0) {
		(void)self->aq_hw_ops->hw_deinit(self->aq_hw);
		(void)self->aq_fw_ops->deinit(self->aq_hw);
	} else {
		(void)self->aq_hw_ops->hw_set_power(self->aq_hw,
						   self->power_state);
+24 −23
Original line number Diff line number Diff line
@@ -26,10 +26,12 @@
	.tcs = HW_ATL_A0_TC_MAX,	  \
	.rxd_alignment = 1U,		  \
	.rxd_size = HW_ATL_A0_RXD_SIZE,   \
	.rxds = 248U, \
	.rxds_max = HW_ATL_A0_MAX_RXD,    \
	.rxds_min = HW_ATL_A0_MIN_RXD,    \
	.txd_alignment = 1U,		  \
	.txd_size = HW_ATL_A0_TXD_SIZE,   \
	.txds = 8U * 1024U, \
	.txds_max = HW_ATL_A0_MAX_TXD,    \
	.txds_min = HW_ATL_A0_MIN_RXD,    \
	.txhwb_alignment = 4096U,	  \
	.tx_rings = HW_ATL_A0_TX_RINGS,   \
	.rx_rings = HW_ATL_A0_RX_RINGS,   \
@@ -875,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
const struct aq_hw_ops hw_atl_ops_a0 = {
	.hw_set_mac_address   = hw_atl_a0_hw_mac_addr_set,
	.hw_init              = hw_atl_a0_hw_init,
	.hw_deinit            = hw_atl_utils_hw_deinit,
	.hw_set_power         = hw_atl_utils_hw_set_power,
	.hw_reset             = hw_atl_a0_hw_reset,
	.hw_start             = hw_atl_a0_hw_start,
+8 −0
Original line number Diff line number Diff line
@@ -88,4 +88,12 @@

#define HW_ATL_A0_FW_VER_EXPECTED 0x01050006U

#define HW_ATL_A0_MIN_RXD \
	(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_RXD_MULTIPLE))
#define HW_ATL_A0_MIN_TXD \
	(ALIGN(AQ_CFG_SKB_FRAGS_MAX + 1U, AQ_HW_TXD_MULTIPLE))

#define HW_ATL_A0_MAX_RXD 8184U
#define HW_ATL_A0_MAX_TXD 8184U

#endif /* HW_ATL_A0_INTERNAL_H */
Loading