mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-04 02:02:28 +09:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/of.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)
|
||||
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)
|
||||
{
|
||||
struct cgx *cgx = cgxd;
|
||||
@@ -592,6 +647,7 @@ static inline void cgx_link_usertable_init(void)
|
||||
cgx_speed_mbps[CGX_LINK_25G] = 25000;
|
||||
cgx_speed_mbps[CGX_LINK_40G] = 40000;
|
||||
cgx_speed_mbps[CGX_LINK_50G] = 50000;
|
||||
cgx_speed_mbps[CGX_LINK_80G] = 80000;
|
||||
cgx_speed_mbps[CGX_LINK_100G] = 100000;
|
||||
|
||||
cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII";
|
||||
@@ -606,6 +662,143 @@ static inline void cgx_link_usertable_init(void)
|
||||
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,
|
||||
struct cgx_link_user_info *linfo,
|
||||
struct cgx *cgx, u8 lmac_id)
|
||||
@@ -615,6 +808,8 @@ static inline void link_status_user_format(u64 lstat,
|
||||
linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
|
||||
linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, 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);
|
||||
lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
|
||||
strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
|
||||
@@ -642,6 +837,9 @@ static inline void cgx_link_change_handler(u64 lstat,
|
||||
lmac->link_info = event.link_uinfo;
|
||||
linfo = &lmac->link_info;
|
||||
|
||||
if (err_type == CGX_ERR_SPEED_CHANGE_INVALID)
|
||||
return;
|
||||
|
||||
/* Ensure callback doesn't get unregistered until we finish it */
|
||||
spin_lock(&lmac->event_cb_lock);
|
||||
|
||||
@@ -670,7 +868,8 @@ static inline bool cgx_cmdresp_is_linkevent(u64 event)
|
||||
|
||||
id = FIELD_GET(EVTREG_ID, event);
|
||||
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;
|
||||
else
|
||||
return false;
|
||||
@@ -785,6 +984,63 @@ int cgx_get_fwdata_base(u64 *base)
|
||||
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)
|
||||
{
|
||||
u64 req = 0;
|
||||
|
||||
@@ -56,6 +56,11 @@
|
||||
#define CGXX_SCRATCH1_REG 0x1058
|
||||
#define CGX_CONST 0x2000
|
||||
#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_GMP_PCS_MRX_CTL 0x30000
|
||||
#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,
|
||||
u8 tx_pause, u8 rx_pause);
|
||||
void cgx_lmac_ptp_config(void *cgxd, int lmac_id, bool enable);
|
||||
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 */
|
||||
|
||||
@@ -43,7 +43,13 @@ enum cgx_error_type {
|
||||
CGX_ERR_TRAINING_FAIL,
|
||||
CGX_ERR_RX_EQU_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 */
|
||||
@@ -59,10 +65,41 @@ enum cgx_link_speed {
|
||||
CGX_LINK_25G,
|
||||
CGX_LINK_40G,
|
||||
CGX_LINK_50G,
|
||||
CGX_LINK_80G,
|
||||
CGX_LINK_100G,
|
||||
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 */
|
||||
enum cgx_cmd_id {
|
||||
CGX_CMD_NONE,
|
||||
@@ -75,12 +112,25 @@ enum cgx_cmd_id {
|
||||
CGX_CMD_INTERNAL_LBK,
|
||||
CGX_CMD_EXTERNAL_LBK,
|
||||
CGX_CMD_HIGIG,
|
||||
CGX_CMD_LINK_STATE_CHANGE,
|
||||
CGX_CMD_LINK_STAT_CHANGE,
|
||||
CGX_CMD_MODE_CHANGE, /* hot plug support */
|
||||
CGX_CMD_INTF_SHUTDOWN,
|
||||
CGX_CMD_GET_MKEX_PRFL_SIZE,
|
||||
CGX_CMD_GET_MKEX_PRFL_ADDR,
|
||||
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 */
|
||||
@@ -171,13 +221,19 @@ struct cgx_lnk_sts {
|
||||
uint64_t full_duplex:1;
|
||||
uint64_t speed:4; /* cgx_link_speed */
|
||||
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_FDUPLEX GENMASK_ULL(10, 10)
|
||||
#define RESP_LINKSTAT_SPEED GENMASK_ULL(14, 11)
|
||||
#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
|
||||
* This CSR acts as a command register
|
||||
@@ -199,4 +255,12 @@ struct cgx_lnk_sts {
|
||||
#define CMDLINKCHANGE_FULLDPLX BIT_ULL(9)
|
||||
#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__ */
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -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_CFG_PAUSE_FRM, 0x20E, cgx_cfg_pause_frm, 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) */ \
|
||||
M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \
|
||||
npa_lf_alloc_req, npa_lf_alloc_rsp) \
|
||||
@@ -360,6 +367,11 @@ struct cgx_stats_rsp {
|
||||
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
|
||||
* setting/getting mac address in the CGX interface
|
||||
*/
|
||||
@@ -373,6 +385,8 @@ struct cgx_link_user_info {
|
||||
uint64_t full_duplex:1;
|
||||
uint64_t lmac_type_id:4;
|
||||
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
|
||||
char lmac_type[LMACTYPE_STR_LEN];
|
||||
};
|
||||
@@ -391,6 +405,79 @@ struct cgx_pause_frm_cfg {
|
||||
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 mailbox error codes
|
||||
|
||||
@@ -357,6 +357,10 @@ struct rvu_fwdata {
|
||||
u64 msixtr_base;
|
||||
#define FWDATA_RESERVED_MEM 1023
|
||||
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;
|
||||
|
||||
@@ -462,6 +462,22 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req,
|
||||
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,
|
||||
struct cgx_mac_addr_set_or_get *req,
|
||||
struct cgx_mac_addr_set_or_get *rsp)
|
||||
@@ -676,6 +692,19 @@ int rvu_mbox_handler_cgx_cfg_pause_frm(struct rvu *rvu,
|
||||
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
|
||||
* from its VFs as well. ie. NIX rx/tx counters at the CGX port level
|
||||
*/
|
||||
@@ -767,3 +796,56 @@ exit:
|
||||
mutex_unlock(&rvu->cgx_cfg_lock);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct otx2_rcv_queue *rq = &pfvf->qset.rq[qidx];
|
||||
@@ -1489,6 +1502,13 @@ void mbox_handler_cgx_stats(struct otx2_nic *pfvf,
|
||||
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,
|
||||
struct nix_txsch_alloc_rsp *rsp)
|
||||
{
|
||||
|
||||
@@ -204,6 +204,8 @@ struct otx2_hw {
|
||||
struct otx2_drv_stats drv_stats;
|
||||
u64 cgx_rx_stats[CGX_RX_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 lbk_links; /* No. of LBK links present in HW */
|
||||
};
|
||||
@@ -661,6 +663,9 @@ void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf,
|
||||
struct nix_txsch_alloc_rsp *rsp);
|
||||
void mbox_handler_cgx_stats(struct otx2_nic *pfvf,
|
||||
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,
|
||||
struct nix_bp_cfg_rsp *rsp);
|
||||
|
||||
@@ -669,6 +674,7 @@ void otx2_get_dev_stats(struct otx2_nic *pfvf);
|
||||
void otx2_get_stats64(struct net_device *netdev,
|
||||
struct rtnl_link_stats64 *stats);
|
||||
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_sq_stats(struct otx2_nic *pfvf, int qidx);
|
||||
void otx2_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/linkmode.h>
|
||||
|
||||
#include "otx2_common.h"
|
||||
#include "otx2_ptp.h"
|
||||
@@ -32,6 +33,14 @@ struct otx2_stat {
|
||||
.index = offsetof(struct otx2_dev_stats, stat) / sizeof(u64), \
|
||||
}
|
||||
|
||||
/* Physical link config */
|
||||
#define OTX2_ETHTOOL_SUPPORTED_MODES 0x638CCBF //110001110001100110010111111
|
||||
|
||||
enum link_mode {
|
||||
OTX2_MODE_SUPPORTED,
|
||||
OTX2_MODE_ADVERTISED
|
||||
};
|
||||
|
||||
static const struct otx2_stat otx2_dev_stats[] = {
|
||||
OTX2_DEV_STAT(rx_ucast_frames),
|
||||
OTX2_DEV_STAT(rx_bcast_frames),
|
||||
@@ -66,6 +75,8 @@ static const unsigned int otx2_n_dev_stats = ARRAY_SIZE(otx2_dev_stats);
|
||||
static const unsigned int otx2_n_drv_stats = ARRAY_SIZE(otx2_drv_stats);
|
||||
static const unsigned int otx2_n_queue_stats = ARRAY_SIZE(otx2_queue_stats);
|
||||
|
||||
static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf);
|
||||
|
||||
static void otx2_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
@@ -128,6 +139,10 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
|
||||
|
||||
strcpy(data, "reset_count");
|
||||
data += ETH_GSTRING_LEN;
|
||||
sprintf(data, "Fec Corrected Errors: ");
|
||||
data += ETH_GSTRING_LEN;
|
||||
sprintf(data, "Fec Uncorrected Errors: ");
|
||||
data += ETH_GSTRING_LEN;
|
||||
}
|
||||
|
||||
static void otx2_get_qset_stats(struct otx2_nic *pfvf,
|
||||
@@ -160,11 +175,30 @@ static void otx2_get_qset_stats(struct otx2_nic *pfvf,
|
||||
}
|
||||
}
|
||||
|
||||
static int otx2_get_phy_fec_stats(struct otx2_nic *pfvf)
|
||||
{
|
||||
struct msg_req *req;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
mutex_lock(&pfvf->mbox.lock);
|
||||
req = otx2_mbox_alloc_msg_cgx_get_phy_fec_stats(&pfvf->mbox);
|
||||
if (!req)
|
||||
goto end;
|
||||
|
||||
if (!otx2_sync_mbox_msg(&pfvf->mbox))
|
||||
rc = 0;
|
||||
end:
|
||||
mutex_unlock(&pfvf->mbox.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Get device and per queue statistics */
|
||||
static void otx2_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct otx2_nic *pfvf = netdev_priv(netdev);
|
||||
u64 fec_corr_blks, fec_uncorr_blks;
|
||||
struct cgx_fw_data *rsp;
|
||||
int stat;
|
||||
|
||||
otx2_get_dev_stats(pfvf);
|
||||
@@ -183,6 +217,32 @@ static void otx2_get_ethtool_stats(struct net_device *netdev,
|
||||
for (stat = 0; stat < CGX_TX_STATS_COUNT; stat++)
|
||||
*(data++) = pfvf->hw.cgx_tx_stats[stat];
|
||||
*(data++) = pfvf->reset_count;
|
||||
|
||||
fec_corr_blks = pfvf->hw.cgx_fec_corr_blks;
|
||||
fec_uncorr_blks = pfvf->hw.cgx_fec_uncorr_blks;
|
||||
|
||||
rsp = otx2_get_fwdata(pfvf);
|
||||
if (!IS_ERR(rsp) && rsp->fwdata.phy.misc.has_fec_stats &&
|
||||
!otx2_get_phy_fec_stats(pfvf)) {
|
||||
/* Fetch fwdata again because it's been recently populated with
|
||||
* latest PHY FEC stats.
|
||||
*/
|
||||
rsp = otx2_get_fwdata(pfvf);
|
||||
if (!IS_ERR(rsp)) {
|
||||
struct fec_stats_s *p = &rsp->fwdata.phy.fec_stats;
|
||||
|
||||
if (pfvf->linfo.fec == OTX2_FEC_BASER) {
|
||||
fec_corr_blks = p->brfec_corr_blks;
|
||||
fec_uncorr_blks = p->brfec_uncorr_blks;
|
||||
} else {
|
||||
fec_corr_blks = p->rsfec_corr_cws;
|
||||
fec_uncorr_blks = p->rsfec_uncorr_cws;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*(data++) = fec_corr_blks;
|
||||
*(data++) = fec_uncorr_blks;
|
||||
}
|
||||
|
||||
static int otx2_get_sset_count(struct net_device *netdev, int sset)
|
||||
@@ -195,9 +255,11 @@ static int otx2_get_sset_count(struct net_device *netdev, int sset)
|
||||
|
||||
qstats_count = otx2_n_queue_stats *
|
||||
(pfvf->hw.rx_queues + pfvf->hw.tx_queues);
|
||||
otx2_update_lmac_fec_stats(pfvf);
|
||||
|
||||
return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count +
|
||||
CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT + 1;
|
||||
CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT + OTX2_FEC_STATS_CNT
|
||||
+ 1;
|
||||
}
|
||||
|
||||
/* Get no of queues device supports and current queue count */
|
||||
@@ -859,6 +921,304 @@ static int otx2_get_ts_info(struct net_device *netdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf)
|
||||
{
|
||||
struct cgx_fw_data *rsp = NULL;
|
||||
struct msg_req *req;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&pfvf->mbox.lock);
|
||||
req = otx2_mbox_alloc_msg_cgx_get_aux_link_info(&pfvf->mbox);
|
||||
if (!req) {
|
||||
mutex_unlock(&pfvf->mbox.lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = otx2_sync_mbox_msg(&pfvf->mbox);
|
||||
if (!err) {
|
||||
rsp = (struct cgx_fw_data *)
|
||||
otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr);
|
||||
} else {
|
||||
rsp = ERR_PTR(err);
|
||||
}
|
||||
|
||||
mutex_unlock(&pfvf->mbox.lock);
|
||||
return rsp;
|
||||
}
|
||||
|
||||
static int otx2_get_fecparam(struct net_device *netdev,
|
||||
struct ethtool_fecparam *fecparam)
|
||||
{
|
||||
struct otx2_nic *pfvf = netdev_priv(netdev);
|
||||
struct cgx_fw_data *rsp;
|
||||
const int fec[] = {
|
||||
ETHTOOL_FEC_OFF,
|
||||
ETHTOOL_FEC_BASER,
|
||||
ETHTOOL_FEC_RS,
|
||||
ETHTOOL_FEC_BASER | ETHTOOL_FEC_RS};
|
||||
#define FEC_MAX_INDEX 4
|
||||
if (pfvf->linfo.fec < FEC_MAX_INDEX)
|
||||
fecparam->active_fec = fec[pfvf->linfo.fec];
|
||||
|
||||
rsp = otx2_get_fwdata(pfvf);
|
||||
if (IS_ERR(rsp))
|
||||
return PTR_ERR(rsp);
|
||||
|
||||
if (rsp->fwdata.supported_fec <= FEC_MAX_INDEX) {
|
||||
if (!rsp->fwdata.supported_fec)
|
||||
fecparam->fec = ETHTOOL_FEC_NONE;
|
||||
else
|
||||
fecparam->fec = fec[rsp->fwdata.supported_fec];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int otx2_set_fecparam(struct net_device *netdev,
|
||||
struct ethtool_fecparam *fecparam)
|
||||
{
|
||||
struct otx2_nic *pfvf = netdev_priv(netdev);
|
||||
struct mbox *mbox = &pfvf->mbox;
|
||||
struct fec_mode *req, *rsp;
|
||||
int err = 0, fec = 0;
|
||||
|
||||
switch (fecparam->fec) {
|
||||
/* Firmware does not support AUTO mode consider it as FEC_OFF */
|
||||
case ETHTOOL_FEC_OFF:
|
||||
case ETHTOOL_FEC_AUTO:
|
||||
fec = OTX2_FEC_OFF;
|
||||
break;
|
||||
case ETHTOOL_FEC_RS:
|
||||
fec = OTX2_FEC_RS;
|
||||
break;
|
||||
case ETHTOOL_FEC_BASER:
|
||||
fec = OTX2_FEC_BASER;
|
||||
break;
|
||||
default:
|
||||
netdev_warn(pfvf->netdev, "Unsupported FEC mode: %d",
|
||||
fecparam->fec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fec == pfvf->linfo.fec)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mbox->lock);
|
||||
req = otx2_mbox_alloc_msg_cgx_set_fec_param(&pfvf->mbox);
|
||||
if (!req) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
req->fec = fec;
|
||||
err = otx2_sync_mbox_msg(&pfvf->mbox);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
rsp = (struct fec_mode *)otx2_mbox_get_rsp(&pfvf->mbox.mbox,
|
||||
0, &req->hdr);
|
||||
if (rsp->fec >= 0)
|
||||
pfvf->linfo.fec = rsp->fec;
|
||||
else
|
||||
err = rsp->fec;
|
||||
end:
|
||||
mutex_unlock(&mbox->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void otx2_get_fec_info(u64 index, int req_mode,
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_fec_modes) = { 0, };
|
||||
|
||||
switch (index) {
|
||||
case OTX2_FEC_NONE:
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
|
||||
otx2_fec_modes);
|
||||
break;
|
||||
case OTX2_FEC_BASER:
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
|
||||
otx2_fec_modes);
|
||||
break;
|
||||
case OTX2_FEC_RS:
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
|
||||
otx2_fec_modes);
|
||||
break;
|
||||
case OTX2_FEC_BASER | OTX2_FEC_RS:
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
|
||||
otx2_fec_modes);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
|
||||
otx2_fec_modes);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add fec modes to existing modes */
|
||||
if (req_mode == OTX2_MODE_ADVERTISED)
|
||||
linkmode_or(link_ksettings->link_modes.advertising,
|
||||
link_ksettings->link_modes.advertising,
|
||||
otx2_fec_modes);
|
||||
else
|
||||
linkmode_or(link_ksettings->link_modes.supported,
|
||||
link_ksettings->link_modes.supported,
|
||||
otx2_fec_modes);
|
||||
}
|
||||
|
||||
static void otx2_get_link_mode_info(u64 link_mode_bmap,
|
||||
bool req_mode,
|
||||
struct ethtool_link_ksettings
|
||||
*link_ksettings)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_link_modes) = { 0, };
|
||||
const int otx2_sgmii_features[6] = {
|
||||
ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
};
|
||||
/* CGX link modes to Ethtool link mode mapping */
|
||||
const int cgx_link_mode[27] = {
|
||||
0, /* SGMII Mode */
|
||||
ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
|
||||
0,
|
||||
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
|
||||
0,
|
||||
0,
|
||||
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
|
||||
0,
|
||||
ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
|
||||
0,
|
||||
ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
|
||||
0,
|
||||
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT
|
||||
};
|
||||
u8 bit;
|
||||
|
||||
link_mode_bmap = link_mode_bmap & OTX2_ETHTOOL_SUPPORTED_MODES;
|
||||
|
||||
for_each_set_bit(bit, (unsigned long *)&link_mode_bmap, 27) {
|
||||
/* SGMII mode is set */
|
||||
if (bit == 0)
|
||||
linkmode_set_bit_array(otx2_sgmii_features,
|
||||
ARRAY_SIZE(otx2_sgmii_features),
|
||||
otx2_link_modes);
|
||||
else
|
||||
linkmode_set_bit(cgx_link_mode[bit], otx2_link_modes);
|
||||
}
|
||||
|
||||
if (req_mode == OTX2_MODE_ADVERTISED)
|
||||
linkmode_copy(link_ksettings->link_modes.advertising,
|
||||
otx2_link_modes);
|
||||
else
|
||||
linkmode_copy(link_ksettings->link_modes.supported,
|
||||
otx2_link_modes);
|
||||
}
|
||||
|
||||
static int otx2_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct otx2_nic *pfvf = netdev_priv(netdev);
|
||||
struct cgx_fw_data *rsp = NULL;
|
||||
|
||||
cmd->base.duplex = pfvf->linfo.full_duplex;
|
||||
cmd->base.speed = pfvf->linfo.speed;
|
||||
cmd->base.autoneg = pfvf->linfo.an;
|
||||
|
||||
rsp = otx2_get_fwdata(pfvf);
|
||||
if (IS_ERR(rsp))
|
||||
return PTR_ERR(rsp);
|
||||
|
||||
if (rsp->fwdata.supported_an)
|
||||
ethtool_link_ksettings_add_link_mode(cmd,
|
||||
supported,
|
||||
Autoneg);
|
||||
|
||||
otx2_get_link_mode_info(rsp->fwdata.advertised_link_modes,
|
||||
OTX2_MODE_ADVERTISED, cmd);
|
||||
otx2_get_fec_info(rsp->fwdata.advertised_fec,
|
||||
OTX2_MODE_ADVERTISED, cmd);
|
||||
otx2_get_link_mode_info(rsp->fwdata.supported_link_modes,
|
||||
OTX2_MODE_SUPPORTED, cmd);
|
||||
otx2_get_fec_info(rsp->fwdata.supported_fec,
|
||||
OTX2_MODE_SUPPORTED, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void otx2_get_advertised_mode(const struct ethtool_link_ksettings *cmd,
|
||||
u64 *mode)
|
||||
{
|
||||
u32 bit_pos;
|
||||
|
||||
/* Firmware does not support requesting multiple advertised modes
|
||||
* return first set bit
|
||||
*/
|
||||
bit_pos = find_first_bit(cmd->link_modes.advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
if (bit_pos != __ETHTOOL_LINK_MODE_MASK_NBITS)
|
||||
*mode = bit_pos;
|
||||
}
|
||||
|
||||
static int otx2_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct otx2_nic *pf = netdev_priv(netdev);
|
||||
struct ethtool_link_ksettings cur_ks;
|
||||
struct cgx_set_link_mode_req *req;
|
||||
struct mbox *mbox = &pf->mbox;
|
||||
int err = 0;
|
||||
|
||||
memset(&cur_ks, 0, sizeof(struct ethtool_link_ksettings));
|
||||
|
||||
if (!ethtool_validate_speed(cmd->base.speed) ||
|
||||
!ethtool_validate_duplex(cmd->base.duplex))
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd->base.autoneg != AUTONEG_ENABLE &&
|
||||
cmd->base.autoneg != AUTONEG_DISABLE)
|
||||
return -EINVAL;
|
||||
|
||||
otx2_get_link_ksettings(netdev, &cur_ks);
|
||||
|
||||
/* Check requested modes against supported modes by hardware */
|
||||
if (!bitmap_subset(cmd->link_modes.advertising,
|
||||
cur_ks.link_modes.supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&mbox->lock);
|
||||
req = otx2_mbox_alloc_msg_cgx_set_link_mode(&pf->mbox);
|
||||
if (!req) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
req->args.speed = cmd->base.speed;
|
||||
/* firmware expects 1 for half duplex and 0 for full duplex
|
||||
* hence inverting
|
||||
*/
|
||||
req->args.duplex = cmd->base.duplex ^ 0x1;
|
||||
req->args.an = cmd->base.autoneg;
|
||||
otx2_get_advertised_mode(cmd, &req->args.mode);
|
||||
|
||||
err = otx2_sync_mbox_msg(&pf->mbox);
|
||||
end:
|
||||
mutex_unlock(&mbox->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops otx2_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_MAX_FRAMES,
|
||||
@@ -886,6 +1246,10 @@ static const struct ethtool_ops otx2_ethtool_ops = {
|
||||
.get_pauseparam = otx2_get_pauseparam,
|
||||
.set_pauseparam = otx2_set_pauseparam,
|
||||
.get_ts_info = otx2_get_ts_info,
|
||||
.get_fecparam = otx2_get_fecparam,
|
||||
.set_fecparam = otx2_set_fecparam,
|
||||
.get_link_ksettings = otx2_get_link_ksettings,
|
||||
.set_link_ksettings = otx2_set_link_ksettings,
|
||||
};
|
||||
|
||||
void otx2_set_ethtool_ops(struct net_device *netdev)
|
||||
@@ -960,6 +1324,20 @@ static int otx2vf_get_sset_count(struct net_device *netdev, int sset)
|
||||
return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count + 1;
|
||||
}
|
||||
|
||||
static int otx2vf_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct otx2_nic *pfvf = netdev_priv(netdev);
|
||||
|
||||
if (is_otx2_lbkvf(pfvf->pdev)) {
|
||||
cmd->base.duplex = DUPLEX_FULL;
|
||||
cmd->base.speed = SPEED_100000;
|
||||
} else {
|
||||
return otx2_get_link_ksettings(netdev, cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops otx2vf_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_MAX_FRAMES,
|
||||
@@ -986,6 +1364,7 @@ static const struct ethtool_ops otx2vf_ethtool_ops = {
|
||||
.set_msglevel = otx2_set_msglevel,
|
||||
.get_pauseparam = otx2_get_pauseparam,
|
||||
.set_pauseparam = otx2_set_pauseparam,
|
||||
.get_link_ksettings = otx2vf_get_link_ksettings,
|
||||
};
|
||||
|
||||
void otx2vf_set_ethtool_ops(struct net_device *netdev)
|
||||
|
||||
@@ -779,6 +779,9 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf,
|
||||
case MBOX_MSG_CGX_STATS:
|
||||
mbox_handler_cgx_stats(pf, (struct cgx_stats_rsp *)msg);
|
||||
break;
|
||||
case MBOX_MSG_CGX_FEC_STATS:
|
||||
mbox_handler_cgx_fec_stats(pf, (struct cgx_fec_stats_rsp *)msg);
|
||||
break;
|
||||
default:
|
||||
if (msg->rc)
|
||||
dev_err(pf->dev,
|
||||
|
||||
Reference in New Issue
Block a user