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

net: thunderx: Pause frame support

Enable pause frames on both Rx and Tx side, configure pause
interval e.t.c. Also support for enable/disable pause frames
on Rx/Tx via ethtool has been added.
Signed-off-by: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d5b2d7a7
...@@ -149,6 +149,12 @@ struct nicvf_rss_info { ...@@ -149,6 +149,12 @@ struct nicvf_rss_info {
u64 key[RSS_HASH_KEY_SIZE]; u64 key[RSS_HASH_KEY_SIZE];
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
struct nicvf_pfc {
u8 autoneg;
u8 fc_rx;
u8 fc_tx;
};
enum rx_stats_reg_offset { enum rx_stats_reg_offset {
RX_OCTS = 0x0, RX_OCTS = 0x0,
RX_UCAST = 0x1, RX_UCAST = 0x1,
...@@ -298,6 +304,7 @@ struct nicvf { ...@@ -298,6 +304,7 @@ struct nicvf {
bool tns_mode; bool tns_mode;
bool loopback_supported; bool loopback_supported;
struct nicvf_rss_info rss_info; struct nicvf_rss_info rss_info;
struct nicvf_pfc pfc;
struct tasklet_struct qs_err_task; struct tasklet_struct qs_err_task;
struct work_struct reset_task; struct work_struct reset_task;
...@@ -358,6 +365,7 @@ struct nicvf { ...@@ -358,6 +365,7 @@ struct nicvf {
#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_LOOPBACK 0x16 /* Set interface in loopback */
#define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */ #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_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 */
...@@ -500,6 +508,14 @@ struct reset_stat_cfg { ...@@ -500,6 +508,14 @@ struct reset_stat_cfg {
u16 sq_stat_mask; 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 */ /* 128 bit shared memory between PF and each VF */
union nic_mbx { union nic_mbx {
struct { u8 msg; } msg; struct { u8 msg; } msg;
...@@ -518,6 +534,7 @@ union nic_mbx { ...@@ -518,6 +534,7 @@ union nic_mbx {
struct nicvf_ptr nicvf; struct nicvf_ptr nicvf;
struct set_loopback lbk; struct set_loopback lbk;
struct reset_stat_cfg reset_stat; struct reset_stat_cfg reset_stat;
struct pfc pfc;
}; };
#define NIC_NODE_ID_MASK 0x03 #define NIC_NODE_ID_MASK 0x03
......
...@@ -898,6 +898,30 @@ static void nic_enable_vf(struct nicpf *nic, int vf, bool enable) ...@@ -898,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); 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 */ /* 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)
{ {
...@@ -1037,6 +1061,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) ...@@ -1037,6 +1061,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
case NIC_MBOX_MSG_RESET_STAT_COUNTER: case NIC_MBOX_MSG_RESET_STAT_COUNTER:
ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat); ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat);
break; break;
case NIC_MBOX_MSG_PFC:
nic_pause_frame(nic, vf, &mbx.pfc);
goto unlock;
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);
......
...@@ -720,6 +720,55 @@ static int nicvf_set_channels(struct net_device *dev, ...@@ -720,6 +720,55 @@ static int nicvf_set_channels(struct net_device *dev,
return err; 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 = { static const struct ethtool_ops nicvf_ethtool_ops = {
.get_settings = nicvf_get_settings, .get_settings = nicvf_get_settings,
.get_link = nicvf_get_link, .get_link = nicvf_get_link,
...@@ -741,6 +790,8 @@ static const struct ethtool_ops nicvf_ethtool_ops = { ...@@ -741,6 +790,8 @@ static const struct ethtool_ops nicvf_ethtool_ops = {
.set_rxfh = nicvf_set_rxfh, .set_rxfh = nicvf_set_rxfh,
.get_channels = nicvf_get_channels, .get_channels = nicvf_get_channels,
.set_channels = nicvf_set_channels, .set_channels = nicvf_set_channels,
.get_pauseparam = nicvf_get_pauseparam,
.set_pauseparam = nicvf_set_pauseparam,
.get_ts_info = ethtool_op_get_ts_info, .get_ts_info = ethtool_op_get_ts_info,
}; };
......
...@@ -256,6 +256,12 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) ...@@ -256,6 +256,12 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
nic->pnicvf = (struct nicvf *)mbx.nicvf.nicvf; nic->pnicvf = (struct nicvf *)mbx.nicvf.nicvf;
nic->pf_acked = true; nic->pf_acked = true;
break; 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: default:
netdev_err(nic->netdev, netdev_err(nic->netdev,
"Invalid message from PF, msg 0x%x\n", mbx.msg.msg); "Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
......
...@@ -212,6 +212,47 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) ...@@ -212,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); 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) static void bgx_sgmii_change_link_state(struct lmac *lmac)
{ {
struct bgx *bgx = lmac->bgx; struct bgx *bgx = lmac->bgx;
...@@ -525,6 +566,18 @@ static int bgx_lmac_xaui_init(struct bgx *bgx, struct lmac *lmac) ...@@ -525,6 +566,18 @@ static int bgx_lmac_xaui_init(struct bgx *bgx, struct lmac *lmac)
cfg |= SMU_TX_CTL_DIC_EN; cfg |= SMU_TX_CTL_DIC_EN;
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg); 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 */ /* take lmac_count into account */
bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1)); bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
/* max packet size */ /* max packet size */
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define MAX_BGX_CHANS_PER_LMAC 16 #define MAX_BGX_CHANS_PER_LMAC 16
#define MAX_DMAC_PER_LMAC 8 #define MAX_DMAC_PER_LMAC 8
#define MAX_FRAME_SIZE 9216 #define MAX_FRAME_SIZE 9216
#define DEFAULT_PAUSE_TIME 0xFFFF
#define BGX_ID_MASK 0x3 #define BGX_ID_MASK 0x3
...@@ -126,7 +127,10 @@ ...@@ -126,7 +127,10 @@
#define SMU_RX_CTL_STATUS (3ull << 0) #define SMU_RX_CTL_STATUS (3ull << 0)
#define BGX_SMUX_TX_APPEND 0x20100 #define BGX_SMUX_TX_APPEND 0x20100
#define SMU_TX_APPEND_FCS_D BIT_ULL(2) #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_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_INT 0x20140
#define BGX_SMUX_TX_CTL 0x20178 #define BGX_SMUX_TX_CTL 0x20178
#define SMU_TX_CTL_DIC_EN BIT_ULL(0) #define SMU_TX_CTL_DIC_EN BIT_ULL(0)
...@@ -136,6 +140,11 @@ ...@@ -136,6 +140,11 @@
#define BGX_SMUX_CTL 0x20200 #define BGX_SMUX_CTL 0x20200
#define SMU_CTL_RX_IDLE BIT_ULL(0) #define SMU_CTL_RX_IDLE BIT_ULL(0)
#define SMU_CTL_TX_IDLE BIT_ULL(1) #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 BGX_GMP_PCS_MRX_CTL 0x30000
#define PCS_MRX_CTL_RST_AN BIT_ULL(9) #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); ...@@ -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_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status);
void bgx_lmac_internal_loopback(int node, int bgx_idx, void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable); 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_init_hw(void);
void xcv_setup_link(bool link_up, int link_speed); 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