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 @@
#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 @@ int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start)
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,
......
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