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

net: atlantic: loopback tests via private flags



Here we add a number of ethtool private flags
to allow enabling various loopbacks on HW.

Thats useful for verification and bringup works.

Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dc12f75a
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -325,6 +325,31 @@ Supported ethtool options
 Example:
 ethtool -N eth0 flow-type udp4 action 0 loc 32

 Private flags (testing)
 ---------------------------------

 Atlantic driver supports private flags for hardware custom features:

	$ ethtool --show-priv-flags ethX

	Private flags for ethX:
	DMASystemLoopback  : off
	PKTSystemLoopback  : off
	DMANetworkLoopback : off
	PHYInternalLoopback: off
	PHYExternalLoopback: off

 Example:

	$ ethtool --set-priv-flags ethX DMASystemLoopback on

 DMASystemLoopback:   DMA Host loopback.
 PKTSystemLoopback:   Packet buffer host loopback.
 DMANetworkLoopback:  Network side loopback on DMA block.
 PHYInternalLoopback: Internal loopback on Phy.
 PHYExternalLoopback: External loopback on Phy (with loopback ethernet cable).


Command Line Parameters
=======================
The following command line parameters are available on atlantic driver:
+54 −1
Original line number Diff line number Diff line
@@ -92,6 +92,14 @@ static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = {
	"Queue[%d] InErrors",
};

static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {
	"DMASystemLoopback",
	"PKTSystemLoopback",
	"DMANetworkLoopback",
	"PHYInternalLoopback",
	"PHYExternalLoopback",
};

static void aq_ethtool_stats(struct net_device *ndev,
			     struct ethtool_stats *stats, u64 *data)
{
@@ -137,7 +145,8 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
	u8 *p = data;

	if (stringset == ETH_SS_STATS) {
	switch (stringset) {
	case ETH_SS_STATS:
		memcpy(p, aq_ethtool_stat_names,
		       sizeof(aq_ethtool_stat_names));
		p = p + sizeof(aq_ethtool_stat_names);
@@ -150,6 +159,11 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
				p += ETH_GSTRING_LEN;
			}
		}
		break;
	case ETH_SS_PRIV_FLAGS:
		memcpy(p, aq_ethtool_priv_flag_names,
		       sizeof(aq_ethtool_priv_flag_names));
		break;
	}
}

@@ -193,6 +207,9 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
		ret = ARRAY_SIZE(aq_ethtool_stat_names) +
			cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
		break;
	case ETH_SS_PRIV_FLAGS:
		ret = ARRAY_SIZE(aq_ethtool_priv_flag_names);
		break;
	default:
		ret = -EOPNOTSUPP;
	}
@@ -650,6 +667,40 @@ static void aq_set_msg_level(struct net_device *ndev, u32 data)
	aq_nic->msg_enable = data;
}

u32 aq_ethtool_get_priv_flags(struct net_device *ndev)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);

	return aq_nic->aq_nic_cfg.priv_flags;
}

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;

	cfg = aq_nic_get_cfg(aq_nic);
	priv_flags = cfg->priv_flags;

	if (flags & ~AQ_PRIV_FLAGS_MASK)
		return -EOPNOTSUPP;

	cfg->priv_flags = flags;

	if ((priv_flags ^ flags) & BIT(AQ_HW_LOOPBACK_DMA_NET)) {
		if (netif_running(ndev)) {
			dev_close(ndev);

			dev_open(ndev, NULL);
		}
	} else if ((priv_flags ^ flags) & AQ_HW_LOOPBACK_MASK) {
		aq_nic_set_loopback(aq_nic);
	}

	return 0;
}

const struct ethtool_ops aq_ethtool_ops = {
	.get_link            = aq_ethtool_get_link,
	.get_regs_len        = aq_ethtool_get_regs_len,
@@ -676,6 +727,8 @@ const struct ethtool_ops aq_ethtool_ops = {
	.set_msglevel        = aq_set_msg_level,
	.get_sset_count      = aq_ethtool_get_sset_count,
	.get_ethtool_stats   = aq_ethtool_stats,
	.get_priv_flags      = aq_ethtool_get_priv_flags,
	.set_priv_flags      = aq_ethtool_set_priv_flags,
	.get_link_ksettings  = aq_ethtool_get_link_ksettings,
	.set_link_ksettings  = aq_ethtool_set_link_ksettings,
	.get_coalesce	     = aq_ethtool_get_coalesce,
+1 −0
Original line number Diff line number Diff line
@@ -12,5 +12,6 @@
#include "aq_common.h"

extern const struct ethtool_ops aq_ethtool_ops;
#define AQ_PRIV_FLAGS_MASK   (AQ_HW_LOOPBACK_MASK)

#endif /* AQ_ETHTOOL_H */
+18 −0
Original line number Diff line number Diff line
@@ -122,6 +122,20 @@ struct aq_stats_s {
#define AQ_HW_LED_BLINK    0x2U
#define AQ_HW_LED_DEFAULT  0x0U

enum aq_priv_flags {
	AQ_HW_LOOPBACK_DMA_SYS,
	AQ_HW_LOOPBACK_PKT_SYS,
	AQ_HW_LOOPBACK_DMA_NET,
	AQ_HW_LOOPBACK_PHYINT_SYS,
	AQ_HW_LOOPBACK_PHYEXT_SYS,
};

#define AQ_HW_LOOPBACK_MASK	(BIT(AQ_HW_LOOPBACK_DMA_SYS) |\
				 BIT(AQ_HW_LOOPBACK_PKT_SYS) |\
				 BIT(AQ_HW_LOOPBACK_DMA_NET) |\
				 BIT(AQ_HW_LOOPBACK_PHYINT_SYS) |\
				 BIT(AQ_HW_LOOPBACK_PHYEXT_SYS))

struct aq_hw_s {
	atomic_t flags;
	u8 rbl_enabled:1;
@@ -280,6 +294,8 @@ struct aq_hw_ops {
			    u64 *timestamp);

	int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);

	int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable);
};

struct aq_fw_ops {
@@ -310,6 +326,8 @@ struct aq_fw_ops {

	int (*led_control)(struct aq_hw_s *self, u32 mode);

	int (*set_phyloopback)(struct aq_hw_s *self, u32 mode, bool enable);

	int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
			 u8 *mac);

+45 −0
Original line number Diff line number Diff line
@@ -406,6 +406,8 @@ int aq_nic_start(struct aq_nic_s *self)

	INIT_WORK(&self->service_task, aq_nic_service_task);

	aq_nic_set_loopback(self);

	timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0);
	aq_nic_service_timer_cb(&self->service_timer);

@@ -625,6 +627,11 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)

	aq_ring_update_queue_state(ring);

	if (self->aq_nic_cfg.priv_flags & BIT(AQ_HW_LOOPBACK_DMA_NET)) {
		err = NETDEV_TX_BUSY;
		goto err_exit;
	}

	/* Above status update may stop the queue. Check this. */
	if (__netif_subqueue_stopped(self->ndev, ring->idx)) {
		err = NETDEV_TX_BUSY;
@@ -973,6 +980,44 @@ u32 aq_nic_get_fw_version(struct aq_nic_s *self)
	return fw_version;
}

int aq_nic_set_loopback(struct aq_nic_s *self)
{
	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;

	if (!self->aq_hw_ops->hw_set_loopback ||
	    !self->aq_fw_ops->set_phyloopback)
		return -ENOTSUPP;

	mutex_lock(&self->fwreq_mutex);
	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
					 AQ_HW_LOOPBACK_DMA_SYS,
					 !!(cfg->priv_flags &
					    BIT(AQ_HW_LOOPBACK_DMA_SYS)));

	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
					 AQ_HW_LOOPBACK_PKT_SYS,
					 !!(cfg->priv_flags &
					    BIT(AQ_HW_LOOPBACK_PKT_SYS)));

	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
					 AQ_HW_LOOPBACK_DMA_NET,
					 !!(cfg->priv_flags &
					    BIT(AQ_HW_LOOPBACK_DMA_NET)));

	self->aq_fw_ops->set_phyloopback(self->aq_hw,
					 AQ_HW_LOOPBACK_PHYINT_SYS,
					 !!(cfg->priv_flags &
					    BIT(AQ_HW_LOOPBACK_PHYINT_SYS)));

	self->aq_fw_ops->set_phyloopback(self->aq_hw,
					 AQ_HW_LOOPBACK_PHYEXT_SYS,
					 !!(cfg->priv_flags &
					    BIT(AQ_HW_LOOPBACK_PHYEXT_SYS)));
	mutex_unlock(&self->fwreq_mutex);

	return 0;
}

int aq_nic_stop(struct aq_nic_s *self)
{
	struct aq_vec_s *aq_vec = NULL;
Loading