Commit d77a2384 authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller

net: thunderx: Support for internal loopback mode

Support for setting VF's corresponding BGX LMAC in internal
loopback mode. This mode can be used for verifying basic HW
functionality such as packet I/O, RX checksum validation,
CQ/RBDR interrupts, stats e.t.c. Useful when DUT has no external
network connectivity.

'loopback' mode can be enabled or disabled via ethtool.

Note: This feature is not supported when no of VFs enabled are
morethan no of physical interfaces i.e active BGX LMACs
Signed-off-by: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarAleksey Makarov <aleksey.makarov@caviumnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 92dc8769
...@@ -265,6 +265,7 @@ struct nicvf { ...@@ -265,6 +265,7 @@ struct nicvf {
u8 node; u8 node;
u8 tns_mode:1; u8 tns_mode:1;
u8 sqs_mode:1; u8 sqs_mode:1;
u8 loopback_supported:1;
u16 mtu; u16 mtu;
struct queue_set *qs; struct queue_set *qs;
#define MAX_SQS_PER_VF_SINGLE_NODE 5 #define MAX_SQS_PER_VF_SINGLE_NODE 5
...@@ -344,6 +345,7 @@ struct nicvf { ...@@ -344,6 +345,7 @@ struct nicvf {
#define NIC_MBOX_MSG_NICVF_PTR 0x13 /* Send nicvf ptr to PF */ #define NIC_MBOX_MSG_NICVF_PTR 0x13 /* Send nicvf ptr to PF */
#define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */ #define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */
#define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */ #define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */
#define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */
#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */
#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
...@@ -353,6 +355,7 @@ struct nic_cfg_msg { ...@@ -353,6 +355,7 @@ struct nic_cfg_msg {
u8 node_id; u8 node_id;
u8 tns_mode:1; u8 tns_mode:1;
u8 sqs_mode:1; u8 sqs_mode:1;
u8 loopback_supported:1;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
}; };
...@@ -452,6 +455,13 @@ struct nicvf_ptr { ...@@ -452,6 +455,13 @@ struct nicvf_ptr {
u64 nicvf; u64 nicvf;
}; };
/* Set interface in loopback mode */
struct set_loopback {
u8 msg;
u8 vf_id;
bool enable;
};
/* 128 bit shared memory between PF and each VF */ /* 128 bit shared memory between PF and each VF */
union nic_mbx { union nic_mbx {
struct { u8 msg; } msg; struct { u8 msg; } msg;
...@@ -468,6 +478,7 @@ union nic_mbx { ...@@ -468,6 +478,7 @@ union nic_mbx {
struct bgx_link_status link_status; struct bgx_link_status link_status;
struct sqs_alloc sqs_alloc; struct sqs_alloc sqs_alloc;
struct nicvf_ptr nicvf; struct nicvf_ptr nicvf;
struct set_loopback lbk;
}; };
#define NIC_NODE_ID_MASK 0x03 #define NIC_NODE_ID_MASK 0x03
......
...@@ -154,6 +154,9 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf) ...@@ -154,6 +154,9 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf)
} }
mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false;
mbx.nic_cfg.node_id = nic->node; mbx.nic_cfg.node_id = nic->node;
mbx.nic_cfg.loopback_supported = vf < MAX_LMAC;
nic_send_msg_to_vf(nic, vf, &mbx); nic_send_msg_to_vf(nic, vf, &mbx);
} }
...@@ -579,6 +582,21 @@ static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) ...@@ -579,6 +582,21 @@ static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs)
nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); nic_send_msg_to_vf(nic, sqs->vf_id, &mbx);
} }
static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
{
int bgx_idx, lmac_idx;
if (lbk->vf_id > MAX_LMAC)
return -1;
bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
return 0;
}
/* Interrupt handler to handle mailbox messages from VFs */ /* Interrupt handler to handle mailbox messages from VFs */
static void nic_handle_mbx_intr(struct nicpf *nic, int vf) static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
{ {
...@@ -702,6 +720,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) ...@@ -702,6 +720,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
case NIC_MBOX_MSG_BGX_STATS: case NIC_MBOX_MSG_BGX_STATS:
nic_get_bgx_stats(nic, &mbx.bgx_stats); nic_get_bgx_stats(nic, &mbx.bgx_stats);
goto unlock; goto unlock;
case NIC_MBOX_MSG_LOOPBACK:
ret = nic_config_loopback(nic, &mbx.lbk);
break;
default: default:
dev_err(&nic->pdev->dev, dev_err(&nic->pdev->dev,
"Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
......
...@@ -202,6 +202,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) ...@@ -202,6 +202,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
ether_addr_copy(nic->netdev->dev_addr, ether_addr_copy(nic->netdev->dev_addr,
mbx.nic_cfg.mac_addr); mbx.nic_cfg.mac_addr);
nic->sqs_mode = mbx.nic_cfg.sqs_mode; nic->sqs_mode = mbx.nic_cfg.sqs_mode;
nic->loopback_supported = mbx.nic_cfg.loopback_supported;
nic->link_up = false; nic->link_up = false;
nic->duplex = 0; nic->duplex = 0;
nic->speed = 0; nic->speed = 0;
...@@ -1404,6 +1405,30 @@ static void nicvf_reset_task(struct work_struct *work) ...@@ -1404,6 +1405,30 @@ static void nicvf_reset_task(struct work_struct *work)
nic->netdev->trans_start = jiffies; nic->netdev->trans_start = jiffies;
} }
static int nicvf_config_loopback(struct nicvf *nic,
netdev_features_t features)
{
union nic_mbx mbx = {};
mbx.lbk.msg = NIC_MBOX_MSG_LOOPBACK;
mbx.lbk.vf_id = nic->vf_id;
mbx.lbk.enable = (features & NETIF_F_LOOPBACK) != 0;
return nicvf_send_msg_to_pf(nic, &mbx);
}
static netdev_features_t nicvf_fix_features(struct net_device *netdev,
netdev_features_t features)
{
struct nicvf *nic = netdev_priv(netdev);
if ((features & NETIF_F_LOOPBACK) &&
netif_running(netdev) && !nic->loopback_supported)
features &= ~NETIF_F_LOOPBACK;
return features;
}
static int nicvf_set_features(struct net_device *netdev, static int nicvf_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
...@@ -1413,6 +1438,9 @@ static int nicvf_set_features(struct net_device *netdev, ...@@ -1413,6 +1438,9 @@ static int nicvf_set_features(struct net_device *netdev,
if (changed & NETIF_F_HW_VLAN_CTAG_RX) if (changed & NETIF_F_HW_VLAN_CTAG_RX)
nicvf_config_vlan_stripping(nic, features); nicvf_config_vlan_stripping(nic, features);
if ((changed & NETIF_F_LOOPBACK) && netif_running(netdev))
return nicvf_config_loopback(nic, features);
return 0; return 0;
} }
...@@ -1424,6 +1452,7 @@ static const struct net_device_ops nicvf_netdev_ops = { ...@@ -1424,6 +1452,7 @@ static const struct net_device_ops nicvf_netdev_ops = {
.ndo_set_mac_address = nicvf_set_mac_address, .ndo_set_mac_address = nicvf_set_mac_address,
.ndo_get_stats64 = nicvf_get_stats64, .ndo_get_stats64 = nicvf_get_stats64,
.ndo_tx_timeout = nicvf_tx_timeout, .ndo_tx_timeout = nicvf_tx_timeout,
.ndo_fix_features = nicvf_fix_features,
.ndo_set_features = nicvf_set_features, .ndo_set_features = nicvf_set_features,
}; };
...@@ -1518,6 +1547,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1518,6 +1547,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features |= NETIF_F_RXHASH; netdev->hw_features |= NETIF_F_RXHASH;
netdev->features |= netdev->hw_features; netdev->features |= netdev->hw_features;
netdev->hw_features |= NETIF_F_LOOPBACK;
netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
......
...@@ -329,6 +329,37 @@ static void bgx_flush_dmac_addrs(struct bgx *bgx, int lmac) ...@@ -329,6 +329,37 @@ static void bgx_flush_dmac_addrs(struct bgx *bgx, int lmac)
} }
} }
/* Configure BGX LMAC in internal loopback mode */
void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable)
{
struct bgx *bgx;
struct lmac *lmac;
u64 cfg;
bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
if (!bgx)
return;
lmac = &bgx->lmac[lmac_idx];
if (lmac->is_sgmii) {
cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL);
if (enable)
cfg |= PCS_MRX_CTL_LOOPBACK1;
else
cfg &= ~PCS_MRX_CTL_LOOPBACK1;
bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg);
} else {
cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1);
if (enable)
cfg |= SPU_CTL_LOOPBACK;
else
cfg &= ~SPU_CTL_LOOPBACK;
bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg);
}
}
EXPORT_SYMBOL(bgx_lmac_internal_loopback);
static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid) static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid)
{ {
u64 cfg; u64 cfg;
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#define BGX_SPUX_CONTROL1 0x10000 #define BGX_SPUX_CONTROL1 0x10000
#define SPU_CTL_LOW_POWER BIT_ULL(11) #define SPU_CTL_LOW_POWER BIT_ULL(11)
#define SPU_CTL_LOOPBACK BIT_ULL(14)
#define SPU_CTL_RESET BIT_ULL(15) #define SPU_CTL_RESET BIT_ULL(15)
#define BGX_SPUX_STATUS1 0x10008 #define BGX_SPUX_STATUS1 0x10008
#define SPU_STATUS1_RCV_LNK BIT_ULL(2) #define SPU_STATUS1_RCV_LNK BIT_ULL(2)
...@@ -126,6 +127,7 @@ ...@@ -126,6 +127,7 @@
#define PCS_MRX_CTL_RST_AN BIT_ULL(9) #define PCS_MRX_CTL_RST_AN BIT_ULL(9)
#define PCS_MRX_CTL_PWR_DN BIT_ULL(11) #define PCS_MRX_CTL_PWR_DN BIT_ULL(11)
#define PCS_MRX_CTL_AN_EN BIT_ULL(12) #define PCS_MRX_CTL_AN_EN BIT_ULL(12)
#define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14)
#define PCS_MRX_CTL_RESET BIT_ULL(15) #define PCS_MRX_CTL_RESET BIT_ULL(15)
#define BGX_GMP_PCS_MRX_STATUS 0x30008 #define BGX_GMP_PCS_MRX_STATUS 0x30008
#define PCS_MRX_STATUS_AN_CPT BIT_ULL(5) #define PCS_MRX_STATUS_AN_CPT BIT_ULL(5)
...@@ -186,6 +188,8 @@ int bgx_get_lmac_count(int node, int bgx); ...@@ -186,6 +188,8 @@ int bgx_get_lmac_count(int node, int bgx);
const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid); const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid);
void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac); void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac);
void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status);
void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable);
u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx); u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx);
u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx); u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx);
#define BGX_RX_STATS_COUNT 11 #define BGX_RX_STATS_COUNT 11
......
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