Commit 8af7b452 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-atlantic-additional-A2-features'



Igor Russkikh says:

====================
net: atlantic: additional A2 features

This patchset adds more features to A2:
 * half duplex rates;
 * EEE;
 * flow control;
 * link partner capabilities reporting;
 * phy loopback.

Feature-wise A2 is almost on-par with A1 save for WoL and filtering, which
will be submitted as separate follow-up patchset(s).
====================

Reviewed-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 29cb9868 ecab7870
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -58,11 +58,19 @@
#define AQ_NIC_RATE_1G		BIT(4)
#define AQ_NIC_RATE_100M	BIT(5)
#define AQ_NIC_RATE_10M		BIT(6)
#define AQ_NIC_RATE_1G_HALF	BIT(7)
#define AQ_NIC_RATE_100M_HALF	BIT(8)
#define AQ_NIC_RATE_10M_HALF	BIT(9)

#define AQ_NIC_RATE_EEE_10G	BIT(7)
#define AQ_NIC_RATE_EEE_5G	BIT(8)
#define AQ_NIC_RATE_EEE_2G5	BIT(9)
#define AQ_NIC_RATE_EEE_1G	BIT(10)
#define AQ_NIC_RATE_EEE_100M	BIT(11)
#define AQ_NIC_RATE_EEE_10G	BIT(10)
#define AQ_NIC_RATE_EEE_5G	BIT(11)
#define AQ_NIC_RATE_EEE_2G5	BIT(12)
#define AQ_NIC_RATE_EEE_1G	BIT(13)
#define AQ_NIC_RATE_EEE_100M	BIT(14)
#define AQ_NIC_RATE_EEE_MSK     (AQ_NIC_RATE_EEE_10G |\
				 AQ_NIC_RATE_EEE_5G |\
				 AQ_NIC_RATE_EEE_2G5 |\
				 AQ_NIC_RATE_EEE_1G |\
				 AQ_NIC_RATE_EEE_100M)

#endif /* AQ_COMMON_H */
+9 −10
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * aQuantia Corporation Network Driver
 * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */

/* File aq_ethtool.c: Definition of ethertool related functions. */
@@ -611,16 +612,13 @@ static int aq_ethtool_get_ts_info(struct net_device *ndev,
	return 0;
}

static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
static u32 eee_mask_to_ethtool_mask(u32 speed)
{
	u32 rate = 0;

	if (speed & AQ_NIC_RATE_EEE_10G)
		rate |= SUPPORTED_10000baseT_Full;

	if (speed & AQ_NIC_RATE_EEE_2G5)
		rate |= SUPPORTED_2500baseX_Full;

	if (speed & AQ_NIC_RATE_EEE_1G)
		rate |= SUPPORTED_1000baseT_Full;

@@ -656,7 +654,7 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
	eee->eee_enabled = !!eee->advertised;

	eee->tx_lpi_enabled = eee->eee_enabled;
	if (eee->advertised & eee->lp_advertised)
	if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK)
		eee->eee_active = true;

	return 0;
@@ -838,6 +836,7 @@ static int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags)
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg;
	u32 priv_flags;
	int ret = 0;

	cfg = aq_nic_get_cfg(aq_nic);
	priv_flags = cfg->priv_flags;
@@ -859,10 +858,10 @@ static int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags)
			dev_open(ndev, NULL);
		}
	} else if ((priv_flags ^ flags) & AQ_HW_LOOPBACK_MASK) {
		aq_nic_set_loopback(aq_nic);
		ret = aq_nic_set_loopback(aq_nic);
	}

	return 0;
	return ret;
}

const struct ethtool_ops aq_ethtool_ops = {
+7 −3
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * aQuantia Corporation Network Driver
 * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */

/* File aq_hw.h: Declaration of abstract interface for NIC hardware specific
@@ -69,6 +70,9 @@ struct aq_hw_caps_s {

struct aq_hw_link_status_s {
	unsigned int mbps;
	bool full_duplex;
	u32 lp_link_speed_msk;
	u32 lp_flow_control;
};

struct aq_stats_s {
+95 −14
Original line number Diff line number Diff line
@@ -935,12 +935,17 @@ static void aq_nic_update_ndev_stats(struct aq_nic_s *self)
void aq_nic_get_link_ksettings(struct aq_nic_s *self,
			       struct ethtool_link_ksettings *cmd)
{
	u32 lp_link_speed_msk;

	if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
		cmd->base.port = PORT_FIBRE;
	else
		cmd->base.port = PORT_TP;
	/* This driver supports only 10G capable adapters, so DUPLEX_FULL */
	cmd->base.duplex = DUPLEX_FULL;

	cmd->base.duplex = DUPLEX_UNKNOWN;
	if (self->link_status.mbps)
		cmd->base.duplex = self->link_status.full_duplex ?
				   DUPLEX_FULL : DUPLEX_HALF;
	cmd->base.autoneg = self->aq_nic_cfg.is_autoneg;

	ethtool_link_ksettings_zero_link_mode(cmd, supported);
@@ -961,14 +966,26 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     1000baseT_Full);

	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     1000baseT_Half);

	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M)
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     100baseT_Full);

	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     100baseT_Half);

	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M)
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     10baseT_Full);

	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     10baseT_Half);

	if (self->aq_nic_cfg.aq_hw_caps->flow_control) {
		ethtool_link_ksettings_add_link_mode(cmd, supported,
						     Pause);
@@ -1004,14 +1021,26 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     1000baseT_Full);

	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     1000baseT_Half);

	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     100baseT_Full);

	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     100baseT_Half);

	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     10baseT_Full);

	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     10baseT_Half);

	if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)
		ethtool_link_ksettings_add_link_mode(cmd, advertising,
						     Pause);
@@ -1026,32 +1055,84 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
	else
		ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);

	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
	lp_link_speed_msk = self->aq_hw->aq_link_status.lp_link_speed_msk;

	if (lp_link_speed_msk & AQ_NIC_RATE_10G)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     10000baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_5G)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     5000baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_2G5)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     2500baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_1G)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     1000baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_1G_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     1000baseT_Half);

	if (lp_link_speed_msk & AQ_NIC_RATE_100M)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     100baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_100M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     100baseT_Half);

	if (lp_link_speed_msk & AQ_NIC_RATE_10M)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     10baseT_Full);

	if (lp_link_speed_msk & AQ_NIC_RATE_10M_HALF)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     10baseT_Half);

	if (self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX)
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     Pause);
	if (!!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_TX) ^
	    !!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX))
		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
						     Asym_Pause);
}

int aq_nic_set_link_ksettings(struct aq_nic_s *self,
			      const struct ethtool_link_ksettings *cmd)
{
	u32 speed = 0U;
	int fduplex = (cmd->base.duplex == DUPLEX_FULL);
	u32 speed = cmd->base.speed;
	u32 rate = 0U;
	int err = 0;

	if (!fduplex && speed > SPEED_1000) {
		err = -EINVAL;
		goto err_exit;
	}

	if (cmd->base.autoneg == AUTONEG_ENABLE) {
		rate = self->aq_nic_cfg.aq_hw_caps->link_speed_msk;
		self->aq_nic_cfg.is_autoneg = true;
	} else {
		speed = cmd->base.speed;

		switch (speed) {
		case SPEED_10:
			rate = AQ_NIC_RATE_10M;
			rate = fduplex ? AQ_NIC_RATE_10M : AQ_NIC_RATE_10M_HALF;
			break;

		case SPEED_100:
			rate = AQ_NIC_RATE_100M;
			rate = fduplex ? AQ_NIC_RATE_100M
				       : AQ_NIC_RATE_100M_HALF;
			break;

		case SPEED_1000:
			rate = AQ_NIC_RATE_1G;
			rate = fduplex ? AQ_NIC_RATE_1G : AQ_NIC_RATE_1G_HALF;
			break;

		case SPEED_2500:
+2 −2
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
	return err;
}

static int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc)
int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc)
{
	hw_atl_rpb_rx_xoff_en_per_tc_set(self, !!(fc & AQ_NIC_FC_RX), tc);

@@ -1556,7 +1556,7 @@ static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
	return aq_hw_err_from_flags(self);
}

static int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable)
int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable)
{
	switch (mode) {
	case AQ_HW_LOOPBACK_DMA_SYS:
Loading