Commit afdb9af9 authored by David S. Miller's avatar David S. Miller

Merge branch 'octeon-ethtool'

Hariprasad Kelam says:

====================
ethtool support for fec and link configuration

This series of patches add support for forward error correction(fec) and
physical link configuration. Patches 1&2 adds necessary mbox handlers for fec
mode configuration request and to fetch stats. Patch 3 registers driver
callbacks for fec mode configuration and display. Patch 4&5 adds support of mbox
handlers for configuring link parameters like speed/duplex and autoneg etc.
Patche 6&7 registers driver callbacks for physical link configuration.

Change-log:
v2:
	- Fixed review comments
	- Corrected indentation issues
        - Return -ENOMEM incase of mbox allocation failure
	- added validation for input fecparams bitmask values
        - added more comments

V3:
	- Removed inline functions
        - Make use of ethtool helpers APIs to display supported
          advertised modes
        - corrected indentation issues
        - code changes such that return early in case of failure
          to aid branch prediction
v4:
	- Corrected indentation issues
	- Use FEC_OFF if user requests for FEC_AUTO mode
	- Do not clear fec stats in case of user changes
	  fec mode
	- dont hide fec stats depending on interface mode
	  selection
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1fb3ca76 cff713ce
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
...@@ -340,6 +341,60 @@ int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat) ...@@ -340,6 +341,60 @@ int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat)
return 0; return 0;
} }
static int cgx_set_fec_stats_count(struct cgx_link_user_info *linfo)
{
if (!linfo->fec)
return 0;
switch (linfo->lmac_type_id) {
case LMAC_MODE_SGMII:
case LMAC_MODE_XAUI:
case LMAC_MODE_RXAUI:
case LMAC_MODE_QSGMII:
return 0;
case LMAC_MODE_10G_R:
case LMAC_MODE_25G_R:
case LMAC_MODE_100G_R:
case LMAC_MODE_USXGMII:
return 1;
case LMAC_MODE_40G_R:
return 4;
case LMAC_MODE_50G_R:
if (linfo->fec == OTX2_FEC_BASER)
return 2;
else
return 1;
default:
return 0;
}
}
int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp)
{
int stats, fec_stats_count = 0;
int corr_reg, uncorr_reg;
struct cgx *cgx = cgxd;
if (!cgx || lmac_id >= cgx->lmac_count)
return -ENODEV;
fec_stats_count =
cgx_set_fec_stats_count(&cgx->lmac_idmap[lmac_id]->link_info);
if (cgx->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_BASER) {
corr_reg = CGXX_SPUX_LNX_FEC_CORR_BLOCKS;
uncorr_reg = CGXX_SPUX_LNX_FEC_UNCORR_BLOCKS;
} else {
corr_reg = CGXX_SPUX_RSFEC_CORR;
uncorr_reg = CGXX_SPUX_RSFEC_UNCORR;
}
for (stats = 0; stats < fec_stats_count; stats++) {
rsp->fec_corr_blks +=
cgx_read(cgx, lmac_id, corr_reg + (stats * 8));
rsp->fec_uncorr_blks +=
cgx_read(cgx, lmac_id, uncorr_reg + (stats * 8));
}
return 0;
}
int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
{ {
struct cgx *cgx = cgxd; struct cgx *cgx = cgxd;
...@@ -592,6 +647,7 @@ static inline void cgx_link_usertable_init(void) ...@@ -592,6 +647,7 @@ static inline void cgx_link_usertable_init(void)
cgx_speed_mbps[CGX_LINK_25G] = 25000; cgx_speed_mbps[CGX_LINK_25G] = 25000;
cgx_speed_mbps[CGX_LINK_40G] = 40000; cgx_speed_mbps[CGX_LINK_40G] = 40000;
cgx_speed_mbps[CGX_LINK_50G] = 50000; cgx_speed_mbps[CGX_LINK_50G] = 50000;
cgx_speed_mbps[CGX_LINK_80G] = 80000;
cgx_speed_mbps[CGX_LINK_100G] = 100000; cgx_speed_mbps[CGX_LINK_100G] = 100000;
cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII"; cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII";
...@@ -606,6 +662,143 @@ static inline void cgx_link_usertable_init(void) ...@@ -606,6 +662,143 @@ static inline void cgx_link_usertable_init(void)
cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII"; cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII";
} }
static int cgx_link_usertable_index_map(int speed)
{
switch (speed) {
case SPEED_10:
return CGX_LINK_10M;
case SPEED_100:
return CGX_LINK_100M;
case SPEED_1000:
return CGX_LINK_1G;
case SPEED_2500:
return CGX_LINK_2HG;
case SPEED_5000:
return CGX_LINK_5G;
case SPEED_10000:
return CGX_LINK_10G;
case SPEED_20000:
return CGX_LINK_20G;
case SPEED_25000:
return CGX_LINK_25G;
case SPEED_40000:
return CGX_LINK_40G;
case SPEED_50000:
return CGX_LINK_50G;
case 80000:
return CGX_LINK_80G;
case SPEED_100000:
return CGX_LINK_100G;
case SPEED_UNKNOWN:
return CGX_LINK_NONE;
}
return CGX_LINK_NONE;
}
static void set_mod_args(struct cgx_set_link_mode_args *args,
u32 speed, u8 duplex, u8 autoneg, u64 mode)
{
/* Fill default values incase of user did not pass
* valid parameters
*/
if (args->duplex == DUPLEX_UNKNOWN)
args->duplex = duplex;
if (args->speed == SPEED_UNKNOWN)
args->speed = speed;
if (args->an == AUTONEG_UNKNOWN)
args->an = autoneg;
args->mode = mode;
args->ports = 0;
}
static void otx2_map_ethtool_link_modes(u64 bitmask,
struct cgx_set_link_mode_args *args)
{
switch (bitmask) {
case ETHTOOL_LINK_MODE_10baseT_Half_BIT:
set_mod_args(args, 10, 1, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_10baseT_Full_BIT:
set_mod_args(args, 10, 0, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_100baseT_Half_BIT:
set_mod_args(args, 100, 1, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_100baseT_Full_BIT:
set_mod_args(args, 100, 0, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_1000baseT_Half_BIT:
set_mod_args(args, 1000, 1, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_1000baseT_Full_BIT:
set_mod_args(args, 1000, 0, 1, BIT_ULL(CGX_MODE_SGMII));
break;
case ETHTOOL_LINK_MODE_1000baseX_Full_BIT:
set_mod_args(args, 1000, 0, 0, BIT_ULL(CGX_MODE_1000_BASEX));
break;
case ETHTOOL_LINK_MODE_10000baseT_Full_BIT:
set_mod_args(args, 1000, 0, 1, BIT_ULL(CGX_MODE_QSGMII));
break;
case ETHTOOL_LINK_MODE_10000baseSR_Full_BIT:
set_mod_args(args, 10000, 0, 0, BIT_ULL(CGX_MODE_10G_C2C));
break;
case ETHTOOL_LINK_MODE_10000baseLR_Full_BIT:
set_mod_args(args, 10000, 0, 0, BIT_ULL(CGX_MODE_10G_C2M));
break;
case ETHTOOL_LINK_MODE_10000baseKR_Full_BIT:
set_mod_args(args, 10000, 0, 1, BIT_ULL(CGX_MODE_10G_KR));
break;
case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
set_mod_args(args, 25000, 0, 0, BIT_ULL(CGX_MODE_25G_C2C));
break;
case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
set_mod_args(args, 25000, 0, 1, BIT_ULL(CGX_MODE_25G_CR));
break;
case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
set_mod_args(args, 25000, 0, 1, BIT_ULL(CGX_MODE_25G_KR));
break;
case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
set_mod_args(args, 40000, 0, 0, BIT_ULL(CGX_MODE_40G_C2C));
break;
case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
set_mod_args(args, 40000, 0, 0, BIT_ULL(CGX_MODE_40G_C2M));
break;
case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
set_mod_args(args, 40000, 0, 1, BIT_ULL(CGX_MODE_40G_CR4));
break;
case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
set_mod_args(args, 40000, 0, 1, BIT_ULL(CGX_MODE_40G_KR4));
break;
case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
set_mod_args(args, 50000, 0, 0, BIT_ULL(CGX_MODE_50G_C2C));
break;
case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
set_mod_args(args, 50000, 0, 0, BIT_ULL(CGX_MODE_50G_C2M));
break;
case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
set_mod_args(args, 50000, 0, 1, BIT_ULL(CGX_MODE_50G_CR));
break;
case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
set_mod_args(args, 50000, 0, 1, BIT_ULL(CGX_MODE_50G_KR));
break;
case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
set_mod_args(args, 100000, 0, 0, BIT_ULL(CGX_MODE_100G_C2C));
break;
case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
set_mod_args(args, 100000, 0, 0, BIT_ULL(CGX_MODE_100G_C2M));
break;
case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
set_mod_args(args, 100000, 0, 1, BIT_ULL(CGX_MODE_100G_CR4));
break;
case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
set_mod_args(args, 100000, 0, 1, BIT_ULL(CGX_MODE_100G_KR4));
break;
default:
set_mod_args(args, 0, 1, 0, BIT_ULL(CGX_MODE_MAX));
break;
}
}
static inline void link_status_user_format(u64 lstat, static inline void link_status_user_format(u64 lstat,
struct cgx_link_user_info *linfo, struct cgx_link_user_info *linfo,
struct cgx *cgx, u8 lmac_id) struct cgx *cgx, u8 lmac_id)
...@@ -615,6 +808,8 @@ static inline void link_status_user_format(u64 lstat, ...@@ -615,6 +808,8 @@ static inline void link_status_user_format(u64 lstat,
linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)]; linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat);
linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat);
linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id); linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id);
lmac_string = cgx_lmactype_string[linfo->lmac_type_id]; lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1); strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
...@@ -642,6 +837,9 @@ static inline void cgx_link_change_handler(u64 lstat, ...@@ -642,6 +837,9 @@ static inline void cgx_link_change_handler(u64 lstat,
lmac->link_info = event.link_uinfo; lmac->link_info = event.link_uinfo;
linfo = &lmac->link_info; linfo = &lmac->link_info;
if (err_type == CGX_ERR_SPEED_CHANGE_INVALID)
return;
/* Ensure callback doesn't get unregistered until we finish it */ /* Ensure callback doesn't get unregistered until we finish it */
spin_lock(&lmac->event_cb_lock); spin_lock(&lmac->event_cb_lock);
...@@ -670,7 +868,8 @@ static inline bool cgx_cmdresp_is_linkevent(u64 event) ...@@ -670,7 +868,8 @@ static inline bool cgx_cmdresp_is_linkevent(u64 event)
id = FIELD_GET(EVTREG_ID, event); id = FIELD_GET(EVTREG_ID, event);
if (id == CGX_CMD_LINK_BRING_UP || if (id == CGX_CMD_LINK_BRING_UP ||
id == CGX_CMD_LINK_BRING_DOWN) id == CGX_CMD_LINK_BRING_DOWN ||
id == CGX_CMD_MODE_CHANGE)
return true; return true;
else else
return false; return false;
...@@ -785,6 +984,63 @@ int cgx_get_fwdata_base(u64 *base) ...@@ -785,6 +984,63 @@ int cgx_get_fwdata_base(u64 *base)
return err; return err;
} }
int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
int cgx_id, int lmac_id)
{
struct cgx *cgx = cgxd;
u64 req = 0, resp;
if (!cgx)
return -ENODEV;
if (args.mode)
otx2_map_ethtool_link_modes(args.mode, &args);
if (!args.speed && args.duplex && !args.an)
return -EINVAL;
req = FIELD_SET(CMDREG_ID, CGX_CMD_MODE_CHANGE, req);
req = FIELD_SET(CMDMODECHANGE_SPEED,
cgx_link_usertable_index_map(args.speed), req);
req = FIELD_SET(CMDMODECHANGE_DUPLEX, args.duplex, req);
req = FIELD_SET(CMDMODECHANGE_AN, args.an, req);
req = FIELD_SET(CMDMODECHANGE_PORT, args.ports, req);
req = FIELD_SET(CMDMODECHANGE_FLAGS, args.mode, req);
return cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id);
}
int cgx_set_fec(u64 fec, int cgx_id, int lmac_id)
{
u64 req = 0, resp;
struct cgx *cgx;
int err = 0;
cgx = cgx_get_pdata(cgx_id);
if (!cgx)
return -ENXIO;
req = FIELD_SET(CMDREG_ID, CGX_CMD_SET_FEC, req);
req = FIELD_SET(CMDSETFEC, fec, req);
err = cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id);
if (err)
return err;
cgx->lmac_idmap[lmac_id]->link_info.fec =
FIELD_GET(RESP_LINKSTAT_FEC, resp);
return cgx->lmac_idmap[lmac_id]->link_info.fec;
}
int cgx_get_phy_fec_stats(void *cgxd, int lmac_id)
{
struct cgx *cgx = cgxd;
u64 req = 0, resp;
if (!cgx)
return -ENODEV;
req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_PHY_FEC_STATS, req);
return cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id);
}
static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable) static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable)
{ {
u64 req = 0; u64 req = 0;
......
...@@ -56,6 +56,11 @@ ...@@ -56,6 +56,11 @@
#define CGXX_SCRATCH1_REG 0x1058 #define CGXX_SCRATCH1_REG 0x1058
#define CGX_CONST 0x2000 #define CGX_CONST 0x2000
#define CGXX_SPUX_CONTROL1 0x10000 #define CGXX_SPUX_CONTROL1 0x10000
#define CGXX_SPUX_LNX_FEC_CORR_BLOCKS 0x10700
#define CGXX_SPUX_LNX_FEC_UNCORR_BLOCKS 0x10800
#define CGXX_SPUX_RSFEC_CORR 0x10088
#define CGXX_SPUX_RSFEC_UNCORR 0x10090
#define CGXX_SPUX_CONTROL1_LBK BIT_ULL(14) #define CGXX_SPUX_CONTROL1_LBK BIT_ULL(14)
#define CGXX_GMP_PCS_MRX_CTL 0x30000 #define CGXX_GMP_PCS_MRX_CTL 0x30000
#define CGXX_GMP_PCS_MRX_CTL_LBK BIT_ULL(14) #define CGXX_GMP_PCS_MRX_CTL_LBK BIT_ULL(14)
...@@ -147,5 +152,10 @@ int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id, ...@@ -147,5 +152,10 @@ int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id,
u8 tx_pause, u8 rx_pause); u8 tx_pause, u8 rx_pause);
void cgx_lmac_ptp_config(void *cgxd, int lmac_id, bool enable); void cgx_lmac_ptp_config(void *cgxd, int lmac_id, bool enable);
u8 cgx_lmac_get_p2x(int cgx_id, int lmac_id); u8 cgx_lmac_get_p2x(int cgx_id, int lmac_id);
int cgx_set_fec(u64 fec, int cgx_id, int lmac_id);
int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp);
int cgx_get_phy_fec_stats(void *cgxd, int lmac_id);
int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
int cgx_id, int lmac_id);
#endif /* CGX_H */ #endif /* CGX_H */
...@@ -43,7 +43,13 @@ enum cgx_error_type { ...@@ -43,7 +43,13 @@ enum cgx_error_type {
CGX_ERR_TRAINING_FAIL, CGX_ERR_TRAINING_FAIL,
CGX_ERR_RX_EQU_FAIL, CGX_ERR_RX_EQU_FAIL,
CGX_ERR_SPUX_BER_FAIL, CGX_ERR_SPUX_BER_FAIL,
CGX_ERR_SPUX_RSFEC_ALGN_FAIL, /* = 22 */ CGX_ERR_SPUX_RSFEC_ALGN_FAIL,
CGX_ERR_SPUX_MARKER_LOCK_FAIL,
CGX_ERR_SET_FEC_INVALID,
CGX_ERR_SET_FEC_FAIL,
CGX_ERR_MODULE_INVALID,
CGX_ERR_MODULE_NOT_PRESENT,
CGX_ERR_SPEED_CHANGE_INVALID,
}; };
/* LINK speed types */ /* LINK speed types */
...@@ -59,10 +65,41 @@ enum cgx_link_speed { ...@@ -59,10 +65,41 @@ enum cgx_link_speed {
CGX_LINK_25G, CGX_LINK_25G,
CGX_LINK_40G, CGX_LINK_40G,
CGX_LINK_50G, CGX_LINK_50G,
CGX_LINK_80G,
CGX_LINK_100G, CGX_LINK_100G,
CGX_LINK_SPEED_MAX, CGX_LINK_SPEED_MAX,
}; };
enum CGX_MODE_ {
CGX_MODE_SGMII,
CGX_MODE_1000_BASEX,
CGX_MODE_QSGMII,
CGX_MODE_10G_C2C,
CGX_MODE_10G_C2M,
CGX_MODE_10G_KR,
CGX_MODE_20G_C2C,
CGX_MODE_25G_C2C,
CGX_MODE_25G_C2M,
CGX_MODE_25G_2_C2C,
CGX_MODE_25G_CR,
CGX_MODE_25G_KR,
CGX_MODE_40G_C2C,
CGX_MODE_40G_C2M,
CGX_MODE_40G_CR4,
CGX_MODE_40G_KR4,
CGX_MODE_40GAUI_C2C,
CGX_MODE_50G_C2C,
CGX_MODE_50G_C2M,
CGX_MODE_50G_4_C2C,
CGX_MODE_50G_CR,
CGX_MODE_50G_KR,
CGX_MODE_80GAUI_C2C,
CGX_MODE_100G_C2C,
CGX_MODE_100G_C2M,
CGX_MODE_100G_CR4,
CGX_MODE_100G_KR4,
CGX_MODE_MAX /* = 29 */
};
/* REQUEST ID types. Input to firmware */ /* REQUEST ID types. Input to firmware */
enum cgx_cmd_id { enum cgx_cmd_id {
CGX_CMD_NONE, CGX_CMD_NONE,
...@@ -75,12 +112,25 @@ enum cgx_cmd_id { ...@@ -75,12 +112,25 @@ enum cgx_cmd_id {
CGX_CMD_INTERNAL_LBK, CGX_CMD_INTERNAL_LBK,
CGX_CMD_EXTERNAL_LBK, CGX_CMD_EXTERNAL_LBK,
CGX_CMD_HIGIG, CGX_CMD_HIGIG,
CGX_CMD_LINK_STATE_CHANGE, CGX_CMD_LINK_STAT_CHANGE,
CGX_CMD_MODE_CHANGE, /* hot plug support */ CGX_CMD_MODE_CHANGE, /* hot plug support */
CGX_CMD_INTF_SHUTDOWN, CGX_CMD_INTF_SHUTDOWN,
CGX_CMD_GET_MKEX_PRFL_SIZE, CGX_CMD_GET_MKEX_PRFL_SIZE,
CGX_CMD_GET_MKEX_PRFL_ADDR, CGX_CMD_GET_MKEX_PRFL_ADDR,
CGX_CMD_GET_FWD_BASE, /* get base address of shared FW data */ CGX_CMD_GET_FWD_BASE, /* get base address of shared FW data */
CGX_CMD_GET_LINK_MODES, /* Supported Link Modes */
CGX_CMD_SET_LINK_MODE,
CGX_CMD_GET_SUPPORTED_FEC,
CGX_CMD_SET_FEC,
CGX_CMD_GET_AN,
CGX_CMD_SET_AN,
CGX_CMD_GET_ADV_LINK_MODES,
CGX_CMD_GET_ADV_FEC,
CGX_CMD_GET_PHY_MOD_TYPE, /* line-side modulation type: NRZ or PAM4 */
CGX_CMD_SET_PHY_MOD_TYPE,
CGX_CMD_PRBS,
CGX_CMD_DISPLAY_EYE,
CGX_CMD_GET_PHY_FEC_STATS,
}; };
/* async event ids */ /* async event ids */
...@@ -171,13 +221,19 @@ struct cgx_lnk_sts { ...@@ -171,13 +221,19 @@ struct cgx_lnk_sts {
uint64_t full_duplex:1; uint64_t full_duplex:1;
uint64_t speed:4; /* cgx_link_speed */ uint64_t speed:4; /* cgx_link_speed */
uint64_t err_type:10; uint64_t err_type:10;
uint64_t reserved2:39; uint64_t an:1; /* AN supported or not */
uint64_t fec:2; /* FEC type if enabled, if not 0 */
uint64_t port:8;
uint64_t reserved2:28;
}; };
#define RESP_LINKSTAT_UP GENMASK_ULL(9, 9) #define RESP_LINKSTAT_UP GENMASK_ULL(9, 9)
#define RESP_LINKSTAT_FDUPLEX GENMASK_ULL(10, 10) #define RESP_LINKSTAT_FDUPLEX GENMASK_ULL(10, 10)
#define RESP_LINKSTAT_SPEED GENMASK_ULL(14, 11) #define RESP_LINKSTAT_SPEED GENMASK_ULL(14, 11)
#define RESP_LINKSTAT_ERRTYPE GENMASK_ULL(24, 15) #define RESP_LINKSTAT_ERRTYPE GENMASK_ULL(24, 15)
#define RESP_LINKSTAT_AN GENMASK_ULL(25, 25)
#define RESP_LINKSTAT_FEC GENMASK_ULL(27, 26)
#define RESP_LINKSTAT_PORT GENMASK_ULL(35, 28)
/* scratchx(1) CSR used for non-secure SW->ATF communication /* scratchx(1) CSR used for non-secure SW->ATF communication
* This CSR acts as a command register * This CSR acts as a command register
...@@ -199,4 +255,12 @@ struct cgx_lnk_sts { ...@@ -199,4 +255,12 @@ struct cgx_lnk_sts {
#define CMDLINKCHANGE_FULLDPLX BIT_ULL(9) #define CMDLINKCHANGE_FULLDPLX BIT_ULL(9)
#define CMDLINKCHANGE_SPEED GENMASK_ULL(13, 10) #define CMDLINKCHANGE_SPEED GENMASK_ULL(13, 10)
#define CMDSETFEC GENMASK_ULL(9, 8)
/* command argument to be passed for cmd ID - CGX_CMD_MODE_CHANGE */
#define CMDMODECHANGE_SPEED GENMASK_ULL(11, 8)
#define CMDMODECHANGE_DUPLEX GENMASK_ULL(12, 12)
#define CMDMODECHANGE_AN GENMASK_ULL(13, 13)
#define CMDMODECHANGE_PORT GENMASK_ULL(21, 14)
#define CMDMODECHANGE_FLAGS GENMASK_ULL(63, 22)
#endif /* __CGX_FW_INTF_H__ */ #endif /* __CGX_FW_INTF_H__ */
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull)) #define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull))
#define MBOX_RSP_TIMEOUT 2000 /* Time(ms) to wait for mbox response */ #define MBOX_RSP_TIMEOUT 3000 /* Time(ms) to wait for mbox response */
#define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */ #define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */
...@@ -149,6 +149,13 @@ M(CGX_PTP_RX_ENABLE, 0x20C, cgx_ptp_rx_enable, msg_req, msg_rsp) \ ...@@ -149,6 +149,13 @@ M(CGX_PTP_RX_ENABLE, 0x20C, cgx_ptp_rx_enable, msg_req, msg_rsp) \
M(CGX_PTP_RX_DISABLE, 0x20D, cgx_ptp_rx_disable, msg_req, msg_rsp) \ M(CGX_PTP_RX_DISABLE, 0x20D, cgx_ptp_rx_disable, msg_req, msg_rsp) \
M(CGX_CFG_PAUSE_FRM, 0x20E, cgx_cfg_pause_frm, cgx_pause_frm_cfg, \ M(CGX_CFG_PAUSE_FRM, 0x20E, cgx_cfg_pause_frm, cgx_pause_frm_cfg, \
cgx_pause_frm_cfg) \ cgx_pause_frm_cfg) \
M(CGX_FEC_SET, 0x210, cgx_set_fec_param, fec_mode, fec_mode) \
M(CGX_FEC_STATS, 0x211, cgx_fec_stats, msg_req, cgx_fec_stats_rsp) \
M(CGX_GET_PHY_FEC_STATS, 0x212, cgx_get_phy_fec_stats, msg_req, msg_rsp) \
M(CGX_FW_DATA_GET, 0x213, cgx_get_aux_link_info, msg_req, cgx_fw_data) \
M(CGX_SET_LINK_MODE, 0x214, cgx_set_link_mode, cgx_set_link_mode_req,\
cgx_set_link_mode_rsp) \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \
M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \ M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \
npa_lf_alloc_req, npa_lf_alloc_rsp) \ npa_lf_alloc_req, npa_lf_alloc_rsp) \
...@@ -360,6 +367,11 @@ struct cgx_stats_rsp { ...@@ -360,6 +367,11 @@ struct cgx_stats_rsp {
u64 tx_stats[CGX_TX_STATS_COUNT]; u64 tx_stats[CGX_TX_STATS_COUNT];
}; };
struct cgx_fec_stats_rsp {
struct mbox_msghdr hdr;
u64 fec_corr_blks;
u64 fec_uncorr_blks;
};
/* Structure for requesting the operation for /* Structure for requesting the operation for
* setting/getting mac address in the CGX interface * setting/getting mac address in the CGX interface
*/ */
...@@ -373,6 +385,8 @@ struct cgx_link_user_info { ...@@ -373,6 +385,8 @@ struct cgx_link_user_info {
uint64_t full_duplex:1; uint64_t full_duplex:1;
uint64_t lmac_type_id:4; uint64_t lmac_type_id:4;
uint64_t speed:20; /* speed in Mbps */ uint64_t speed:20; /* speed in Mbps */
uint64_t an:1; /* AN supported or not */
uint64_t fec:2; /* FEC type if enabled else 0 */
#define LMACTYPE_STR_LEN 16 #define LMACTYPE_STR_LEN 16
char lmac_type[LMACTYPE_STR_LEN]; char lmac_type[LMACTYPE_STR_LEN];
}; };
...@@ -391,6 +405,79 @@ struct cgx_pause_frm_cfg { ...@@ -391,6 +405,79 @@ struct cgx_pause_frm_cfg {
u8 tx_pause; u8 tx_pause;
}; };
enum fec_type {
OTX2_FEC_NONE,
OTX2_FEC_BASER,
OTX2_FEC_RS,
OTX2_FEC_STATS_CNT = 2,
OTX2_FEC_OFF,
};
struct fec_mode {
struct mbox_msghdr hdr;
int fec;
};
struct sfp_eeprom_s {
#define SFP_EEPROM_SIZE 256
u16 sff_id;
u8 buf[SFP_EEPROM_SIZE];
u64 reserved;
};
struct phy_s {
struct {
u64 can_change_mod_type:1;
u64 mod_type:1;
u64 has_fec_stats:1;
} misc;
struct fec_stats_s {
u32 rsfec_corr_cws;
u32 rsfec_uncorr_cws;
u32 brfec_corr_blks;
u32 brfec_uncorr_blks;
} fec_stats;
};
struct cgx_lmac_fwdata_s {
u16 rw_valid;
u64 supported_fec;
u64 supported_an;
u64 supported_link_modes;
/* only applicable if AN is supported */
u64 advertised_fec;
u64 advertised_link_modes;
/* Only applicable if SFP/QSFP slot is present */
struct sfp_eeprom_s sfp_eeprom;
struct phy_s phy;
#define LMAC_FWDATA_RESERVED_MEM 1021
u64 reserved[LMAC_FWDATA_RESERVED_MEM];
};
struct cgx_fw_data {
struct mbox_msghdr hdr;
struct cgx_lmac_fwdata_s fwdata;
};
struct cgx_set_link_mode_args {
u32 speed;
u8 duplex;
u8 an;
u8 ports;
u64 mode;
};
struct cgx_set_link_mode_req {
#define AUTONEG_UNKNOWN 0xff
struct mbox_msghdr hdr;
struct cgx_set_link_mode_args args;
};
struct cgx_set_link_mode_rsp {
struct mbox_msghdr hdr;
int status;
};
/* NPA mbox message formats */ /* NPA mbox message formats */
/* NPA mailbox error codes /* NPA mailbox error codes
......
...@@ -357,6 +357,10 @@ struct rvu_fwdata { ...@@ -357,6 +357,10 @@ struct rvu_fwdata {
u64 msixtr_base; u64 msixtr_base;
#define FWDATA_RESERVED_MEM 1023 #define FWDATA_RESERVED_MEM 1023
u64 reserved[FWDATA_RESERVED_MEM]; u64 reserved[FWDATA_RESERVED_MEM];
#define CGX_MAX 5
#define CGX_LMACS_MAX 4
struct cgx_lmac_fwdata_s cgx_fw_data[CGX_MAX][CGX_LMACS_MAX];
/* Do not add new fields below this line */
}; };
struct ptp; struct ptp;
......
...@@ -462,6 +462,22 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req, ...@@ -462,6 +462,22 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req,
return 0; return 0;
} }
int rvu_mbox_handler_cgx_fec_stats(struct rvu *rvu,
struct msg_req *req,
struct cgx_fec_stats_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_idx, lmac;
void *cgxd;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
cgxd = rvu_cgx_pdata(cgx_idx, rvu);
return cgx_get_fec_stats(cgxd, lmac, rsp);
}
int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu, int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
struct cgx_mac_addr_set_or_get *req, struct cgx_mac_addr_set_or_get *req,
struct cgx_mac_addr_set_or_get *rsp) struct cgx_mac_addr_set_or_get *rsp)
...@@ -676,6 +692,19 @@ int rvu_mbox_handler_cgx_cfg_pause_frm(struct rvu *rvu, ...@@ -676,6 +692,19 @@ int rvu_mbox_handler_cgx_cfg_pause_frm(struct rvu *rvu,
return 0; return 0;
} }
int rvu_mbox_handler_cgx_get_phy_fec_stats(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!is_pf_cgxmapped(rvu, pf))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
return cgx_get_phy_fec_stats(rvu_cgx_pdata(cgx_id, rvu), lmac_id);
}
/* Finds cumulative status of NIX rx/tx counters from LF of a PF and those /* Finds cumulative status of NIX rx/tx counters from LF of a PF and those
* from its VFs as well. ie. NIX rx/tx counters at the CGX port level * from its VFs as well. ie. NIX rx/tx counters at the CGX port level
*/ */
...@@ -767,3 +796,56 @@ int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start) ...@@ -767,3 +796,56 @@ int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start)
mutex_unlock(&rvu->cgx_cfg_lock); mutex_unlock(&rvu->cgx_cfg_lock);
return err; return err;
} }
int rvu_mbox_handler_cgx_set_fec_param(struct rvu *rvu,
struct fec_mode *req,
struct fec_mode *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!is_pf_cgxmapped(rvu, pf))
return -EPERM;
if (req->fec == OTX2_FEC_OFF)
req->fec = OTX2_FEC_NONE;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
rsp->fec = cgx_set_fec(req->fec, cgx_id, lmac_id);
return 0;
}
int rvu_mbox_handler_cgx_get_aux_link_info(struct rvu *rvu, struct msg_req *req,
struct cgx_fw_data *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!rvu->fwdata)
return -ENXIO;
if (!is_pf_cgxmapped(rvu, pf))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
memcpy(&rsp->fwdata, &rvu->fwdata->cgx_fw_data[cgx_id][lmac_id],
sizeof(struct cgx_lmac_fwdata_s));
return 0;
}
int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
struct cgx_set_link_mode_req *req,
struct cgx_set_link_mode_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_idx, lmac;
void *cgxd;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
cgxd = rvu_cgx_pdata(cgx_idx, rvu);
rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac);
return 0;
}
...@@ -60,6 +60,19 @@ void otx2_update_lmac_stats(struct otx2_nic *pfvf) ...@@ -60,6 +60,19 @@ void otx2_update_lmac_stats(struct otx2_nic *pfvf)
mutex_unlock(&pfvf->mbox.lock); mutex_unlock(&pfvf->mbox.lock);
} }
void otx2_update_lmac_fec_stats(struct otx2_nic *pfvf)
{
struct msg_req *req;
if (!netif_running(pfvf->netdev))
return;
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_fec_stats(&pfvf->mbox);
if (req)
otx2_sync_mbox_msg(&pfvf->mbox);
mutex_unlock(&pfvf->mbox.lock);
}
int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx) int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx)
{ {
struct otx2_rcv_queue *rq = &pfvf->qset.rq[qidx]; struct otx2_rcv_queue *rq = &pfvf->qset.rq[qidx];
...@@ -1489,6 +1502,13 @@ void mbox_handler_cgx_stats(struct otx2_nic *pfvf, ...@@ -1489,6 +1502,13 @@ void mbox_handler_cgx_stats(struct otx2_nic *pfvf,
pfvf->hw.cgx_tx_stats[id] = rsp->tx_stats[id]; pfvf->hw.cgx_tx_stats[id] = rsp->tx_stats[id];
} }
void mbox_handler_cgx_fec_stats(struct otx2_nic *pfvf,
struct cgx_fec_stats_rsp *rsp)
{
pfvf->hw.cgx_fec_corr_blks += rsp->fec_corr_blks;
pfvf->hw.cgx_fec_uncorr_blks += rsp->fec_uncorr_blks;
}
void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf, void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf,
struct nix_txsch_alloc_rsp *rsp) struct nix_txsch_alloc_rsp *rsp)
{ {
......
...@@ -204,6 +204,8 @@ struct otx2_hw { ...@@ -204,6 +204,8 @@ struct otx2_hw {
struct otx2_drv_stats drv_stats; struct otx2_drv_stats drv_stats;
u64 cgx_rx_stats[CGX_RX_STATS_COUNT]; u64 cgx_rx_stats[CGX_RX_STATS_COUNT];
u64 cgx_tx_stats[CGX_TX_STATS_COUNT]; u64 cgx_tx_stats[CGX_TX_STATS_COUNT];
u64 cgx_fec_corr_blks;
u64 cgx_fec_uncorr_blks;
u8 cgx_links; /* No. of CGX links present in HW */ u8 cgx_links; /* No. of CGX links present in HW */
u8 lbk_links; /* No. of LBK links present in HW */ u8 lbk_links; /* No. of LBK links present in HW */
}; };
...@@ -661,6 +663,9 @@ void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf, ...@@ -661,6 +663,9 @@ void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf,
struct nix_txsch_alloc_rsp *rsp); struct nix_txsch_alloc_rsp *rsp);
void mbox_handler_cgx_stats(struct otx2_nic *pfvf, void mbox_handler_cgx_stats(struct otx2_nic *pfvf,
struct cgx_stats_rsp *rsp); struct cgx_stats_rsp *rsp);
void mbox_handler_cgx_fec_stats(struct otx2_nic *pfvf,
struct cgx_fec_stats_rsp *rsp);
void otx2_set_fec_stats_count(struct otx2_nic *pfvf);
void mbox_handler_nix_bp_enable(struct otx2_nic *pfvf, void mbox_handler_nix_bp_enable(struct otx2_nic *pfvf,
struct nix_bp_cfg_rsp *rsp); struct nix_bp_cfg_rsp *rsp);
...@@ -669,6 +674,7 @@ void otx2_get_dev_stats(struct otx2_nic *pfvf); ...@@ -669,6 +674,7 @@ void otx2_get_dev_stats(struct otx2_nic *pfvf);
void otx2_get_stats64(struct net_device *netdev, void otx2_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats); struct rtnl_link_stats64 *stats);
void otx2_update_lmac_stats(struct otx2_nic *pfvf); void otx2_update_lmac_stats(struct otx2_nic *pfvf);
void otx2_update_lmac_fec_stats(struct otx2_nic *pfvf);
int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx); int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx);
int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx); int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx);
void otx2_set_ethtool_ops(struct net_device *netdev); void otx2_set_ethtool_ops(struct net_device *netdev);
......
...@@ -779,6 +779,9 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf, ...@@ -779,6 +779,9 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf,
case MBOX_MSG_CGX_STATS: case MBOX_MSG_CGX_STATS:
mbox_handler_cgx_stats(pf, (struct cgx_stats_rsp *)msg); mbox_handler_cgx_stats(pf, (struct cgx_stats_rsp *)msg);
break; break;
case MBOX_MSG_CGX_FEC_STATS:
mbox_handler_cgx_fec_stats(pf, (struct cgx_fec_stats_rsp *)msg);
break;
default: default:
if (msg->rc) if (msg->rc)
dev_err(pf->dev, dev_err(pf->dev,
......
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