Commit 33362fc2 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlx5-DCBX-and-ethtool-updates'

Saeed Mahameed says:

====================
Mellanox 100G mlx5 DCBX and ethtool updates

This series provides the following mlx5 updates:

From Huy:
DCBX CEE API and DCBX firmware/host modes support.
    - 1st patch ensures the dcbnl_rtnl_ops is published only when the qos
      capability bits is on.
    - 2nd patch adds the support for CEE interfaces into mlx5 dcbnl_rtnl_ops
    - 3rd patch refactors ETS query to read ETS configuration directly from
      firmware rather than having a software shadow to it. The existing IEEE
      interfaces stays the same.
    - 4th patch adds the support for MLX5_REG_DCBX_PARAM and MLX5_REG_DCBX_APP
      firmware commands to manipulate mlx5 DCBX mode.
    - 5th patch adds the driver support for the new DCBX firmware.  This ensures
      the backward compatibility versus the old and new firmware. With the new DCBX
      firmware, qos settings can be controlled by either firmware or software
      depending on the DCBX mode.

From Kamal and Saeed:
    - mlx5 self-test support.

From Shaker:
    - Private flag to give the user the ability to enable/disable mlx5 CQE
      compression.

V1->V2:
    - Check ETS capability where needed in:
	("net/mlx5e: Read ETS settings directly from firmware")
    - Fix return value of mlx5e_dcbnl_switch_to_host_mode in:
	("net/mlx5e: ConnectX-4 firmware support for DCBX")
    - Update commit message of:
	("net/mlx5e: ConnectX-4 firmware support for DCBX")
    - Fix two sparse static check warnings in en_selftest.c

This series was generated against commit:
e5f12b3f ("Merge branch 'mlxsw-trap-groups-and-policers'")
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 44900010 9bcc8606
......@@ -8,6 +8,6 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \
en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \
en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
en_tc.o en_arfs.o en_rep.o en_fs_ethtool.o
en_tc.o en_arfs.o en_rep.o en_fs_ethtool.o en_selftest.o
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o
......@@ -167,22 +167,28 @@ struct mlx5e_umr_wqe {
struct mlx5_wqe_data_seg data;
};
extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = {
"rx_cqe_moder",
"rx_cqe_compress",
};
enum mlx5e_priv_flag {
MLX5E_PFLAG_RX_CQE_BASED_MODER = (1 << 0),
MLX5E_PFLAG_RX_CQE_COMPRESS = (1 << 1),
};
#define MLX5E_SET_PRIV_FLAG(priv, pflag, enable) \
do { \
if (enable) \
priv->pflags |= pflag; \
else \
priv->pflags &= ~pflag; \
#define MLX5E_SET_PFLAG(priv, pflag, enable) \
do { \
if (enable) \
(priv)->params.pflags |= (pflag); \
else \
(priv)->params.pflags &= ~(pflag); \
} while (0)
#define MLX5E_GET_PFLAG(priv, pflag) (!!((priv)->params.pflags & (pflag)))
#ifdef CONFIG_MLX5_CORE_EN_DCB
#define MLX5E_MAX_BW_ALLOC 100 /* Max percentage of BW allocation */
#endif
......@@ -201,8 +207,7 @@ struct mlx5e_params {
u16 num_channels;
u8 num_tc;
u8 rx_cq_period_mode;
bool rx_cqe_compress_admin;
bool rx_cqe_compress;
bool rx_cqe_compress_def;
struct mlx5e_cq_moder rx_cq_moderation;
struct mlx5e_cq_moder tx_cq_moderation;
u16 min_rx_wqes;
......@@ -214,13 +219,35 @@ struct mlx5e_params {
u8 toeplitz_hash_key[40];
u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE];
bool vlan_strip_disable;
#ifdef CONFIG_MLX5_CORE_EN_DCB
struct ieee_ets ets;
#endif
bool rx_am_enabled;
u32 lro_timeout;
u32 pflags;
};
#ifdef CONFIG_MLX5_CORE_EN_DCB
struct mlx5e_cee_config {
/* bw pct for priority group */
u8 pg_bw_pct[CEE_DCBX_MAX_PGS];
u8 prio_to_pg_map[CEE_DCBX_MAX_PRIO];
bool pfc_setting[CEE_DCBX_MAX_PRIO];
bool pfc_enable;
};
enum {
MLX5_DCB_CHG_RESET,
MLX5_DCB_NO_CHG,
MLX5_DCB_CHG_NO_RESET,
};
struct mlx5e_dcbx {
enum mlx5_dcbx_oper_mode mode;
struct mlx5e_cee_config cee_cfg; /* pending configuration */
/* The only setting that cannot be read from FW */
u8 tc_tsa[IEEE_8021QAZ_MAX_TCS];
};
#endif
struct mlx5e_tstamp {
rwlock_t lock;
struct cyclecounter cycles;
......@@ -682,12 +709,15 @@ struct mlx5e_priv {
struct work_struct tx_timeout_work;
struct delayed_work update_stats_work;
u32 pflags;
struct mlx5_core_dev *mdev;
struct net_device *netdev;
struct mlx5e_stats stats;
struct mlx5e_tstamp tstamp;
u16 q_counter;
#ifdef CONFIG_MLX5_CORE_EN_DCB
struct mlx5e_dcbx dcbx;
#endif
const struct mlx5e_profile *profile;
void *ppriv;
};
......@@ -729,6 +759,9 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv);
void mlx5e_init_l2_addr(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft);
int mlx5e_self_test_num(struct mlx5e_priv *priv);
void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
u64 *buf);
int mlx5e_ethtool_get_flow(struct mlx5e_priv *priv, struct ethtool_rxnfc *info,
int location);
int mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,
......@@ -819,6 +852,7 @@ extern const struct ethtool_ops mlx5e_ethtool_ops;
#ifdef CONFIG_MLX5_CORE_EN_DCB
extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets);
void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv);
#endif
#ifndef CONFIG_RFS_ACCEL
......@@ -854,7 +888,8 @@ void mlx5e_destroy_tir(struct mlx5_core_dev *mdev,
struct mlx5e_tir *tir);
int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev);
void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev);
int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5_core_dev *mdev);
int mlx5e_refresh_tirs_self_loopback(struct mlx5_core_dev *mdev,
bool enable_uc_lb);
struct mlx5_eswitch_rep;
int mlx5e_vport_rep_load(struct mlx5_eswitch *esw,
......
......@@ -94,7 +94,7 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
/* Reset CQE compression to Admin default */
mlx5e_modify_rx_cqe_compression(priv, priv->params.rx_cqe_compress_admin);
mlx5e_modify_rx_cqe_compression(priv, priv->params.rx_cqe_compress_def);
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
......@@ -111,6 +111,7 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
/* Disable CQE compression */
netdev_warn(dev, "Disabling cqe compression");
mlx5e_modify_rx_cqe_compression(priv, false);
config.rx_filter = HWTSTAMP_FILTER_ALL;
break;
......
......@@ -137,7 +137,8 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
mlx5_unmap_free_uar(mdev, &res->cq_uar);
}
int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5_core_dev *mdev)
int mlx5e_refresh_tirs_self_loopback(struct mlx5_core_dev *mdev,
bool enable_uc_lb)
{
struct mlx5e_tir *tir;
void *in;
......@@ -149,6 +150,10 @@ int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5_core_dev *mdev)
if (!in)
return -ENOMEM;
if (enable_uc_lb)
MLX5_SET(modify_tir_in, in, ctx.self_lb_block,
MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_);
MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
list_for_each_entry(tir, &mdev->mlx5e_res.td.tirs_list, list) {
......
......@@ -38,16 +38,77 @@
#define MLX5E_100MB (100000)
#define MLX5E_1GB (1000000)
#define MLX5E_CEE_STATE_UP 1
#define MLX5E_CEE_STATE_DOWN 0
/* If dcbx mode is non-host set the dcbx mode to host.
*/
static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv,
enum mlx5_dcbx_oper_mode mode)
{
struct mlx5_core_dev *mdev = priv->mdev;
u32 param[MLX5_ST_SZ_DW(dcbx_param)];
int err;
err = mlx5_query_port_dcbx_param(mdev, param);
if (err)
return err;
MLX5_SET(dcbx_param, param, version_admin, mode);
if (mode != MLX5E_DCBX_PARAM_VER_OPER_HOST)
MLX5_SET(dcbx_param, param, willing_admin, 1);
return mlx5_set_port_dcbx_param(mdev, param);
}
static int mlx5e_dcbnl_switch_to_host_mode(struct mlx5e_priv *priv)
{
struct mlx5e_dcbx *dcbx = &priv->dcbx;
int err;
if (!MLX5_CAP_GEN(priv->mdev, dcbx))
return 0;
if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_HOST)
return 0;
err = mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_HOST);
if (err)
return err;
dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_HOST;
return 0;
}
static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
struct ieee_ets *ets)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
int err = 0;
int i;
if (!MLX5_CAP_GEN(priv->mdev, ets))
return -ENOTSUPP;
memcpy(ets, &priv->params.ets, sizeof(*ets));
return 0;
ets->ets_cap = mlx5_max_tc(priv->mdev) + 1;
for (i = 0; i < ets->ets_cap; i++) {
err = mlx5_query_port_prio_tc(mdev, i, &ets->prio_tc[i]);
if (err)
return err;
}
for (i = 0; i < ets->ets_cap; i++) {
err = mlx5_query_port_tc_bw_alloc(mdev, i, &ets->tc_tx_bw[i]);
if (err)
return err;
if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC)
priv->dcbx.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
}
memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa));
return err;
}
enum {
......@@ -110,9 +171,6 @@ int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets)
int max_tc = mlx5_max_tc(mdev);
int err;
if (!MLX5_CAP_GEN(mdev, ets))
return -ENOTSUPP;
mlx5e_build_tc_group(ets, tc_group, max_tc);
mlx5e_build_tc_tx_bw(ets, tc_tx_bw, tc_group, max_tc);
......@@ -124,7 +182,14 @@ int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets)
if (err)
return err;
return mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw);
err = mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw);
if (err)
return err;
memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa));
return err;
}
static int mlx5e_dbcnl_validate_ets(struct net_device *netdev,
......@@ -170,6 +235,9 @@ static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev,
struct mlx5e_priv *priv = netdev_priv(netdev);
int err;
if (!MLX5_CAP_GEN(priv->mdev, ets))
return -ENOTSUPP;
err = mlx5e_dbcnl_validate_ets(netdev, ets);
if (err)
return err;
......@@ -178,9 +246,6 @@ static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev,
if (err)
return err;
memcpy(&priv->params.ets, ets, sizeof(*ets));
priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
return 0;
}
......@@ -222,13 +287,39 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev,
static u8 mlx5e_dcbnl_getdcbx(struct net_device *dev)
{
return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5e_dcbx *dcbx = &priv->dcbx;
u8 mode = DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_VER_CEE;
if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_HOST)
mode |= DCB_CAP_DCBX_HOST;
return mode;
}
static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5e_dcbx *dcbx = &priv->dcbx;
if ((!mode) && MLX5_CAP_GEN(priv->mdev, dcbx)) {
if (dcbx->mode == MLX5E_DCBX_PARAM_VER_OPER_AUTO)
return 0;
/* set dcbx to fw controlled */
if (!mlx5e_dcbnl_set_dcbx_mode(priv, MLX5E_DCBX_PARAM_VER_OPER_AUTO)) {
dcbx->mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO;
return 0;
}
return 1;
}
if (mlx5e_dcbnl_switch_to_host_mode(netdev_priv(dev)))
return 1;
if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
(mode & DCB_CAP_DCBX_VER_CEE) ||
!(mode & DCB_CAP_DCBX_VER_CEE) ||
!(mode & DCB_CAP_DCBX_VER_IEEE) ||
!(mode & DCB_CAP_DCBX_HOST))
return 1;
......@@ -304,6 +395,284 @@ static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev,
return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit);
}
static u8 mlx5e_dcbnl_setall(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg;
struct mlx5_core_dev *mdev = priv->mdev;
struct ieee_ets ets;
struct ieee_pfc pfc;
int err = -ENOTSUPP;
int i;
if (!MLX5_CAP_GEN(mdev, ets))
goto out;
memset(&ets, 0, sizeof(ets));
memset(&pfc, 0, sizeof(pfc));
ets.ets_cap = IEEE_8021QAZ_MAX_TCS;
for (i = 0; i < CEE_DCBX_MAX_PGS; i++) {
ets.tc_tx_bw[i] = cee_cfg->pg_bw_pct[i];
ets.tc_rx_bw[i] = cee_cfg->pg_bw_pct[i];
ets.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
ets.prio_tc[i] = cee_cfg->prio_to_pg_map[i];
}
err = mlx5e_dbcnl_validate_ets(netdev, &ets);
if (err) {
netdev_err(netdev,
"%s, Failed to validate ETS: %d\n", __func__, err);
goto out;
}
err = mlx5e_dcbnl_ieee_setets_core(priv, &ets);
if (err) {
netdev_err(netdev,
"%s, Failed to set ETS: %d\n", __func__, err);
goto out;
}
/* Set PFC */
pfc.pfc_cap = mlx5_max_tc(mdev) + 1;
if (!cee_cfg->pfc_enable)
pfc.pfc_en = 0;
else
for (i = 0; i < CEE_DCBX_MAX_PRIO; i++)
pfc.pfc_en |= cee_cfg->pfc_setting[i] << i;
err = mlx5e_dcbnl_ieee_setpfc(netdev, &pfc);
if (err) {
netdev_err(netdev,
"%s, Failed to set PFC: %d\n", __func__, err);
goto out;
}
out:
return err ? MLX5_DCB_NO_CHG : MLX5_DCB_CHG_RESET;
}
static u8 mlx5e_dcbnl_getstate(struct net_device *netdev)
{
return MLX5E_CEE_STATE_UP;
}
static void mlx5e_dcbnl_getpermhwaddr(struct net_device *netdev,
u8 *perm_addr)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
if (!perm_addr)
return;
mlx5_query_nic_vport_mac_address(priv->mdev, 0, perm_addr);
}
static void mlx5e_dcbnl_setpgtccfgtx(struct net_device *netdev,
int priority, u8 prio_type,
u8 pgid, u8 bw_pct, u8 up_map)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg;
if (priority >= CEE_DCBX_MAX_PRIO) {
netdev_err(netdev,
"%s, priority is out of range\n", __func__);
return;
}
if (pgid >= CEE_DCBX_MAX_PGS) {
netdev_err(netdev,
"%s, priority group is out of range\n", __func__);
return;
}
cee_cfg->prio_to_pg_map[priority] = pgid;
}
static void mlx5e_dcbnl_setpgbwgcfgtx(struct net_device *netdev,
int pgid, u8 bw_pct)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg;
if (pgid >= CEE_DCBX_MAX_PGS) {
netdev_err(netdev,
"%s, priority group is out of range\n", __func__);
return;
}
cee_cfg->pg_bw_pct[pgid] = bw_pct;
}
static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev,
int priority, u8 *prio_type,
u8 *pgid, u8 *bw_pct, u8 *up_map)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
if (priority >= CEE_DCBX_MAX_PRIO) {
netdev_err(netdev,
"%s, priority is out of range\n", __func__);
return;
}
*prio_type = 0;
*bw_pct = 0;
*up_map = 0;
if (mlx5_query_port_prio_tc(mdev, priority, pgid))
*pgid = 0;
}
static void mlx5e_dcbnl_getpgbwgcfgtx(struct net_device *netdev,
int pgid, u8 *bw_pct)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
if (pgid >= CEE_DCBX_MAX_PGS) {
netdev_err(netdev,
"%s, priority group is out of range\n", __func__);
return;
}
if (mlx5_query_port_tc_bw_alloc(mdev, pgid, bw_pct))
*bw_pct = 0;
}
static void mlx5e_dcbnl_setpfccfg(struct net_device *netdev,
int priority, u8 setting)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg;
if (priority >= CEE_DCBX_MAX_PRIO) {
netdev_err(netdev,
"%s, priority is out of range\n", __func__);
return;
}
if (setting > 1)
return;
cee_cfg->pfc_setting[priority] = setting;
}
static int
mlx5e_dcbnl_get_priority_pfc(struct net_device *netdev,
int priority, u8 *setting)
{
struct ieee_pfc pfc;
int err;
err = mlx5e_dcbnl_ieee_getpfc(netdev, &pfc);
if (err)
*setting = 0;
else
*setting = (pfc.pfc_en >> priority) & 0x01;
return err;
}
static void mlx5e_dcbnl_getpfccfg(struct net_device *netdev,
int priority, u8 *setting)
{
if (priority >= CEE_DCBX_MAX_PRIO) {
netdev_err(netdev,
"%s, priority is out of range\n", __func__);
return;
}
if (!setting)
return;
mlx5e_dcbnl_get_priority_pfc(netdev, priority, setting);
}
static u8 mlx5e_dcbnl_getcap(struct net_device *netdev,
int capid, u8 *cap)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
u8 rval = 0;
switch (capid) {
case DCB_CAP_ATTR_PG:
*cap = true;
break;
case DCB_CAP_ATTR_PFC:
*cap = true;
break;
case DCB_CAP_ATTR_UP2TC:
*cap = false;
break;
case DCB_CAP_ATTR_PG_TCS:
*cap = 1 << mlx5_max_tc(mdev);
break;
case DCB_CAP_ATTR_PFC_TCS:
*cap = 1 << mlx5_max_tc(mdev);
break;
case DCB_CAP_ATTR_GSP:
*cap = false;
break;
case DCB_CAP_ATTR_BCN:
*cap = false;
break;
case DCB_CAP_ATTR_DCBX:
*cap = (DCB_CAP_DCBX_LLD_MANAGED |
DCB_CAP_DCBX_VER_CEE |
DCB_CAP_DCBX_STATIC);
break;
default:
*cap = 0;
rval = 1;
break;
}
return rval;
}
static int mlx5e_dcbnl_getnumtcs(struct net_device *netdev,
int tcs_id, u8 *num)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
switch (tcs_id) {
case DCB_NUMTCS_ATTR_PG:
case DCB_NUMTCS_ATTR_PFC:
*num = mlx5_max_tc(mdev) + 1;
break;
default:
return -EINVAL;
}
return 0;
}
static u8 mlx5e_dcbnl_getpfcstate(struct net_device *netdev)
{
struct ieee_pfc pfc;
if (mlx5e_dcbnl_ieee_getpfc(netdev, &pfc))
return MLX5E_CEE_STATE_DOWN;
return pfc.pfc_en ? MLX5E_CEE_STATE_UP : MLX5E_CEE_STATE_DOWN;
}
static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_cee_config *cee_cfg = &priv->dcbx.cee_cfg;
if ((state != MLX5E_CEE_STATE_UP) && (state != MLX5E_CEE_STATE_DOWN))
return;
cee_cfg->pfc_enable = state;
}
const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
.ieee_getets = mlx5e_dcbnl_ieee_getets,
.ieee_setets = mlx5e_dcbnl_ieee_setets,
......@@ -313,4 +682,70 @@ const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
.ieee_setpfc = mlx5e_dcbnl_ieee_setpfc,
.getdcbx = mlx5e_dcbnl_getdcbx,
.setdcbx = mlx5e_dcbnl_setdcbx,
/* CEE interfaces */
.setall = mlx5e_dcbnl_setall,
.getstate = mlx5e_dcbnl_getstate,
.getpermhwaddr = mlx5e_dcbnl_getpermhwaddr,
.setpgtccfgtx = mlx5e_dcbnl_setpgtccfgtx,
.setpgbwgcfgtx = mlx5e_dcbnl_setpgbwgcfgtx,
.getpgtccfgtx = mlx5e_dcbnl_getpgtccfgtx,
.getpgbwgcfgtx = mlx5e_dcbnl_getpgbwgcfgtx,
.setpfccfg = mlx5e_dcbnl_setpfccfg,
.getpfccfg = mlx5e_dcbnl_getpfccfg,
.getcap = mlx5e_dcbnl_getcap,
.getnumtcs = mlx5e_dcbnl_getnumtcs,
.getpfcstate = mlx5e_dcbnl_getpfcstate,
.setpfcstate = mlx5e_dcbnl_setpfcstate,
};
static void mlx5e_dcbnl_query_dcbx_mode(struct mlx5e_priv *priv,
enum mlx5_dcbx_oper_mode *mode)
{
u32 out[MLX5_ST_SZ_DW(dcbx_param)];
*mode = MLX5E_DCBX_PARAM_VER_OPER_HOST;
if (!mlx5_query_port_dcbx_param(priv->mdev, out))
*mode = MLX5_GET(dcbx_param, out, version_oper);
/* From driver's point of view, we only care if the mode
* is host (HOST) or non-host (AUTO)
*/
if (*mode != MLX5E_DCBX_PARAM_VER_OPER_HOST)
*mode = MLX5E_DCBX_PARAM_VER_OPER_AUTO;
}
static void mlx5e_ets_init(struct mlx5e_priv *priv)
{
int i;
struct ieee_ets ets;
memset(&ets, 0, sizeof(ets));
ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
for (i = 0; i < ets.ets_cap; i++) {
ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
ets.prio_tc[i] = i;
}
memcpy(priv->dcbx.tc_tsa, ets.tc_tsa, sizeof(ets.tc_tsa));
/* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
ets.prio_tc[0] = 1;
ets.prio_tc[1] = 0;
mlx5e_dcbnl_ieee_setets_core(priv, &ets);
}
void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv)
{
struct mlx5e_dcbx *dcbx = &priv->dcbx;
if (MLX5_CAP_GEN(priv->mdev, dcbx))
mlx5e_dcbnl_query_dcbx_mode(priv, &dcbx->mode);
mlx5e_ets_init(priv);
}
......@@ -180,6 +180,8 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
case ETH_SS_PRIV_FLAGS:
return ARRAY_SIZE(mlx5e_priv_flags);
case ETH_SS_TEST:
return mlx5e_self_test_num(priv);
/* fallthrough */
default:
return -EOPNOTSUPP;
......@@ -286,6 +288,9 @@ static void mlx5e_get_strings(struct net_device *dev,
break;
case ETH_SS_TEST:
for (i = 0; i < mlx5e_self_test_num(priv); i++)
strcpy(data + i * ETH_GSTRING_LEN,
mlx5e_self_tests[i]);
break;
case ETH_SS_STATS:
......@@ -1476,6 +1481,35 @@ static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable)
return err;
}
static int set_pflag_rx_cqe_compress(struct net_device *netdev,
bool enable)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
int err = 0;
bool reset;
if (!MLX5_CAP_GEN(mdev, cqe_compression))
return -ENOTSUPP;
if (enable && priv->tstamp.hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n");
return -EINVAL;
}
reset = test_bit(MLX5E_STATE_OPENED, &priv->state);
if (reset)
mlx5e_close_locked(netdev);
MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS, enable);
priv->params.rx_cqe_compress_def = enable;
if (reset)
err = mlx5e_open_locked(netdev);
return err;
}
static int mlx5e_handle_pflag(struct net_device *netdev,
u32 wanted_flags,
enum mlx5e_priv_flag flag,
......@@ -1483,7 +1517,7 @@ static int mlx5e_handle_pflag(struct net_device *netdev,
{
struct mlx5e_priv *priv = netdev_priv(netdev);
bool enable = !!(wanted_flags & flag);
u32 changes = wanted_flags ^ priv->pflags;
u32 changes = wanted_flags ^ priv->params.pflags;
int err;
if (!(changes & flag))
......@@ -1496,7 +1530,7 @@ static int mlx5e_handle_pflag(struct net_device *netdev,
return err;
}
MLX5E_SET_PRIV_FLAG(priv, flag, enable);
MLX5E_SET_PFLAG(priv, flag, enable);
return 0;
}
......@@ -1506,20 +1540,26 @@ static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags)
int err;
mutex_lock(&priv->state_lock);
err = mlx5e_handle_pflag(netdev, pflags,
MLX5E_PFLAG_RX_CQE_BASED_MODER,
set_pflag_rx_cqe_based_moder);
if (err)
goto out;
err = mlx5e_handle_pflag(netdev, pflags,
MLX5E_PFLAG_RX_CQE_COMPRESS,
set_pflag_rx_cqe_compress);
out:
mutex_unlock(&priv->state_lock);
return err ? -EINVAL : 0;
return err;
}
static u32 mlx5e_get_priv_flags(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
return priv->pflags;
return priv->params.pflags;
}
static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
......@@ -1573,5 +1613,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
.get_module_info = mlx5e_get_module_info,
.get_module_eeprom = mlx5e_get_module_eeprom,
.get_priv_flags = mlx5e_get_priv_flags,
.set_priv_flags = mlx5e_set_priv_flags
.set_priv_flags = mlx5e_set_priv_flags,
.self_test = mlx5e_self_test,
};
......@@ -84,7 +84,8 @@ static void mlx5e_set_rq_type_params(struct mlx5e_priv *priv, u8 rq_type)
switch (priv->params.rq_wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
priv->params.log_rq_size = MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE_MPW;
priv->params.mpwqe_log_stride_sz = priv->params.rx_cqe_compress ?
priv->params.mpwqe_log_stride_sz =
MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS) ?
MLX5_MPWRQ_LOG_STRIDE_SIZE_CQE_COMPRESS :
MLX5_MPWRQ_LOG_STRIDE_SIZE;
priv->params.mpwqe_log_num_strides = MLX5_MPWRQ_LOG_WQE_SZ -
......@@ -101,7 +102,7 @@ static void mlx5e_set_rq_type_params(struct mlx5e_priv *priv, u8 rq_type)
priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ,
BIT(priv->params.log_rq_size),
BIT(priv->params.mpwqe_log_stride_sz),
priv->params.rx_cqe_compress_admin);
MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS));
}
static void mlx5e_set_rq_priv_params(struct mlx5e_priv *priv)
......@@ -1664,7 +1665,7 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
}
MLX5_SET(cqc, cqc, log_cq_size, log_cq_size);
if (priv->params.rx_cqe_compress) {
if (MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS)) {
MLX5_SET(cqc, cqc, mini_cqe_res_format, MLX5_CQE_FORMAT_CSUM);
MLX5_SET(cqc, cqc, cqe_comp_en, 1);
}
......@@ -2136,7 +2137,7 @@ int mlx5e_open_locked(struct net_device *netdev)
goto err_clear_state_opened_flag;
}
err = mlx5e_refresh_tirs_self_loopback_enable(priv->mdev);
err = mlx5e_refresh_tirs_self_loopback(priv->mdev, false);
if (err) {
netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
__func__, err);
......@@ -3325,24 +3326,6 @@ u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev)
2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
}
#ifdef CONFIG_MLX5_CORE_EN_DCB
static void mlx5e_ets_init(struct mlx5e_priv *priv)
{
int i;
priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
for (i = 0; i < priv->params.ets.ets_cap; i++) {
priv->params.ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
priv->params.ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
priv->params.ets.prio_tc[i] = i;
}
/* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
priv->params.ets.prio_tc[0] = 1;
priv->params.ets.prio_tc[1] = 0;
}
#endif
void mlx5e_build_default_indir_rqt(struct mlx5_core_dev *mdev,
u32 *indirection_rqt, int len,
int num_channels)
......@@ -3465,17 +3448,16 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
/* set CQE compression */
priv->params.rx_cqe_compress_admin = false;
priv->params.rx_cqe_compress_def = false;
if (MLX5_CAP_GEN(mdev, cqe_compression) &&
MLX5_CAP_GEN(mdev, vport_group_manager)) {
mlx5e_get_max_linkspeed(mdev, &link_speed);
mlx5e_get_pci_bw(mdev, &pci_bw);
mlx5_core_dbg(mdev, "Max link speed = %d, PCI BW = %d\n",
link_speed, pci_bw);
priv->params.rx_cqe_compress_admin =
priv->params.rx_cqe_compress_def =
cqe_compress_heuristic(link_speed, pci_bw);
}
priv->params.rx_cqe_compress = priv->params.rx_cqe_compress_admin;
mlx5e_set_rq_priv_params(priv);
if (priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
......@@ -3506,12 +3488,9 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
/* Initialize pflags */
MLX5E_SET_PRIV_FLAG(priv, MLX5E_PFLAG_RX_CQE_BASED_MODER,
priv->params.rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
#ifdef CONFIG_MLX5_CORE_EN_DCB
mlx5e_ets_init(priv);
#endif
MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_BASED_MODER,
priv->params.rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS, priv->params.rx_cqe_compress_def);
mutex_init(&priv->state_lock);
......@@ -3549,7 +3528,8 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
#ifdef CONFIG_MLX5_CORE_EN_DCB
netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
if (MLX5_CAP_GEN(mdev, qos))
netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
#endif
} else {
netdev->netdev_ops = &mlx5e_netdev_ops_basic;
......@@ -3788,7 +3768,7 @@ static int mlx5e_init_nic_tx(struct mlx5e_priv *priv)
}
#ifdef CONFIG_MLX5_CORE_EN_DCB
mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
mlx5e_dcbnl_initialize(priv);
#endif
return 0;
}
......
......@@ -164,14 +164,14 @@ void mlx5e_modify_rx_cqe_compression(struct mlx5e_priv *priv, bool val)
mutex_lock(&priv->state_lock);
if (priv->params.rx_cqe_compress == val)
if (MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS) == val)
goto unlock;
was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
if (was_opened)
mlx5e_close_locked(priv->netdev);
priv->params.rx_cqe_compress = val;
MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS, val);
if (was_opened)
mlx5e_open_locked(priv->netdev);
......
/*
* Copyright (c) 2016, Mellanox Technologies, Ltd. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/ip.h>
#include <linux/udp.h>
#include <net/udp.h>
#include "en.h"
enum {
MLX5E_ST_LINK_STATE,
MLX5E_ST_LINK_SPEED,
MLX5E_ST_HEALTH_INFO,
MLX5E_ST_LOOPBACK,
MLX5E_ST_NUM,
};
const char mlx5e_self_tests[MLX5E_ST_NUM][ETH_GSTRING_LEN] = {
"Link Test",
"Speed Test",
"Health Test",
"Loopback Test",
};
int mlx5e_self_test_num(struct mlx5e_priv *priv)
{
return ARRAY_SIZE(mlx5e_self_tests);
}
static int mlx5e_test_health_info(struct mlx5e_priv *priv)
{
struct mlx5_core_health *health = &priv->mdev->priv.health;
return health->sick ? 1 : 0;
}
static int mlx5e_test_link_state(struct mlx5e_priv *priv)
{
u8 port_state;
if (!netif_carrier_ok(priv->netdev))
return 1;
port_state = mlx5_query_vport_state(priv->mdev, MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT, 0);
return port_state == VPORT_STATE_UP ? 0 : 1;
}
static int mlx5e_test_link_speed(struct mlx5e_priv *priv)
{
u32 out[MLX5_ST_SZ_DW(ptys_reg)];
u32 eth_proto_oper;
int i;
if (!netif_carrier_ok(priv->netdev))
return 1;
if (mlx5_query_port_ptys(priv->mdev, out, sizeof(out), MLX5_PTYS_EN, 1))
return 1;
eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; i++) {
if (eth_proto_oper & MLX5E_PROT_MASK(i))
return 0;
}
return 1;
}
/* loopback test */
#define MLX5E_TEST_PKT_SIZE (MLX5_MPWRQ_SMALL_PACKET_THRESHOLD - NET_IP_ALIGN)
static const char mlx5e_test_text[ETH_GSTRING_LEN] = "MLX5E SELF TEST";
#define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
struct mlx5ehdr {
__be32 version;
__be64 magic;
char text[ETH_GSTRING_LEN];
};
static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
{
struct sk_buff *skb = NULL;
struct mlx5ehdr *mlxh;
struct ethhdr *ethh;
struct udphdr *udph;
struct iphdr *iph;
int datalen, iplen;
datalen = MLX5E_TEST_PKT_SIZE -
(sizeof(*ethh) + sizeof(*iph) + sizeof(*udph));
skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
if (!skb) {
netdev_err(priv->netdev, "\tFailed to alloc loopback skb\n");
return NULL;
}
prefetchw(skb->data);
skb_reserve(skb, NET_IP_ALIGN);
/* Reserve for ethernet and IP header */
ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb->len);
iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
skb_set_transport_header(skb, skb->len);
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
/* Fill ETH header */
ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr);
eth_zero_addr(ethh->h_source);
ethh->h_proto = htons(ETH_P_IP);
/* Fill UDP header */
udph->source = htons(9);
udph->dest = htons(9); /* Discard Protocol */
udph->len = htons(datalen + sizeof(struct udphdr));
udph->check = 0;
/* Fill IP header */
iph->ihl = 5;
iph->ttl = 32;
iph->version = 4;
iph->protocol = IPPROTO_UDP;
iplen = sizeof(struct iphdr) + sizeof(struct udphdr) + datalen;
iph->tot_len = htons(iplen);
iph->frag_off = 0;
iph->saddr = 0;
iph->daddr = 0;
iph->tos = 0;
iph->id = 0;
ip_send_check(iph);
/* Fill test header and data */
mlxh = (struct mlx5ehdr *)skb_put(skb, sizeof(*mlxh));
mlxh->version = 0;
mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
strlcpy(mlxh->text, mlx5e_test_text, sizeof(mlxh->text));
datalen -= sizeof(*mlxh);
memset(skb_put(skb, datalen), 0, datalen);
skb->csum = 0;
skb->ip_summed = CHECKSUM_PARTIAL;
udp4_hwcsum(skb, iph->saddr, iph->daddr);
skb->protocol = htons(ETH_P_IP);
skb->pkt_type = PACKET_HOST;
skb->dev = priv->netdev;
return skb;
}
struct mlx5e_lbt_priv {
struct packet_type pt;
struct completion comp;
bool loopback_ok;
};
static int
mlx5e_test_loopback_validate(struct sk_buff *skb,
struct net_device *ndev,
struct packet_type *pt,
struct net_device *orig_ndev)
{
struct mlx5e_lbt_priv *lbtp = pt->af_packet_priv;
struct mlx5ehdr *mlxh;
struct ethhdr *ethh;
struct udphdr *udph;
struct iphdr *iph;
/* We are only going to peek, no need to clone the SKB */
if (skb->protocol != htons(ETH_P_IP))
goto out;
if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb))
goto out;
ethh = (struct ethhdr *)skb_mac_header(skb);
if (!ether_addr_equal(ethh->h_dest, orig_ndev->dev_addr))
goto out;
iph = ip_hdr(skb);
if (iph->protocol != IPPROTO_UDP)
goto out;
udph = udp_hdr(skb);
if (udph->dest != htons(9))
goto out;
mlxh = (struct mlx5ehdr *)((char *)udph + sizeof(*udph));
if (mlxh->magic != cpu_to_be64(MLX5E_TEST_MAGIC))
goto out; /* so close ! */
/* bingo */
lbtp->loopback_ok = true;
complete(&lbtp->comp);
out:
kfree_skb(skb);
return 0;
}
static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv,
struct mlx5e_lbt_priv *lbtp)
{
int err = 0;
err = mlx5e_refresh_tirs_self_loopback(priv->mdev, true);
if (err) {
netdev_err(priv->netdev,
"\tFailed to enable UC loopback err(%d)\n", err);
return err;
}
lbtp->loopback_ok = false;
init_completion(&lbtp->comp);
lbtp->pt.type = htons(ETH_P_ALL);
lbtp->pt.func = mlx5e_test_loopback_validate;
lbtp->pt.dev = priv->netdev;
lbtp->pt.af_packet_priv = lbtp;
dev_add_pack(&lbtp->pt);
return err;
}
static void mlx5e_test_loopback_cleanup(struct mlx5e_priv *priv,
struct mlx5e_lbt_priv *lbtp)
{
dev_remove_pack(&lbtp->pt);
mlx5e_refresh_tirs_self_loopback(priv->mdev, false);
}
#define MLX5E_LB_VERIFY_TIMEOUT (msecs_to_jiffies(200))
static int mlx5e_test_loopback(struct mlx5e_priv *priv)
{
struct mlx5e_lbt_priv *lbtp;
struct sk_buff *skb = NULL;
int err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
netdev_err(priv->netdev,
"\tCan't perform loobpack test while device is down\n");
return -ENODEV;
}
lbtp = kzalloc(sizeof(*lbtp), GFP_KERNEL);
if (!lbtp)
return -ENOMEM;
lbtp->loopback_ok = false;
err = mlx5e_test_loopback_setup(priv, lbtp);
if (err)
goto out;
skb = mlx5e_test_get_udp_skb(priv);
if (!skb) {
err = -ENOMEM;
goto cleanup;
}
skb_set_queue_mapping(skb, 0);
err = dev_queue_xmit(skb);
if (err) {
netdev_err(priv->netdev,
"\tFailed to xmit loopback packet err(%d)\n",
err);
goto cleanup;
}
wait_for_completion_timeout(&lbtp->comp, MLX5E_LB_VERIFY_TIMEOUT);
err = !lbtp->loopback_ok;
cleanup:
mlx5e_test_loopback_cleanup(priv, lbtp);
out:
kfree(lbtp);
return err;
}
static int (*mlx5e_st_func[MLX5E_ST_NUM])(struct mlx5e_priv *) = {
mlx5e_test_link_state,
mlx5e_test_link_speed,
mlx5e_test_health_info,
mlx5e_test_loopback
};
void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
u64 *buf)
{
struct mlx5e_priv *priv = netdev_priv(ndev);
int i;
memset(buf, 0, sizeof(u64) * MLX5E_ST_NUM);
mutex_lock(&priv->state_lock);
netdev_info(ndev, "Self test begin..\n");
for (i = 0; i < MLX5E_ST_NUM; i++) {
netdev_info(ndev, "\t[%d] %s start..\n",
i, mlx5e_self_tests[i]);
buf[i] = mlx5e_st_func[i](priv);
netdev_info(ndev, "\t[%d] %s end: result(%lld)\n",
i, mlx5e_self_tests[i], buf[i]);
}
mutex_unlock(&priv->state_lock);
for (i = 0; i < MLX5E_ST_NUM; i++) {
if (buf[i]) {
etest->flags |= ETH_TEST_FL_FAILED;
break;
}
}
netdev_info(ndev, "Self test out: status flags(0x%x)\n",
etest->flags);
}
......@@ -548,6 +548,26 @@ int mlx5_max_tc(struct mlx5_core_dev *mdev)
return num_tc - 1;
}
int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
{
u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
MLX5_SET(dcbx_param, in, port_number, 1);
return mlx5_core_access_reg(mdev, in, sizeof(in), out,
sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
}
int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
{
u32 out[MLX5_ST_SZ_DW(dcbx_param)];
MLX5_SET(dcbx_param, in, port_number, 1);
return mlx5_core_access_reg(mdev, in, sizeof(out), out,
sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
}
int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
{
u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
......@@ -572,6 +592,28 @@ int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
}
EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
u8 prio, u8 *tc)
{
u32 in[MLX5_ST_SZ_DW(qtct_reg)];
u32 out[MLX5_ST_SZ_DW(qtct_reg)];
int err;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
MLX5_SET(qtct_reg, in, port_number, 1);
MLX5_SET(qtct_reg, in, prio, prio);
err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
sizeof(out), MLX5_REG_QTCT, 0, 0);
if (!err)
*tc = MLX5_GET(qtct_reg, out, tclass);
return err;
}
EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
int inlen)
{
......@@ -625,6 +667,27 @@ int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
}
EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
u8 tc, u8 *bw_pct)
{
u32 out[MLX5_ST_SZ_DW(qetc_reg)];
void *ets_tcn_conf;
int err;
err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
if (err)
return err;
ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
tc_configuration[tc]);
*bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
bw_allocation);
return 0;
}
EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
u8 *max_bw_value,
u8 *max_bw_units)
......
......@@ -104,6 +104,8 @@ enum {
enum {
MLX5_REG_QETCR = 0x4005,
MLX5_REG_QTCT = 0x400a,
MLX5_REG_DCBX_PARAM = 0x4020,
MLX5_REG_DCBX_APP = 0x4021,
MLX5_REG_PCAP = 0x5001,
MLX5_REG_PMTU = 0x5003,
MLX5_REG_PTYS = 0x5004,
......@@ -124,6 +126,11 @@ enum {
MLX5_REG_MPCNT = 0x9051,
};
enum mlx5_dcbx_oper_mode {
MLX5E_DCBX_PARAM_VER_OPER_HOST = 0x0,
MLX5E_DCBX_PARAM_VER_OPER_AUTO = 0x3,
};
enum {
MLX5_ATOMIC_OPS_CMP_SWAP = 1 << 0,
MLX5_ATOMIC_OPS_FETCH_ADD = 1 << 1,
......
......@@ -141,8 +141,12 @@ int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx,
int mlx5_max_tc(struct mlx5_core_dev *mdev);
int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc);
int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
u8 prio, u8 *tc);
int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group);
int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw);
int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
u8 tc, u8 *bw_pct);
int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
u8 *max_bw_value,
u8 *max_bw_unit);
......@@ -158,4 +162,6 @@ void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
u16 offset, u16 size, u8 *data);
int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out);
int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in);
#endif /* __MLX5_PORT_H__ */
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