net/cxgbe: support configuring link FEC

Add ethdev ops to query and configure link FEC.

Signed-off-by: Karra Satwik <kaara.satwik@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
This commit is contained in:
Karra Satwik 2020-12-21 04:17:42 +05:30 committed by Ferruh Yigit
parent a83041b1e9
commit 62aafe0358
4 changed files with 218 additions and 0 deletions

View File

@ -331,6 +331,8 @@ static inline int t4_link_l1cfg_ns(struct port_info *pi, u32 caps)
int t4_set_link_speed(struct port_info *pi, u32 speed, u32 *new_caps);
int t4_set_link_pause(struct port_info *pi, u8 autoneg, u8 pause_tx,
u8 pause_rx, u32 *new_caps);
int t4_set_link_fec(struct port_info *pi, u8 fec_rs, u8 fec_baser,
u8 fec_none, u32 *new_caps);
unsigned int t4_fwcap_to_speed(u32 caps);
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta);

View File

@ -4473,6 +4473,76 @@ int t4_set_link_pause(struct port_info *pi, u8 autoneg, u8 pause_tx,
return 0;
}
int t4_set_link_fec(struct port_info *pi, u8 fec_rs, u8 fec_baser,
u8 fec_none, u32 *new_caps)
{
struct link_config *lc = &pi->link_cfg;
u32 max_speed, caps = *new_caps;
if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)))
return -EOPNOTSUPP;
/* Link might be down. In that case consider the max
* speed advertised
*/
max_speed = t4_fwcap_to_speed(lc->link_caps);
if (!max_speed)
max_speed = t4_fwcap_to_speed(lc->acaps);
caps &= ~V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC);
if (fec_rs) {
switch (max_speed) {
case 100000:
case 25000:
caps |= FW_PORT_CAP32_FEC_RS;
break;
default:
return -EOPNOTSUPP;
}
}
if (fec_baser) {
switch (max_speed) {
case 50000:
case 25000:
caps |= FW_PORT_CAP32_FEC_BASER_RS;
break;
default:
return -EOPNOTSUPP;
}
}
if (fec_none)
caps |= FW_PORT_CAP32_FEC_NO_FEC;
if (!(caps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC))) {
/* No explicit encoding is requested.
* So, default back to AUTO.
*/
switch (max_speed) {
case 100000:
caps |= FW_PORT_CAP32_FEC_RS |
FW_PORT_CAP32_FEC_NO_FEC;
break;
case 50000:
caps |= FW_PORT_CAP32_FEC_BASER_RS |
FW_PORT_CAP32_FEC_NO_FEC;
break;
case 25000:
caps |= FW_PORT_CAP32_FEC_RS |
FW_PORT_CAP32_FEC_BASER_RS |
FW_PORT_CAP32_FEC_NO_FEC;
break;
default:
return -EOPNOTSUPP;
}
}
*new_caps = caps;
return 0;
}
/**
* t4_handle_get_port_info - process a FW reply message
* @pi: the port info
@ -4630,6 +4700,7 @@ void t4_reset_link_config(struct adapter *adap, int idx)
void t4_init_link_config(struct port_info *pi, u32 pcaps, u32 acaps,
u8 mdio_addr, u8 port_type, u8 mod_type)
{
u8 fec_rs = 0, fec_baser = 0, fec_none = 0;
struct link_config *lc = &pi->link_cfg;
lc->pcaps = pcaps;
@ -4650,6 +4721,23 @@ void t4_init_link_config(struct port_info *pi, u32 pcaps, u32 acaps,
if (lc->pcaps & FW_PORT_CAP32_FORCE_PAUSE)
lc->admin_caps &= ~FW_PORT_CAP32_FORCE_PAUSE;
/* Reset FEC caps to default values */
if (lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)) {
if (lc->acaps & FW_PORT_CAP32_FEC_RS)
fec_rs = 1;
else if (lc->acaps & FW_PORT_CAP32_FEC_BASER_RS)
fec_baser = 1;
else
fec_none = 1;
lc->admin_caps &= ~V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC);
t4_set_link_fec(pi, fec_rs, fec_baser, fec_none,
&lc->admin_caps);
}
if (lc->pcaps & FW_PORT_CAP32_FORCE_FEC)
lc->admin_caps &= ~FW_PORT_CAP32_FORCE_FEC;
/* Reset MDI to AUTO */
if (lc->pcaps & FW_PORT_CAP32_MDIAUTO) {
lc->admin_caps &= ~V_FW_PORT_CAP32_MDI(M_FW_PORT_CAP32_MDI);

View File

@ -1615,7 +1615,9 @@ struct fw_vi_stats_cmd {
#define FW_PORT_CAP32_MDIAUTO 0x00400000UL
#define FW_PORT_CAP32_FEC_RS 0x00800000UL
#define FW_PORT_CAP32_FEC_BASER_RS 0x01000000UL
#define FW_PORT_CAP32_FEC_NO_FEC 0x02000000UL
#define FW_PORT_CAP32_FORCE_PAUSE 0x10000000UL
#define FW_PORT_CAP32_FORCE_FEC 0x20000000UL
#define S_FW_PORT_CAP32_SPEED 0
#define M_FW_PORT_CAP32_SPEED 0xfff
@ -1641,6 +1643,10 @@ enum fw_port_mdi32 {
#define G_FW_PORT_CAP32_MDI(x) \
(((x) >> S_FW_PORT_CAP32_MDI) & M_FW_PORT_CAP32_MDI)
#define S_FW_PORT_CAP32_FEC 23
#define M_FW_PORT_CAP32_FEC 0x1f
#define V_FW_PORT_CAP32_FEC(x) ((x) << S_FW_PORT_CAP32_FEC)
enum fw_port_action {
FW_PORT_ACTION_L1_CFG32 = 0x0009,
FW_PORT_ACTION_GET_PORT_INFO32 = 0x000a,

View File

@ -1193,6 +1193,125 @@ int cxgbe_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *addr)
return 0;
}
static int cxgbe_fec_get_capa_speed_to_fec(struct link_config *lc,
struct rte_eth_fec_capa *capa_arr)
{
int num = 0;
if (lc->pcaps & FW_PORT_CAP32_SPEED_100G) {
if (capa_arr) {
capa_arr[num].speed = ETH_SPEED_NUM_100G;
capa_arr[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) |
RTE_ETH_FEC_MODE_CAPA_MASK(RS);
}
num++;
}
if (lc->pcaps & FW_PORT_CAP32_SPEED_50G) {
if (capa_arr) {
capa_arr[num].speed = ETH_SPEED_NUM_50G;
capa_arr[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) |
RTE_ETH_FEC_MODE_CAPA_MASK(BASER);
}
num++;
}
if (lc->pcaps & FW_PORT_CAP32_SPEED_25G) {
if (capa_arr) {
capa_arr[num].speed = ETH_SPEED_NUM_25G;
capa_arr[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) |
RTE_ETH_FEC_MODE_CAPA_MASK(BASER) |
RTE_ETH_FEC_MODE_CAPA_MASK(RS);
}
num++;
}
return num;
}
static int cxgbe_fec_get_capability(struct rte_eth_dev *dev,
struct rte_eth_fec_capa *speed_fec_capa,
unsigned int num)
{
struct port_info *pi = dev->data->dev_private;
struct link_config *lc = &pi->link_cfg;
u8 num_entries;
if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)))
return -EOPNOTSUPP;
num_entries = cxgbe_fec_get_capa_speed_to_fec(lc, NULL);
if (!speed_fec_capa || num < num_entries)
return num_entries;
return cxgbe_fec_get_capa_speed_to_fec(lc, speed_fec_capa);
}
static int cxgbe_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa)
{
struct port_info *pi = dev->data->dev_private;
struct link_config *lc = &pi->link_cfg;
u32 fec_caps = 0, caps = lc->link_caps;
if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)))
return -EOPNOTSUPP;
if (caps & FW_PORT_CAP32_FEC_RS)
fec_caps = RTE_ETH_FEC_MODE_CAPA_MASK(RS);
else if (caps & FW_PORT_CAP32_FEC_BASER_RS)
fec_caps = RTE_ETH_FEC_MODE_CAPA_MASK(BASER);
else
fec_caps = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC);
*fec_capa = fec_caps;
return 0;
}
static int cxgbe_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa)
{
struct port_info *pi = dev->data->dev_private;
u8 fec_rs = 0, fec_baser = 0, fec_none = 0;
struct link_config *lc = &pi->link_cfg;
u32 new_caps = lc->admin_caps;
int ret;
if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)))
return -EOPNOTSUPP;
if (!fec_capa)
return -EINVAL;
if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(AUTO))
goto set_fec;
if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC))
fec_none = 1;
if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(BASER))
fec_baser = 1;
if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(RS))
fec_rs = 1;
set_fec:
ret = t4_set_link_fec(pi, fec_rs, fec_baser, fec_none, &new_caps);
if (ret != 0)
return ret;
if (lc->pcaps & FW_PORT_CAP32_FORCE_FEC)
new_caps |= FW_PORT_CAP32_FORCE_FEC;
else
new_caps &= ~FW_PORT_CAP32_FORCE_FEC;
if (new_caps != lc->admin_caps) {
ret = t4_link_l1cfg(pi, new_caps);
if (ret == 0)
lc->admin_caps = new_caps;
}
return ret;
}
static const struct eth_dev_ops cxgbe_eth_dev_ops = {
.dev_start = cxgbe_dev_start,
.dev_stop = cxgbe_dev_stop,
@ -1230,6 +1349,9 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
.mac_addr_set = cxgbe_mac_addr_set,
.reta_update = cxgbe_dev_rss_reta_update,
.reta_query = cxgbe_dev_rss_reta_query,
.fec_get_capability = cxgbe_fec_get_capability,
.fec_get = cxgbe_fec_get,
.fec_set = cxgbe_fec_set,
};
/*