Commit 0ebc5b62 authored by David S. Miller's avatar David S. Miller

Merge branch 'thunderx-new-features'

Sunil Goutham says:

====================
net: thunderx: Support for 80xx, RED, PFC e.t.c

This patch series adds support for SLM modules present on 80xx
silicon, enables ramdom early discard, backpressure generation,
PFC and some ethtool changes to display supported link modes e.t.c.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a7dac9f9 430da208
......@@ -149,6 +149,12 @@ struct nicvf_rss_info {
u64 key[RSS_HASH_KEY_SIZE];
} ____cacheline_aligned_in_smp;
struct nicvf_pfc {
u8 autoneg;
u8 fc_rx;
u8 fc_tx;
};
enum rx_stats_reg_offset {
RX_OCTS = 0x0,
RX_UCAST = 0x1,
......@@ -292,11 +298,13 @@ struct nicvf {
u8 node;
u8 cpi_alg;
bool link_up;
u8 mac_type;
u8 duplex;
u32 speed;
bool tns_mode;
bool loopback_supported;
struct nicvf_rss_info rss_info;
struct nicvf_pfc pfc;
struct tasklet_struct qs_err_task;
struct work_struct reset_task;
......@@ -357,6 +365,7 @@ struct nicvf {
#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_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */
#define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */
#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */
#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
......@@ -446,6 +455,7 @@ struct bgx_stats_msg {
/* Physical interface link status */
struct bgx_link_status {
u8 msg;
u8 mac_type;
u8 link_up;
u8 duplex;
u32 speed;
......@@ -498,6 +508,14 @@ struct reset_stat_cfg {
u16 sq_stat_mask;
};
struct pfc {
u8 msg;
u8 get; /* Get or set PFC settings */
u8 autoneg;
u8 fc_rx;
u8 fc_tx;
};
/* 128 bit shared memory between PF and each VF */
union nic_mbx {
struct { u8 msg; } msg;
......@@ -516,6 +534,7 @@ union nic_mbx {
struct nicvf_ptr nicvf;
struct set_loopback lbk;
struct reset_stat_cfg reset_stat;
struct pfc pfc;
};
#define NIC_NODE_ID_MASK 0x03
......
......@@ -809,6 +809,15 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
/* Enable moving average calculation.
* Keep the LVL/AVG delay to HW enforced minimum so that, not too many
* packets sneek in between average calculations.
*/
nic_reg_write(nic, NIC_PF_CQ_AVG_CFG,
(BIT_ULL(20) | 0x2ull << 14 | 0x1));
nic_reg_write(nic, NIC_PF_RRM_AVG_CFG,
(BIT_ULL(20) | 0x3ull << 14 | 0x1));
return 0;
}
......@@ -889,6 +898,30 @@ static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable);
}
static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg)
{
int bgx, lmac;
struct pfc pfc;
union nic_mbx mbx = {};
if (vf >= nic->num_vf_en)
return;
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
if (cfg->get) {
bgx_lmac_get_pfc(nic->node, bgx, lmac, &pfc);
mbx.pfc.msg = NIC_MBOX_MSG_PFC;
mbx.pfc.autoneg = pfc.autoneg;
mbx.pfc.fc_rx = pfc.fc_rx;
mbx.pfc.fc_tx = pfc.fc_tx;
nic_send_msg_to_vf(nic, vf, &mbx);
} else {
bgx_lmac_set_pfc(nic->node, bgx, lmac, cfg);
nic_mbx_send_ack(nic, vf);
}
}
/* Interrupt handler to handle mailbox messages from VFs */
static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
{
......@@ -1028,6 +1061,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
case NIC_MBOX_MSG_RESET_STAT_COUNTER:
ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat);
break;
case NIC_MBOX_MSG_PFC:
nic_pause_frame(nic, vf, &mbx.pfc);
goto unlock;
default:
dev_err(&nic->pdev->dev,
"Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
......@@ -1258,6 +1294,7 @@ static void nic_poll_for_link(struct work_struct *work)
mbx.link_status.link_up = link.link_up;
mbx.link_status.duplex = link.duplex;
mbx.link_status.speed = link.speed;
mbx.link_status.mac_type = link.mac_type;
nic_send_msg_to_vf(nic, vf, &mbx);
}
}
......
......@@ -130,12 +130,42 @@ static int nicvf_get_settings(struct net_device *netdev,
return 0;
}
if (nic->speed <= 1000) {
cmd->port = PORT_MII;
switch (nic->speed) {
case SPEED_1000:
cmd->port = PORT_MII | PORT_TP;
cmd->autoneg = AUTONEG_ENABLE;
cmd->supported |= SUPPORTED_MII | SUPPORTED_TP;
cmd->supported |= SUPPORTED_1000baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_10baseT_Half;
cmd->supported |= SUPPORTED_Autoneg;
cmd->advertising |= ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_10baseT_Half;
break;
case SPEED_10000:
if (nic->mac_type == BGX_MODE_RXAUI) {
cmd->port = PORT_TP;
cmd->supported |= SUPPORTED_TP;
} else {
cmd->port = PORT_FIBRE;
cmd->supported |= SUPPORTED_FIBRE;
}
cmd->autoneg = AUTONEG_DISABLE;
cmd->supported |= SUPPORTED_10000baseT_Full;
break;
case SPEED_40000:
cmd->port = PORT_FIBRE;
cmd->autoneg = AUTONEG_DISABLE;
cmd->supported |= SUPPORTED_FIBRE;
cmd->supported |= SUPPORTED_40000baseCR4_Full;
break;
}
cmd->duplex = nic->duplex;
ethtool_cmd_speed_set(cmd, nic->speed);
......@@ -690,6 +720,55 @@ static int nicvf_set_channels(struct net_device *dev,
return err;
}
static void nicvf_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct nicvf *nic = netdev_priv(dev);
union nic_mbx mbx = {};
/* Supported only for 10G/40G interfaces */
if ((nic->mac_type == BGX_MODE_SGMII) ||
(nic->mac_type == BGX_MODE_QSGMII) ||
(nic->mac_type == BGX_MODE_RGMII))
return;
mbx.pfc.msg = NIC_MBOX_MSG_PFC;
mbx.pfc.get = 1;
if (!nicvf_send_msg_to_pf(nic, &mbx)) {
pause->autoneg = nic->pfc.autoneg;
pause->rx_pause = nic->pfc.fc_rx;
pause->tx_pause = nic->pfc.fc_tx;
}
}
static int nicvf_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct nicvf *nic = netdev_priv(dev);
union nic_mbx mbx = {};
/* Supported only for 10G/40G interfaces */
if ((nic->mac_type == BGX_MODE_SGMII) ||
(nic->mac_type == BGX_MODE_QSGMII) ||
(nic->mac_type == BGX_MODE_RGMII))
return -EOPNOTSUPP;
if (pause->autoneg)
return -EOPNOTSUPP;
mbx.pfc.msg = NIC_MBOX_MSG_PFC;
mbx.pfc.get = 0;
mbx.pfc.fc_rx = pause->rx_pause;
mbx.pfc.fc_tx = pause->tx_pause;
if (nicvf_send_msg_to_pf(nic, &mbx))
return -EAGAIN;
nic->pfc.fc_rx = pause->rx_pause;
nic->pfc.fc_tx = pause->tx_pause;
return 0;
}
static const struct ethtool_ops nicvf_ethtool_ops = {
.get_settings = nicvf_get_settings,
.get_link = nicvf_get_link,
......@@ -711,6 +790,8 @@ static const struct ethtool_ops nicvf_ethtool_ops = {
.set_rxfh = nicvf_set_rxfh,
.get_channels = nicvf_get_channels,
.set_channels = nicvf_set_channels,
.get_pauseparam = nicvf_get_pauseparam,
.set_pauseparam = nicvf_set_pauseparam,
.get_ts_info = ethtool_op_get_ts_info,
};
......
......@@ -221,6 +221,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
nic->link_up = mbx.link_status.link_up;
nic->duplex = mbx.link_status.duplex;
nic->speed = mbx.link_status.speed;
nic->mac_type = mbx.link_status.mac_type;
if (nic->link_up) {
netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n",
nic->netdev->name, nic->speed,
......@@ -255,6 +256,12 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
nic->pnicvf = (struct nicvf *)mbx.nicvf.nicvf;
nic->pf_acked = true;
break;
case NIC_MBOX_MSG_PFC:
nic->pfc.autoneg = mbx.pfc.autoneg;
nic->pfc.fc_rx = mbx.pfc.fc_rx;
nic->pfc.fc_tx = mbx.pfc.fc_tx;
nic->pf_acked = true;
break;
default:
netdev_err(nic->netdev,
"Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
......
......@@ -544,14 +544,18 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
nicvf_send_msg_to_pf(nic, &mbx);
mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG;
mbx.rq.cfg = (1ULL << 63) | (1ULL << 62) | (qs->vnic_id << 0);
mbx.rq.cfg = BIT_ULL(63) | BIT_ULL(62) |
(RQ_PASS_RBDR_LVL << 16) | (RQ_PASS_CQ_LVL << 8) |
(qs->vnic_id << 0);
nicvf_send_msg_to_pf(nic, &mbx);
/* RQ drop config
* Enable CQ drop to reserve sufficient CQEs for all tx packets
*/
mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG;
mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
mbx.rq.cfg = BIT_ULL(63) | BIT_ULL(62) |
(RQ_PASS_RBDR_LVL << 40) | (RQ_DROP_RBDR_LVL << 32) |
(RQ_PASS_CQ_LVL << 16) | (RQ_DROP_CQ_LVL << 8);
nicvf_send_msg_to_pf(nic, &mbx);
if (!nic->sqs_mode && (qidx == 0)) {
......@@ -650,6 +654,7 @@ static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
sq_cfg.ldwb = 0;
sq_cfg.qsize = SND_QSIZE;
sq_cfg.tstmp_bgx_intf = 0;
sq_cfg.cq_limit = 0;
nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, *(u64 *)&sq_cfg);
/* Set threshold value for interrupt generation */
......
......@@ -85,12 +85,26 @@
#define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
MAX_CQE_PER_PKT_XMIT)
/* Calculate number of CQEs to reserve for all SQEs.
* Its 1/256th level of CQ size.
* '+ 1' to account for pipelining
/* RED and Backpressure levels of CQ for pkt reception
* For CQ, level is a measure of emptiness i.e 0x0 means full
* eg: For CQ of size 4K, and for pass/drop levels of 128/96
* HW accepts pkt if unused CQE >= 2048
* RED accepts pkt if unused CQE < 2048 & >= 1536
* DROPs pkts if unused CQE < 1536
*/
#define RQ_PASS_CQ_LVL 128ULL
#define RQ_DROP_CQ_LVL 96ULL
/* RED and Backpressure levels of RBDR for pkt reception
* For RBDR, level is a measure of fullness i.e 0x0 means empty
* eg: For RBDR of size 8K, and for pass/drop levels of 4/0
* HW accepts pkt if unused RBs >= 256
* RED accepts pkt if unused RBs < 256 & >= 0
* DROPs pkts if unused RBs < 0
*/
#define RQ_CQ_DROP ((256 / (CMP_QUEUE_LEN / \
(CMP_QUEUE_LEN - MAX_CQES_FOR_TX))) + 1)
#define RQ_PASS_RBDR_LVL 8ULL
#define RQ_DROP_RBDR_LVL 0ULL
/* Descriptor size in bytes */
#define SND_QUEUE_DESC_SIZE 16
......
......@@ -624,7 +624,9 @@ struct cq_cfg {
struct sq_cfg {
#if defined(__BIG_ENDIAN_BITFIELD)
u64 reserved_20_63:44;
u64 reserved_32_63:32;
u64 cq_limit:8;
u64 reserved_20_23:4;
u64 ena:1;
u64 reserved_18_18:1;
u64 reset:1;
......@@ -642,7 +644,9 @@ struct sq_cfg {
u64 reset:1;
u64 reserved_18_18:1;
u64 ena:1;
u64 reserved_20_63:44;
u64 reserved_20_23:4;
u64 cq_limit:8;
u64 reserved_32_63:32;
#endif
};
......
......@@ -161,6 +161,7 @@ void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status)
return;
lmac = &bgx->lmac[lmacid];
link->mac_type = lmac->lmac_type;
link->link_up = lmac->link_up;
link->duplex = lmac->last_duplex;
link->speed = lmac->last_speed;
......@@ -211,6 +212,47 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
}
EXPORT_SYMBOL(bgx_lmac_rx_tx_enable);
void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause)
{
struct pfc *pfc = (struct pfc *)pause;
struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
struct lmac *lmac;
u64 cfg;
if (!bgx)
return;
lmac = &bgx->lmac[lmacid];
if (lmac->is_sgmii)
return;
cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_CBFC_CTL);
pfc->fc_rx = cfg & RX_EN;
pfc->fc_tx = cfg & TX_EN;
pfc->autoneg = 0;
}
EXPORT_SYMBOL(bgx_lmac_get_pfc);
void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause)
{
struct pfc *pfc = (struct pfc *)pause;
struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
struct lmac *lmac;
u64 cfg;
if (!bgx)
return;
lmac = &bgx->lmac[lmacid];
if (lmac->is_sgmii)
return;
cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_CBFC_CTL);
cfg &= ~(RX_EN | TX_EN);
cfg |= (pfc->fc_rx ? RX_EN : 0x00);
cfg |= (pfc->fc_tx ? TX_EN : 0x00);
bgx_reg_write(bgx, lmacid, BGX_SMUX_CBFC_CTL, cfg);
}
EXPORT_SYMBOL(bgx_lmac_set_pfc);
static void bgx_sgmii_change_link_state(struct lmac *lmac)
{
struct bgx *bgx = lmac->bgx;
......@@ -524,6 +566,18 @@ static int bgx_lmac_xaui_init(struct bgx *bgx, struct lmac *lmac)
cfg |= SMU_TX_CTL_DIC_EN;
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
/* Enable receive and transmission of pause frames */
bgx_reg_write(bgx, lmacid, BGX_SMUX_CBFC_CTL, ((0xffffULL << 32) |
BCK_EN | DRP_EN | TX_EN | RX_EN));
/* Configure pause time and interval */
bgx_reg_write(bgx, lmacid,
BGX_SMUX_TX_PAUSE_PKT_TIME, DEFAULT_PAUSE_TIME);
cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_PAUSE_PKT_INTERVAL);
cfg &= ~0xFFFFull;
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_PAUSE_PKT_INTERVAL,
cfg | (DEFAULT_PAUSE_TIME - 0x1000));
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_PAUSE_ZERO, 0x01);
/* take lmac_count into account */
bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
/* max packet size */
......@@ -970,11 +1024,25 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
lmac_set_training(bgx, lmac, lmac->lmacid);
lmac_set_lane2sds(bgx, lmac);
/* Set LMAC type of other lmac on same DLM i.e LMAC 1/3 */
olmac = &bgx->lmac[idx + 1];
/* Check if other LMAC on the same DLM is already configured by
* firmware, if so use the same config or else set as same, as
* that of LMAC 0/2.
* This check is needed as on 80xx only one lane of each of the
* DLM of BGX0 is used, so have to rely on firmware for
* distingushing 80xx from 81xx.
*/
cmr_cfg = bgx_reg_read(bgx, idx + 1, BGX_CMRX_CFG);
lmac_type = (u8)((cmr_cfg >> 8) & 0x07);
lane_to_sds = (u8)(cmr_cfg & 0xFF);
if ((lmac_type == 0) && (lane_to_sds == 0xE4)) {
olmac->lmac_type = lmac->lmac_type;
lmac_set_training(bgx, olmac, olmac->lmacid);
lmac_set_lane2sds(bgx, olmac);
} else {
olmac->lmac_type = lmac_type;
olmac->lane_to_sds = lane_to_sds;
}
lmac_set_training(bgx, olmac, olmac->lmacid);
}
}
......
......@@ -27,6 +27,7 @@
#define MAX_BGX_CHANS_PER_LMAC 16
#define MAX_DMAC_PER_LMAC 8
#define MAX_FRAME_SIZE 9216
#define DEFAULT_PAUSE_TIME 0xFFFF
#define BGX_ID_MASK 0x3
......@@ -126,7 +127,10 @@
#define SMU_RX_CTL_STATUS (3ull << 0)
#define BGX_SMUX_TX_APPEND 0x20100
#define SMU_TX_APPEND_FCS_D BIT_ULL(2)
#define BGX_SMUX_TX_PAUSE_PKT_TIME 0x20110
#define BGX_SMUX_TX_MIN_PKT 0x20118
#define BGX_SMUX_TX_PAUSE_PKT_INTERVAL 0x20120
#define BGX_SMUX_TX_PAUSE_ZERO 0x20138
#define BGX_SMUX_TX_INT 0x20140
#define BGX_SMUX_TX_CTL 0x20178
#define SMU_TX_CTL_DIC_EN BIT_ULL(0)
......@@ -136,6 +140,11 @@
#define BGX_SMUX_CTL 0x20200
#define SMU_CTL_RX_IDLE BIT_ULL(0)
#define SMU_CTL_TX_IDLE BIT_ULL(1)
#define BGX_SMUX_CBFC_CTL 0x20218
#define RX_EN BIT_ULL(0)
#define TX_EN BIT_ULL(1)
#define BCK_EN BIT_ULL(2)
#define DRP_EN BIT_ULL(3)
#define BGX_GMP_PCS_MRX_CTL 0x30000
#define PCS_MRX_CTL_RST_AN BIT_ULL(9)
......@@ -207,6 +216,9 @@ 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_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable);
void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause);
void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause);
void xcv_init_hw(void);
void xcv_setup_link(bool link_up, int link_speed);
......
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