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

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
......@@ -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:
......
......@@ -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,
......
......@@ -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 */
......@@ -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);
......
......@@ -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;
......
......@@ -46,6 +46,7 @@ struct aq_nic_cfg_s {
bool is_polling;
bool is_rss;
bool is_lro;
u32 priv_flags;
u8 tcs;
struct aq_rss_parameters aq_rss;
u32 eee_speeds;
......@@ -158,6 +159,7 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
const struct ethtool_link_ksettings *cmd);
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_set_loopback(struct aq_nic_s *self);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
void aq_nic_shutdown(struct aq_nic_s *self);
u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);
......
......@@ -1427,6 +1427,30 @@ 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)
{
switch (mode) {
case AQ_HW_LOOPBACK_DMA_SYS:
hw_atl_tpb_tx_dma_sys_lbk_en_set(self, enable);
hw_atl_rpb_dma_sys_lbk_set(self, enable);
break;
case AQ_HW_LOOPBACK_PKT_SYS:
hw_atl_tpo_tx_pkt_sys_lbk_en_set(self, enable);
hw_atl_rpf_tpo_to_rpf_sys_lbk_set(self, enable);
break;
case AQ_HW_LOOPBACK_DMA_NET:
hw_atl_rpf_vlan_prom_mode_en_set(self, enable);
hw_atl_rpfl2promiscuous_mode_en_set(self, enable);
hw_atl_tpb_tx_tx_clk_gate_en_set(self, !enable);
hw_atl_tpb_tx_dma_net_lbk_en_set(self, enable);
hw_atl_rpb_dma_net_lbk_set(self, enable);
break;
default:
return -EINVAL;
}
return 0;
}
const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address = hw_atl_b0_hw_mac_addr_set,
.hw_init = hw_atl_b0_hw_init,
......@@ -1481,5 +1505,9 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.rx_extract_ts = hw_atl_b0_rx_extract_ts,
.extract_hwts = hw_atl_b0_extract_hwts,
.hw_set_offload = hw_atl_b0_hw_offload_set,
.hw_set_fc = hw_atl_b0_set_fc,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
.hw_set_offload = hw_atl_b0_hw_offload_set,
.hw_set_loopback = hw_atl_b0_set_loopback,
.hw_set_fc = hw_atl_b0_set_fc,
};
......@@ -563,6 +563,13 @@ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk)
HW_ATL_RPB_DMA_SYS_LBK_SHIFT, dma_sys_lbk);
}
void hw_atl_rpb_dma_net_lbk_set(struct aq_hw_s *aq_hw, u32 dma_net_lbk)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_DMA_NET_LBK_ADR,
HW_ATL_RPB_DMA_NET_LBK_MSK,
HW_ATL_RPB_DMA_NET_LBK_SHIFT, dma_net_lbk);
}
void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw,
u32 rx_traf_class_mode)
{
......@@ -1341,7 +1348,26 @@ void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_
tx_dma_sys_lbk_en);
}
void hw_atl_tpb_tx_dma_net_lbk_en_set(struct aq_hw_s *aq_hw,
u32 tx_dma_net_lbk_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_DMA_NET_LBK_ADR,
HW_ATL_TPB_DMA_NET_LBK_MSK,
HW_ATL_TPB_DMA_NET_LBK_SHIFT,
tx_dma_net_lbk_en);
}
void hw_atl_tpb_tx_tx_clk_gate_en_set(struct aq_hw_s *aq_hw,
u32 tx_clk_gate_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_TX_CLK_GATE_EN_ADR,
HW_ATL_TPB_TX_CLK_GATE_EN_MSK,
HW_ATL_TPB_TX_CLK_GATE_EN_SHIFT,
tx_clk_gate_en);
}
void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_buff_size_per_tc, u32 buffer)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_TXBBUF_SIZE_ADR(buffer),
......
......@@ -288,6 +288,9 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw,
/* set dma system loopback */
void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk);
/* set dma network loopback */
void hw_atl_rpb_dma_net_lbk_set(struct aq_hw_s *aq_hw, u32 dma_net_lbk);
/* set rx traffic class mode */
void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw,
u32 rx_traf_class_mode);
......@@ -629,6 +632,14 @@ void hw_atl_tpb_tx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw,
/* set tx dma system loopback enable */
void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_en);
/* set tx dma network loopback enable */
void hw_atl_tpb_tx_dma_net_lbk_en_set(struct aq_hw_s *aq_hw,
u32 tx_dma_net_lbk_en);
/* set tx clock gating enable */
void hw_atl_tpb_tx_tx_clk_gate_en_set(struct aq_hw_s *aq_hw,
u32 tx_clk_gate_en);
/* set tx packet buffer size (per tc) */
void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 tx_pkt_buff_size_per_tc,
......
......@@ -554,6 +554,24 @@
/* default value of bitfield dma_sys_loopback */
#define HW_ATL_RPB_DMA_SYS_LBK_DEFAULT 0x0
/* rx dma_net_loopback bitfield definitions
* preprocessor definitions for the bitfield "dma_net_loopback".
* port="pif_rpb_dma_net_lbk_i"
*/
/* register address for bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_ADR 0x00005000
/* bitmask for bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_MSK 0x00000010
/* inverted bitmask for bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_MSKN 0xffffffef
/* lower bit position of bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_SHIFT 4
/* width of bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_WIDTH 1
/* default value of bitfield dma_net_loopback */
#define HW_ATL_RPB_DMA_NET_LBK_DEFAULT 0x0
/* rx rx_tc_mode bitfield definitions
* preprocessor definitions for the bitfield "rx_tc_mode".
* port="pif_rpb_rx_tc_mode_i,pif_rpf_rx_tc_mode_i"
......@@ -2107,6 +2125,24 @@
/* default value of bitfield dma_sys_loopback */
#define HW_ATL_TPB_DMA_SYS_LBK_DEFAULT 0x0
/* tx dma_net_loopback bitfield definitions
* preprocessor definitions for the bitfield "dma_net_loopback".
* port="pif_tpb_dma_net_lbk_i"
*/
/* register address for bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_ADR 0x00007000
/* bitmask for bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_MSK 0x00000010
/* inverted bitmask for bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_MSKN 0xffffffef
/* lower bit position of bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_SHIFT 4
/* width of bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_WIDTH 1
/* default value of bitfield dma_net_loopback */
#define HW_ATL_TPB_DMA_NET_LBK_DEFAULT 0x0
/* tx tx{b}_buf_size[7:0] bitfield definitions
* preprocessor definitions for the bitfield "tx{b}_buf_size[7:0]".
* parameter: buffer {b} | stride size 0x10 | range [0, 7]
......@@ -2144,6 +2180,24 @@
/* default value of bitfield tx_scp_ins_en */
#define HW_ATL_TPB_TX_SCP_INS_EN_DEFAULT 0x0
/* tx tx_clk_gate_en bitfield definitions
* preprocessor definitions for the bitfield "tx_clk_gate_en".
* port="pif_tpb_clk_gate_en_i"
*/
/* register address for bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_ADR 0x00007900
/* bitmask for bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_MSK 0x00000010
/* inverted bitmask for bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_MSKN 0xffffffef
/* lower bit position of bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_SHIFT 4
/* width of bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_WIDTH 1
/* default value of bitfield tx_clk_gate_en */
#define HW_ATL_TPB_TX_CLK_GATE_EN_DEFAULT 0x1
/* tx ipv4_chk_en bitfield definitions
* preprocessor definitions for the bitfield "ipv4_chk_en".
* port="pif_tpo_ipv4_chk_en_i"
......
......@@ -42,6 +42,9 @@
#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
#define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE)
#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
#define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK)
#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK)
#define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT)
#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE)
......@@ -53,6 +56,7 @@
#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E
#define HW_ATL_FW_VER_LED 0x03010026U
#define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU
struct __packed fw2x_msg_wol_pattern {
u8 mask[16];
......@@ -539,6 +543,33 @@ static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
return 0;
}
static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
{
u32 mpi_opts;
switch (mode) {
case AQ_HW_LOOPBACK_PHYINT_SYS:
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
if (enable)
mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
else
mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
break;
case AQ_HW_LOOPBACK_PHYEXT_SYS:
mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
if (enable)
mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
else
mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
break;
default:
return -EINVAL;
}
return 0;
}
static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
{
return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
......@@ -586,4 +617,5 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.send_fw_request = aq_fw2x_send_fw_request,
.enable_ptp = aq_fw3x_enable_ptp,
.led_control = aq_fw2x_led_control,
.set_phyloopback = aq_fw2x_set_phyloopback,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment