Merge branch 'mlx5e-100G-extensions'
Saeed Mahameed says:
====================
Mellanox 100G mlx5e Ethernet extensions
This series includes multiple features extensions for mlx5 Ethernet netdevice driver.
Namely, TX Rate limiting, RX interrupt moderation, ethtool settings.
TX Rate limiting:
- ConnectX-4 rate limiting infrastructure
- Set max rate NDO support
RX interrupt moderation:
- CQE based coalescing option (controlled via priv flags)
- Adaptive RX coalescing
ethtool settings:
- priv flags callbacks
- Support new ksettings API
- Add 50G missing link mode
- Support auto negotiation on/off
Applied on top: 0e9390ebf1
("Merge branch 'mlxsw-next'")
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5502bef3e7
|
@ -1,11 +1,13 @@
|
|||
obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
|
||||
|
||||
mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
|
||||
health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
|
||||
mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o fs_counters.o
|
||||
health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
|
||||
mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
|
||||
fs_counters.o rl.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o \
|
||||
en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \
|
||||
en_txrx.o en_clock.o vxlan.o en_tc.o en_arfs.o
|
||||
en_rx_am.o en_txrx.o en_clock.o vxlan.o en_tc.o \
|
||||
en_arfs.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
|
||||
#define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (64 * 1024)
|
||||
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10
|
||||
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE 0x3
|
||||
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20
|
||||
#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC 0x10
|
||||
#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS 0x20
|
||||
|
@ -88,6 +89,7 @@
|
|||
#define MLX5E_LOG_INDIR_RQT_SIZE 0x7
|
||||
#define MLX5E_INDIR_RQT_SIZE BIT(MLX5E_LOG_INDIR_RQT_SIZE)
|
||||
#define MLX5E_MAX_NUM_CHANNELS (MLX5E_INDIR_RQT_SIZE >> 1)
|
||||
#define MLX5E_MAX_NUM_SQS (MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC)
|
||||
#define MLX5E_TX_CQ_POLL_BUDGET 128
|
||||
#define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */
|
||||
#define MLX5E_SQ_BF_BUDGET 16
|
||||
|
@ -143,11 +145,32 @@ struct mlx5e_umr_wqe {
|
|||
struct mlx5_wqe_data_seg data;
|
||||
};
|
||||
|
||||
static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = {
|
||||
"rx_cqe_moder",
|
||||
};
|
||||
|
||||
enum mlx5e_priv_flag {
|
||||
MLX5E_PFLAG_RX_CQE_BASED_MODER = (1 << 0),
|
||||
};
|
||||
|
||||
#define MLX5E_SET_PRIV_FLAG(priv, pflag, enable) \
|
||||
do { \
|
||||
if (enable) \
|
||||
priv->pflags |= pflag; \
|
||||
else \
|
||||
priv->pflags &= ~pflag; \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN_DCB
|
||||
#define MLX5E_MAX_BW_ALLOC 100 /* Max percentage of BW allocation */
|
||||
#define MLX5E_MIN_BW_ALLOC 1 /* Min percentage of BW allocation */
|
||||
#endif
|
||||
|
||||
struct mlx5e_cq_moder {
|
||||
u16 usec;
|
||||
u16 pkts;
|
||||
};
|
||||
|
||||
struct mlx5e_params {
|
||||
u8 log_sq_size;
|
||||
u8 rq_wq_type;
|
||||
|
@ -156,12 +179,11 @@ struct mlx5e_params {
|
|||
u8 log_rq_size;
|
||||
u16 num_channels;
|
||||
u8 num_tc;
|
||||
u8 rx_cq_period_mode;
|
||||
bool rx_cqe_compress_admin;
|
||||
bool rx_cqe_compress;
|
||||
u16 rx_cq_moderation_usec;
|
||||
u16 rx_cq_moderation_pkts;
|
||||
u16 tx_cq_moderation_usec;
|
||||
u16 tx_cq_moderation_pkts;
|
||||
struct mlx5e_cq_moder rx_cq_moderation;
|
||||
struct mlx5e_cq_moder tx_cq_moderation;
|
||||
u16 min_rx_wqes;
|
||||
bool lro_en;
|
||||
u32 lro_wqe_sz;
|
||||
|
@ -173,6 +195,7 @@ struct mlx5e_params {
|
|||
#ifdef CONFIG_MLX5_CORE_EN_DCB
|
||||
struct ieee_ets ets;
|
||||
#endif
|
||||
bool rx_am_enabled;
|
||||
};
|
||||
|
||||
struct mlx5e_tstamp {
|
||||
|
@ -191,6 +214,7 @@ struct mlx5e_tstamp {
|
|||
enum {
|
||||
MLX5E_RQ_STATE_POST_WQES_ENABLE,
|
||||
MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS,
|
||||
MLX5E_RQ_STATE_AM,
|
||||
};
|
||||
|
||||
struct mlx5e_cq {
|
||||
|
@ -198,6 +222,7 @@ struct mlx5e_cq {
|
|||
struct mlx5_cqwq wq;
|
||||
|
||||
/* data path - accessed per napi poll */
|
||||
u16 event_ctr;
|
||||
struct napi_struct *napi;
|
||||
struct mlx5_core_cq mcq;
|
||||
struct mlx5e_channel *channel;
|
||||
|
@ -225,6 +250,30 @@ struct mlx5e_dma_info {
|
|||
dma_addr_t addr;
|
||||
};
|
||||
|
||||
struct mlx5e_rx_am_stats {
|
||||
int ppms; /* packets per msec */
|
||||
int epms; /* events per msec */
|
||||
};
|
||||
|
||||
struct mlx5e_rx_am_sample {
|
||||
ktime_t time;
|
||||
unsigned int pkt_ctr;
|
||||
u16 event_ctr;
|
||||
};
|
||||
|
||||
struct mlx5e_rx_am { /* Adaptive Moderation */
|
||||
u8 state;
|
||||
struct mlx5e_rx_am_stats prev_stats;
|
||||
struct mlx5e_rx_am_sample start_sample;
|
||||
struct work_struct work;
|
||||
u8 profile_ix;
|
||||
u8 mode;
|
||||
u8 tune_state;
|
||||
u8 steps_right;
|
||||
u8 steps_left;
|
||||
u8 tired;
|
||||
};
|
||||
|
||||
struct mlx5e_rq {
|
||||
/* data path */
|
||||
struct mlx5_wq_ll wq;
|
||||
|
@ -245,6 +294,8 @@ struct mlx5e_rq {
|
|||
unsigned long state;
|
||||
int ix;
|
||||
|
||||
struct mlx5e_rx_am am; /* Adaptive Moderation */
|
||||
|
||||
/* control */
|
||||
struct mlx5_wq_ctrl wq_ctrl;
|
||||
u8 wq_type;
|
||||
|
@ -354,6 +405,7 @@ struct mlx5e_sq {
|
|||
struct mlx5e_channel *channel;
|
||||
int tc;
|
||||
struct mlx5e_ico_wqe_info *ico_wqe_info;
|
||||
u32 rate_limit;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
static inline bool mlx5e_sq_has_room_for(struct mlx5e_sq *sq, u16 n)
|
||||
|
@ -530,6 +582,7 @@ struct mlx5e_priv {
|
|||
u32 indir_rqtn;
|
||||
u32 indir_tirn[MLX5E_NUM_INDIR_TIRS];
|
||||
struct mlx5e_direct_tir direct_tir[MLX5E_MAX_NUM_CHANNELS];
|
||||
u32 tx_rates[MLX5E_MAX_NUM_SQS];
|
||||
|
||||
struct mlx5e_flow_steering fs;
|
||||
struct mlx5e_vxlan_db vxlan;
|
||||
|
@ -540,6 +593,7 @@ struct mlx5e_priv {
|
|||
struct work_struct set_rx_mode_work;
|
||||
struct delayed_work update_stats_work;
|
||||
|
||||
u32 pflags;
|
||||
struct mlx5_core_dev *mdev;
|
||||
struct net_device *netdev;
|
||||
struct mlx5e_stats stats;
|
||||
|
@ -562,6 +616,7 @@ enum mlx5e_link_mode {
|
|||
MLX5E_10GBASE_ER = 14,
|
||||
MLX5E_40GBASE_SR4 = 15,
|
||||
MLX5E_40GBASE_LR4 = 16,
|
||||
MLX5E_50GBASE_SR2 = 18,
|
||||
MLX5E_100GBASE_CR4 = 20,
|
||||
MLX5E_100GBASE_SR4 = 21,
|
||||
MLX5E_100GBASE_KR4 = 22,
|
||||
|
@ -579,6 +634,9 @@ enum mlx5e_link_mode {
|
|||
|
||||
#define MLX5E_PROT_MASK(link_mode) (1 << link_mode)
|
||||
|
||||
|
||||
void mlx5e_build_ptys2ethtool_map(void);
|
||||
|
||||
void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw);
|
||||
u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
|
||||
void *accel_priv, select_queue_fallback_t fallback);
|
||||
|
@ -612,6 +670,10 @@ void mlx5e_free_rx_fragmented_mpwqe(struct mlx5e_rq *rq,
|
|||
struct mlx5e_mpw_info *wi);
|
||||
struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq);
|
||||
|
||||
void mlx5e_rx_am(struct mlx5e_rq *rq);
|
||||
void mlx5e_rx_am_work(struct work_struct *work);
|
||||
struct mlx5e_cq_moder mlx5e_am_get_def_profile(u8 rx_cq_period_mode);
|
||||
|
||||
void mlx5e_update_stats(struct mlx5e_priv *priv);
|
||||
|
||||
int mlx5e_create_flow_steering(struct mlx5e_priv *priv);
|
||||
|
@ -647,6 +709,9 @@ void mlx5e_build_default_indir_rqt(struct mlx5_core_dev *mdev,
|
|||
int num_channels);
|
||||
int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
|
||||
|
||||
void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params,
|
||||
u8 cq_period_mode);
|
||||
|
||||
static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
|
||||
struct mlx5_wqe_ctrl_seg *ctrl, int bf_sz)
|
||||
{
|
||||
|
|
|
@ -191,7 +191,6 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev,
|
|||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(dev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
enum mlx5_port_status ps;
|
||||
u8 curr_pfc_en;
|
||||
int ret;
|
||||
|
||||
|
@ -200,14 +199,8 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev,
|
|||
if (pfc->pfc_en == curr_pfc_en)
|
||||
return 0;
|
||||
|
||||
mlx5_query_port_admin_status(mdev, &ps);
|
||||
if (ps == MLX5_PORT_UP)
|
||||
mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN);
|
||||
|
||||
ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en);
|
||||
|
||||
if (ps == MLX5_PORT_UP)
|
||||
mlx5_set_port_admin_status(mdev, MLX5_PORT_UP);
|
||||
mlx5_toggle_port_link(mdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -48,123 +48,85 @@ static void mlx5e_get_drvinfo(struct net_device *dev,
|
|||
sizeof(drvinfo->bus_info));
|
||||
}
|
||||
|
||||
static const struct {
|
||||
u32 supported;
|
||||
u32 advertised;
|
||||
struct ptys2ethtool_config {
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertised);
|
||||
u32 speed;
|
||||
} ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER] = {
|
||||
[MLX5E_1000BASE_CX_SGMII] = {
|
||||
.supported = SUPPORTED_1000baseKX_Full,
|
||||
.advertised = ADVERTISED_1000baseKX_Full,
|
||||
.speed = 1000,
|
||||
},
|
||||
[MLX5E_1000BASE_KX] = {
|
||||
.supported = SUPPORTED_1000baseKX_Full,
|
||||
.advertised = ADVERTISED_1000baseKX_Full,
|
||||
.speed = 1000,
|
||||
},
|
||||
[MLX5E_10GBASE_CX4] = {
|
||||
.supported = SUPPORTED_10000baseKX4_Full,
|
||||
.advertised = ADVERTISED_10000baseKX4_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_10GBASE_KX4] = {
|
||||
.supported = SUPPORTED_10000baseKX4_Full,
|
||||
.advertised = ADVERTISED_10000baseKX4_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_10GBASE_KR] = {
|
||||
.supported = SUPPORTED_10000baseKR_Full,
|
||||
.advertised = ADVERTISED_10000baseKR_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_20GBASE_KR2] = {
|
||||
.supported = SUPPORTED_20000baseKR2_Full,
|
||||
.advertised = ADVERTISED_20000baseKR2_Full,
|
||||
.speed = 20000,
|
||||
},
|
||||
[MLX5E_40GBASE_CR4] = {
|
||||
.supported = SUPPORTED_40000baseCR4_Full,
|
||||
.advertised = ADVERTISED_40000baseCR4_Full,
|
||||
.speed = 40000,
|
||||
},
|
||||
[MLX5E_40GBASE_KR4] = {
|
||||
.supported = SUPPORTED_40000baseKR4_Full,
|
||||
.advertised = ADVERTISED_40000baseKR4_Full,
|
||||
.speed = 40000,
|
||||
},
|
||||
[MLX5E_56GBASE_R4] = {
|
||||
.supported = SUPPORTED_56000baseKR4_Full,
|
||||
.advertised = ADVERTISED_56000baseKR4_Full,
|
||||
.speed = 56000,
|
||||
},
|
||||
[MLX5E_10GBASE_CR] = {
|
||||
.supported = SUPPORTED_10000baseKR_Full,
|
||||
.advertised = ADVERTISED_10000baseKR_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_10GBASE_SR] = {
|
||||
.supported = SUPPORTED_10000baseKR_Full,
|
||||
.advertised = ADVERTISED_10000baseKR_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_10GBASE_ER] = {
|
||||
.supported = SUPPORTED_10000baseKR_Full,
|
||||
.advertised = ADVERTISED_10000baseKR_Full,
|
||||
.speed = 10000,
|
||||
},
|
||||
[MLX5E_40GBASE_SR4] = {
|
||||
.supported = SUPPORTED_40000baseSR4_Full,
|
||||
.advertised = ADVERTISED_40000baseSR4_Full,
|
||||
.speed = 40000,
|
||||
},
|
||||
[MLX5E_40GBASE_LR4] = {
|
||||
.supported = SUPPORTED_40000baseLR4_Full,
|
||||
.advertised = ADVERTISED_40000baseLR4_Full,
|
||||
.speed = 40000,
|
||||
},
|
||||
[MLX5E_100GBASE_CR4] = {
|
||||
.speed = 100000,
|
||||
},
|
||||
[MLX5E_100GBASE_SR4] = {
|
||||
.speed = 100000,
|
||||
},
|
||||
[MLX5E_100GBASE_KR4] = {
|
||||
.speed = 100000,
|
||||
},
|
||||
[MLX5E_100GBASE_LR4] = {
|
||||
.speed = 100000,
|
||||
},
|
||||
[MLX5E_100BASE_TX] = {
|
||||
.speed = 100,
|
||||
},
|
||||
[MLX5E_1000BASE_T] = {
|
||||
.supported = SUPPORTED_1000baseT_Full,
|
||||
.advertised = ADVERTISED_1000baseT_Full,
|
||||
.speed = 1000,
|
||||
},
|
||||
[MLX5E_10GBASE_T] = {
|
||||
.supported = SUPPORTED_10000baseT_Full,
|
||||
.advertised = ADVERTISED_10000baseT_Full,
|
||||
.speed = 1000,
|
||||
},
|
||||
[MLX5E_25GBASE_CR] = {
|
||||
.speed = 25000,
|
||||
},
|
||||
[MLX5E_25GBASE_KR] = {
|
||||
.speed = 25000,
|
||||
},
|
||||
[MLX5E_25GBASE_SR] = {
|
||||
.speed = 25000,
|
||||
},
|
||||
[MLX5E_50GBASE_CR2] = {
|
||||
.speed = 50000,
|
||||
},
|
||||
[MLX5E_50GBASE_KR2] = {
|
||||
.speed = 50000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER];
|
||||
|
||||
#define MLX5_BUILD_PTYS2ETHTOOL_CONFIG(reg_, speed_, ...) \
|
||||
({ \
|
||||
struct ptys2ethtool_config *cfg; \
|
||||
const unsigned int modes[] = { __VA_ARGS__ }; \
|
||||
unsigned int i; \
|
||||
cfg = &ptys2ethtool_table[reg_]; \
|
||||
cfg->speed = speed_; \
|
||||
bitmap_zero(cfg->supported, \
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS); \
|
||||
bitmap_zero(cfg->advertised, \
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS); \
|
||||
for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \
|
||||
__set_bit(modes[i], cfg->supported); \
|
||||
__set_bit(modes[i], cfg->advertised); \
|
||||
} \
|
||||
})
|
||||
|
||||
void mlx5e_build_ptys2ethtool_map(void)
|
||||
{
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_CX_SGMII, SPEED_1000,
|
||||
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_KX, SPEED_1000,
|
||||
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CX4, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KX4, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KR, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_20GBASE_KR2, SPEED_20000,
|
||||
ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_CR4, SPEED_40000,
|
||||
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_KR4, SPEED_40000,
|
||||
ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_56GBASE_R4, SPEED_56000,
|
||||
ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CR, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_SR, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_ER, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_SR4, SPEED_40000,
|
||||
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_LR4, SPEED_40000,
|
||||
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_SR2, SPEED_50000,
|
||||
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_CR4, SPEED_100000,
|
||||
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_SR4, SPEED_100000,
|
||||
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_KR4, SPEED_100000,
|
||||
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_LR4, SPEED_100000,
|
||||
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_T, SPEED_10000,
|
||||
ETHTOOL_LINK_MODE_10000baseT_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_CR, SPEED_25000,
|
||||
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_KR, SPEED_25000,
|
||||
ETHTOOL_LINK_MODE_25000baseKR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_SR, SPEED_25000,
|
||||
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_CR2, SPEED_50000,
|
||||
ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT);
|
||||
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_KR2, SPEED_50000,
|
||||
ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT);
|
||||
}
|
||||
|
||||
static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
|
@ -198,6 +160,8 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
|
|||
MLX5E_NUM_RQ_STATS(priv) +
|
||||
MLX5E_NUM_SQ_STATS(priv) +
|
||||
MLX5E_NUM_PFC_COUNTERS(priv);
|
||||
case ETH_SS_PRIV_FLAGS:
|
||||
return ARRAY_SIZE(mlx5e_priv_flags);
|
||||
/* fallthrough */
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -272,9 +236,12 @@ static void mlx5e_get_strings(struct net_device *dev,
|
|||
uint32_t stringset, uint8_t *data)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_PRIV_FLAGS:
|
||||
for (i = 0; i < ARRAY_SIZE(mlx5e_priv_flags); i++)
|
||||
strcpy(data + i * ETH_GSTRING_LEN, mlx5e_priv_flags[i]);
|
||||
break;
|
||||
|
||||
case ETH_SS_TEST:
|
||||
|
@ -519,10 +486,11 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
|
|||
if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
|
||||
return -ENOTSUPP;
|
||||
|
||||
coal->rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
|
||||
coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
|
||||
coal->tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
|
||||
coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation_pkts;
|
||||
coal->rx_coalesce_usecs = priv->params.rx_cq_moderation.usec;
|
||||
coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation.pkts;
|
||||
coal->tx_coalesce_usecs = priv->params.tx_cq_moderation.usec;
|
||||
coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation.pkts;
|
||||
coal->use_adaptive_rx_coalesce = priv->params.rx_am_enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -533,6 +501,10 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
|
|||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
struct mlx5e_channel *c;
|
||||
bool restart =
|
||||
!!coal->use_adaptive_rx_coalesce != priv->params.rx_am_enabled;
|
||||
bool was_opened;
|
||||
int err = 0;
|
||||
int tc;
|
||||
int i;
|
||||
|
||||
|
@ -540,12 +512,19 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
|
|||
return -ENOTSUPP;
|
||||
|
||||
mutex_lock(&priv->state_lock);
|
||||
priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
|
||||
priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
|
||||
priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
|
||||
priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
|
||||
|
||||
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
|
||||
was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
|
||||
if (was_opened && restart) {
|
||||
mlx5e_close_locked(netdev);
|
||||
priv->params.rx_am_enabled = !!coal->use_adaptive_rx_coalesce;
|
||||
}
|
||||
|
||||
priv->params.tx_cq_moderation.usec = coal->tx_coalesce_usecs;
|
||||
priv->params.tx_cq_moderation.pkts = coal->tx_max_coalesced_frames;
|
||||
priv->params.rx_cq_moderation.usec = coal->rx_coalesce_usecs;
|
||||
priv->params.rx_cq_moderation.pkts = coal->rx_max_coalesced_frames;
|
||||
|
||||
if (!was_opened || restart)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < priv->params.num_channels; ++i) {
|
||||
|
@ -564,35 +543,37 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
|
|||
}
|
||||
|
||||
out:
|
||||
if (was_opened && restart)
|
||||
err = mlx5e_open_locked(netdev);
|
||||
|
||||
mutex_unlock(&priv->state_lock);
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32 ptys2ethtool_supported_link(u32 eth_proto_cap)
|
||||
static void ptys2ethtool_supported_link(unsigned long *supported_modes,
|
||||
u32 eth_proto_cap)
|
||||
{
|
||||
int i;
|
||||
u32 supported_modes = 0;
|
||||
int proto;
|
||||
|
||||
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
|
||||
if (eth_proto_cap & MLX5E_PROT_MASK(i))
|
||||
supported_modes |= ptys2ethtool_table[i].supported;
|
||||
}
|
||||
return supported_modes;
|
||||
for_each_set_bit(proto, (unsigned long *)ð_proto_cap, MLX5E_LINK_MODES_NUMBER)
|
||||
bitmap_or(supported_modes, supported_modes,
|
||||
ptys2ethtool_table[proto].supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
}
|
||||
|
||||
static u32 ptys2ethtool_adver_link(u32 eth_proto_cap)
|
||||
static void ptys2ethtool_adver_link(unsigned long *advertising_modes,
|
||||
u32 eth_proto_cap)
|
||||
{
|
||||
int i;
|
||||
u32 advertising_modes = 0;
|
||||
int proto;
|
||||
|
||||
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
|
||||
if (eth_proto_cap & MLX5E_PROT_MASK(i))
|
||||
advertising_modes |= ptys2ethtool_table[i].advertised;
|
||||
}
|
||||
return advertising_modes;
|
||||
for_each_set_bit(proto, (unsigned long *)ð_proto_cap, MLX5E_LINK_MODES_NUMBER)
|
||||
bitmap_or(advertising_modes, advertising_modes,
|
||||
ptys2ethtool_table[proto].advertised,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
}
|
||||
|
||||
static u32 ptys2ethtool_supported_port(u32 eth_proto_cap)
|
||||
static void ptys2ethtool_supported_port(struct ethtool_link_ksettings *link_ksettings,
|
||||
u32 eth_proto_cap)
|
||||
{
|
||||
if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR)
|
||||
| MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
|
||||
|
@ -600,7 +581,7 @@ static u32 ptys2ethtool_supported_port(u32 eth_proto_cap)
|
|||
| MLX5E_PROT_MASK(MLX5E_40GBASE_SR4)
|
||||
| MLX5E_PROT_MASK(MLX5E_100GBASE_SR4)
|
||||
| MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) {
|
||||
return SUPPORTED_FIBRE;
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, FIBRE);
|
||||
}
|
||||
|
||||
if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4)
|
||||
|
@ -608,9 +589,8 @@ static u32 ptys2ethtool_supported_port(u32 eth_proto_cap)
|
|||
| MLX5E_PROT_MASK(MLX5E_10GBASE_KR)
|
||||
| MLX5E_PROT_MASK(MLX5E_10GBASE_KX4)
|
||||
| MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) {
|
||||
return SUPPORTED_Backplane;
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Backplane);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
|
||||
|
@ -634,7 +614,7 @@ int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
|
|||
|
||||
static void get_speed_duplex(struct net_device *netdev,
|
||||
u32 eth_proto_oper,
|
||||
struct ethtool_cmd *cmd)
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
int i;
|
||||
u32 speed = SPEED_UNKNOWN;
|
||||
|
@ -651,23 +631,32 @@ static void get_speed_duplex(struct net_device *netdev,
|
|||
}
|
||||
}
|
||||
out:
|
||||
ethtool_cmd_speed_set(cmd, speed);
|
||||
cmd->duplex = duplex;
|
||||
link_ksettings->base.speed = speed;
|
||||
link_ksettings->base.duplex = duplex;
|
||||
}
|
||||
|
||||
static void get_supported(u32 eth_proto_cap, u32 *supported)
|
||||
static void get_supported(u32 eth_proto_cap,
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
*supported |= ptys2ethtool_supported_port(eth_proto_cap);
|
||||
*supported |= ptys2ethtool_supported_link(eth_proto_cap);
|
||||
*supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
unsigned long *supported = link_ksettings->link_modes.supported;
|
||||
|
||||
ptys2ethtool_supported_port(link_ksettings, eth_proto_cap);
|
||||
ptys2ethtool_supported_link(supported, eth_proto_cap);
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Pause);
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Asym_Pause);
|
||||
}
|
||||
|
||||
static void get_advertising(u32 eth_proto_cap, u8 tx_pause,
|
||||
u8 rx_pause, u32 *advertising)
|
||||
u8 rx_pause,
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
*advertising |= ptys2ethtool_adver_link(eth_proto_cap);
|
||||
*advertising |= tx_pause ? ADVERTISED_Pause : 0;
|
||||
*advertising |= (tx_pause ^ rx_pause) ? ADVERTISED_Asym_Pause : 0;
|
||||
unsigned long *advertising = link_ksettings->link_modes.advertising;
|
||||
|
||||
ptys2ethtool_adver_link(advertising, eth_proto_cap);
|
||||
if (tx_pause)
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Pause);
|
||||
if (tx_pause ^ rx_pause)
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Asym_Pause);
|
||||
}
|
||||
|
||||
static u8 get_connector_port(u32 eth_proto)
|
||||
|
@ -695,13 +684,16 @@ static u8 get_connector_port(u32 eth_proto)
|
|||
return PORT_OTHER;
|
||||
}
|
||||
|
||||
static void get_lp_advertising(u32 eth_proto_lp, u32 *lp_advertising)
|
||||
static void get_lp_advertising(u32 eth_proto_lp,
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
*lp_advertising = ptys2ethtool_adver_link(eth_proto_lp);
|
||||
unsigned long *lp_advertising = link_ksettings->link_modes.lp_advertising;
|
||||
|
||||
ptys2ethtool_adver_link(lp_advertising, eth_proto_lp);
|
||||
}
|
||||
|
||||
static int mlx5e_get_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *cmd)
|
||||
static int mlx5e_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
|
@ -710,6 +702,8 @@ static int mlx5e_get_settings(struct net_device *netdev,
|
|||
u32 eth_proto_admin;
|
||||
u32 eth_proto_lp;
|
||||
u32 eth_proto_oper;
|
||||
u8 an_disable_admin;
|
||||
u8 an_status;
|
||||
int err;
|
||||
|
||||
err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1);
|
||||
|
@ -720,35 +714,49 @@ static int mlx5e_get_settings(struct net_device *netdev,
|
|||
goto err_query_ptys;
|
||||
}
|
||||
|
||||
eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
|
||||
eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
|
||||
eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
|
||||
eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
|
||||
eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
|
||||
eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
|
||||
eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
|
||||
eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
|
||||
an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
|
||||
an_status = MLX5_GET(ptys_reg, out, an_status);
|
||||
|
||||
cmd->supported = 0;
|
||||
cmd->advertising = 0;
|
||||
ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
|
||||
ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
|
||||
|
||||
get_supported(eth_proto_cap, &cmd->supported);
|
||||
get_advertising(eth_proto_admin, 0, 0, &cmd->advertising);
|
||||
get_speed_duplex(netdev, eth_proto_oper, cmd);
|
||||
get_supported(eth_proto_cap, link_ksettings);
|
||||
get_advertising(eth_proto_admin, 0, 0, link_ksettings);
|
||||
get_speed_duplex(netdev, eth_proto_oper, link_ksettings);
|
||||
|
||||
eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
|
||||
|
||||
cmd->port = get_connector_port(eth_proto_oper);
|
||||
get_lp_advertising(eth_proto_lp, &cmd->lp_advertising);
|
||||
link_ksettings->base.port = get_connector_port(eth_proto_oper);
|
||||
get_lp_advertising(eth_proto_lp, link_ksettings);
|
||||
|
||||
cmd->transceiver = XCVR_INTERNAL;
|
||||
if (an_status == MLX5_AN_COMPLETE)
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings,
|
||||
lp_advertising, Autoneg);
|
||||
|
||||
link_ksettings->base.autoneg = an_disable_admin ? AUTONEG_DISABLE :
|
||||
AUTONEG_ENABLE;
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
|
||||
Autoneg);
|
||||
if (!an_disable_admin)
|
||||
ethtool_link_ksettings_add_link_mode(link_ksettings,
|
||||
advertising, Autoneg);
|
||||
|
||||
err_query_ptys:
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32 mlx5e_ethtool2ptys_adver_link(u32 link_modes)
|
||||
static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes)
|
||||
{
|
||||
u32 i, ptys_modes = 0;
|
||||
|
||||
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
|
||||
if (ptys2ethtool_table[i].advertised & link_modes)
|
||||
if (bitmap_intersects(ptys2ethtool_table[i].advertised,
|
||||
link_modes,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS))
|
||||
ptys_modes |= MLX5E_PROT_MASK(i);
|
||||
}
|
||||
|
||||
|
@ -767,21 +775,25 @@ static u32 mlx5e_ethtool2ptys_speed_link(u32 speed)
|
|||
return speed_links;
|
||||
}
|
||||
|
||||
static int mlx5e_set_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *cmd)
|
||||
static int mlx5e_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *link_ksettings)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
u32 link_modes;
|
||||
u32 speed;
|
||||
u32 eth_proto_cap, eth_proto_admin;
|
||||
enum mlx5_port_status ps;
|
||||
bool an_changes = false;
|
||||
u8 an_disable_admin;
|
||||
u8 an_disable_cap;
|
||||
bool an_disable;
|
||||
u32 link_modes;
|
||||
u8 an_status;
|
||||
u32 speed;
|
||||
int err;
|
||||
|
||||
speed = ethtool_cmd_speed(cmd);
|
||||
speed = link_ksettings->base.speed;
|
||||
|
||||
link_modes = cmd->autoneg == AUTONEG_ENABLE ?
|
||||
mlx5e_ethtool2ptys_adver_link(cmd->advertising) :
|
||||
link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
|
||||
mlx5e_ethtool2ptys_adver_link(link_ksettings->link_modes.advertising) :
|
||||
mlx5e_ethtool2ptys_speed_link(speed);
|
||||
|
||||
err = mlx5_query_port_proto_cap(mdev, ð_proto_cap, MLX5_PTYS_EN);
|
||||
|
@ -806,15 +818,18 @@ static int mlx5e_set_settings(struct net_device *netdev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (link_modes == eth_proto_admin)
|
||||
mlx5_query_port_autoneg(mdev, MLX5_PTYS_EN, &an_status,
|
||||
&an_disable_cap, &an_disable_admin);
|
||||
|
||||
an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE;
|
||||
an_changes = ((!an_disable && an_disable_admin) ||
|
||||
(an_disable && !an_disable_admin));
|
||||
|
||||
if (!an_changes && link_modes == eth_proto_admin)
|
||||
goto out;
|
||||
|
||||
mlx5_query_port_admin_status(mdev, &ps);
|
||||
if (ps == MLX5_PORT_UP)
|
||||
mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN);
|
||||
mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN);
|
||||
if (ps == MLX5_PORT_UP)
|
||||
mlx5_set_port_admin_status(mdev, MLX5_PORT_UP);
|
||||
mlx5_set_port_ptys(mdev, an_disable, link_modes, MLX5_PTYS_EN);
|
||||
mlx5_toggle_port_link(mdev);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
@ -1272,6 +1287,87 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*mlx5e_pflag_handler)(struct net_device *netdev, bool enable);
|
||||
|
||||
static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
bool rx_mode_changed;
|
||||
u8 rx_cq_period_mode;
|
||||
int err = 0;
|
||||
bool reset;
|
||||
|
||||
rx_cq_period_mode = enable ?
|
||||
MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
|
||||
MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
|
||||
rx_mode_changed = rx_cq_period_mode != priv->params.rx_cq_period_mode;
|
||||
|
||||
if (rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE &&
|
||||
!MLX5_CAP_GEN(mdev, cq_period_start_from_cqe))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (!rx_mode_changed)
|
||||
return 0;
|
||||
|
||||
reset = test_bit(MLX5E_STATE_OPENED, &priv->state);
|
||||
if (reset)
|
||||
mlx5e_close_locked(netdev);
|
||||
|
||||
mlx5e_set_rx_cq_mode_params(&priv->params, rx_cq_period_mode);
|
||||
|
||||
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,
|
||||
mlx5e_pflag_handler pflag_handler)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
bool enable = !!(wanted_flags & flag);
|
||||
u32 changes = wanted_flags ^ priv->pflags;
|
||||
int err;
|
||||
|
||||
if (!(changes & flag))
|
||||
return 0;
|
||||
|
||||
err = pflag_handler(netdev, enable);
|
||||
if (err) {
|
||||
netdev_err(netdev, "%s private flag 0x%x failed err %d\n",
|
||||
enable ? "Enable" : "Disable", flag, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
MLX5E_SET_PRIV_FLAG(priv, flag, enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
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);
|
||||
|
||||
mutex_unlock(&priv->state_lock);
|
||||
return err ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static u32 mlx5e_get_priv_flags(struct net_device *netdev)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
|
||||
return priv->pflags;
|
||||
}
|
||||
|
||||
const struct ethtool_ops mlx5e_ethtool_ops = {
|
||||
.get_drvinfo = mlx5e_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
|
@ -1284,8 +1380,8 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
|
|||
.set_channels = mlx5e_set_channels,
|
||||
.get_coalesce = mlx5e_get_coalesce,
|
||||
.set_coalesce = mlx5e_set_coalesce,
|
||||
.get_settings = mlx5e_get_settings,
|
||||
.set_settings = mlx5e_set_settings,
|
||||
.get_link_ksettings = mlx5e_get_link_ksettings,
|
||||
.set_link_ksettings = mlx5e_set_link_ksettings,
|
||||
.get_rxfh_key_size = mlx5e_get_rxfh_key_size,
|
||||
.get_rxfh_indir_size = mlx5e_get_rxfh_indir_size,
|
||||
.get_rxfh = mlx5e_get_rxfh,
|
||||
|
@ -1301,4 +1397,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
|
|||
.set_wol = mlx5e_set_wol,
|
||||
.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
|
||||
};
|
||||
|
|
|
@ -40,8 +40,9 @@
|
|||
#include "vxlan.h"
|
||||
|
||||
struct mlx5e_rq_param {
|
||||
u32 rqc[MLX5_ST_SZ_DW(rqc)];
|
||||
struct mlx5_wq_param wq;
|
||||
u32 rqc[MLX5_ST_SZ_DW(rqc)];
|
||||
struct mlx5_wq_param wq;
|
||||
bool am_enabled;
|
||||
};
|
||||
|
||||
struct mlx5e_sq_param {
|
||||
|
@ -55,6 +56,7 @@ struct mlx5e_cq_param {
|
|||
u32 cqc[MLX5_ST_SZ_DW(cqc)];
|
||||
struct mlx5_wq_param wq;
|
||||
u16 eq_ix;
|
||||
u8 cq_period_mode;
|
||||
};
|
||||
|
||||
struct mlx5e_channel_param {
|
||||
|
@ -336,6 +338,9 @@ static int mlx5e_create_rq(struct mlx5e_channel *c,
|
|||
wqe->data.byte_count = cpu_to_be32(byte_count);
|
||||
}
|
||||
|
||||
INIT_WORK(&rq->am.work, mlx5e_rx_am_work);
|
||||
rq->am.mode = priv->params.rx_cq_period_mode;
|
||||
|
||||
rq->wq_type = priv->params.rq_wq_type;
|
||||
rq->pdev = c->pdev;
|
||||
rq->netdev = c->netdev;
|
||||
|
@ -508,6 +513,9 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
|
|||
if (err)
|
||||
goto err_disable_rq;
|
||||
|
||||
if (param->am_enabled)
|
||||
set_bit(MLX5E_RQ_STATE_AM, &c->rq.state);
|
||||
|
||||
set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
|
||||
|
||||
sq->ico_wqe_info[pi].opcode = MLX5_OPCODE_NOP;
|
||||
|
@ -536,6 +544,8 @@ static void mlx5e_close_rq(struct mlx5e_rq *rq)
|
|||
/* avoid destroying rq before mlx5e_poll_rx_cq() is done with it */
|
||||
napi_synchronize(&rq->channel->napi);
|
||||
|
||||
cancel_work_sync(&rq->am.work);
|
||||
|
||||
mlx5e_disable_rq(rq);
|
||||
mlx5e_destroy_rq(rq);
|
||||
}
|
||||
|
@ -702,7 +712,8 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state)
|
||||
static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state,
|
||||
int next_state, bool update_rl, int rl_index)
|
||||
{
|
||||
struct mlx5e_channel *c = sq->channel;
|
||||
struct mlx5e_priv *priv = c->priv;
|
||||
|
@ -722,6 +733,10 @@ static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state)
|
|||
|
||||
MLX5_SET(modify_sq_in, in, sq_state, curr_state);
|
||||
MLX5_SET(sqc, sqc, state, next_state);
|
||||
if (update_rl && next_state == MLX5_SQC_STATE_RDY) {
|
||||
MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
|
||||
MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index);
|
||||
}
|
||||
|
||||
err = mlx5_core_modify_sq(mdev, sq->sqn, in, inlen);
|
||||
|
||||
|
@ -737,6 +752,8 @@ static void mlx5e_disable_sq(struct mlx5e_sq *sq)
|
|||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
|
||||
mlx5_core_destroy_sq(mdev, sq->sqn);
|
||||
if (sq->rate_limit)
|
||||
mlx5_rl_remove_rate(mdev, sq->rate_limit);
|
||||
}
|
||||
|
||||
static int mlx5e_open_sq(struct mlx5e_channel *c,
|
||||
|
@ -754,7 +771,8 @@ static int mlx5e_open_sq(struct mlx5e_channel *c,
|
|||
if (err)
|
||||
goto err_destroy_sq;
|
||||
|
||||
err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
|
||||
err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
|
||||
false, 0);
|
||||
if (err)
|
||||
goto err_disable_sq;
|
||||
|
||||
|
@ -793,7 +811,8 @@ static void mlx5e_close_sq(struct mlx5e_sq *sq)
|
|||
if (mlx5e_sq_has_room_for(sq, 1))
|
||||
mlx5e_send_nop(sq, true);
|
||||
|
||||
mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR);
|
||||
mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR,
|
||||
false, 0);
|
||||
}
|
||||
|
||||
while (sq->cc != sq->pc) /* wait till sq is empty */
|
||||
|
@ -887,6 +906,7 @@ static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
|
|||
|
||||
mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
|
||||
|
||||
MLX5_SET(cqc, cqc, cq_period_mode, param->cq_period_mode);
|
||||
MLX5_SET(cqc, cqc, c_eqn, eqn);
|
||||
MLX5_SET(cqc, cqc, uar_page, mcq->uar->index);
|
||||
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
|
||||
|
@ -916,8 +936,7 @@ static void mlx5e_disable_cq(struct mlx5e_cq *cq)
|
|||
static int mlx5e_open_cq(struct mlx5e_channel *c,
|
||||
struct mlx5e_cq_param *param,
|
||||
struct mlx5e_cq *cq,
|
||||
u16 moderation_usecs,
|
||||
u16 moderation_frames)
|
||||
struct mlx5e_cq_moder moderation)
|
||||
{
|
||||
int err;
|
||||
struct mlx5e_priv *priv = c->priv;
|
||||
|
@ -933,8 +952,8 @@ static int mlx5e_open_cq(struct mlx5e_channel *c,
|
|||
|
||||
if (MLX5_CAP_GEN(mdev, cq_moderation))
|
||||
mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
|
||||
moderation_usecs,
|
||||
moderation_frames);
|
||||
moderation.usec,
|
||||
moderation.pkts);
|
||||
return 0;
|
||||
|
||||
err_destroy_cq:
|
||||
|
@ -963,8 +982,7 @@ static int mlx5e_open_tx_cqs(struct mlx5e_channel *c,
|
|||
|
||||
for (tc = 0; tc < c->num_tc; tc++) {
|
||||
err = mlx5e_open_cq(c, &cparam->tx_cq, &c->sq[tc].cq,
|
||||
priv->params.tx_cq_moderation_usec,
|
||||
priv->params.tx_cq_moderation_pkts);
|
||||
priv->params.tx_cq_moderation);
|
||||
if (err)
|
||||
goto err_close_tx_cqs;
|
||||
}
|
||||
|
@ -1024,14 +1042,91 @@ static void mlx5e_build_channeltc_to_txq_map(struct mlx5e_priv *priv, int ix)
|
|||
ix + i * priv->params.num_channels;
|
||||
}
|
||||
|
||||
static int mlx5e_set_sq_maxrate(struct net_device *dev,
|
||||
struct mlx5e_sq *sq, u32 rate)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(dev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
u16 rl_index = 0;
|
||||
int err;
|
||||
|
||||
if (rate == sq->rate_limit)
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
|
||||
if (sq->rate_limit)
|
||||
/* remove current rl index to free space to next ones */
|
||||
mlx5_rl_remove_rate(mdev, sq->rate_limit);
|
||||
|
||||
sq->rate_limit = 0;
|
||||
|
||||
if (rate) {
|
||||
err = mlx5_rl_add_rate(mdev, rate, &rl_index);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed configuring rate %u: %d\n",
|
||||
rate, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY,
|
||||
MLX5_SQC_STATE_RDY, true, rl_index);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed configuring rate %u: %d\n",
|
||||
rate, err);
|
||||
/* remove the rate from the table */
|
||||
if (rate)
|
||||
mlx5_rl_remove_rate(mdev, rate);
|
||||
return err;
|
||||
}
|
||||
|
||||
sq->rate_limit = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(dev);
|
||||
struct mlx5_core_dev *mdev = priv->mdev;
|
||||
struct mlx5e_sq *sq = priv->txq_to_sq_map[index];
|
||||
int err = 0;
|
||||
|
||||
if (!mlx5_rl_is_supported(mdev)) {
|
||||
netdev_err(dev, "Rate limiting is not supported on this device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* rate is given in Mb/sec, HW config is in Kb/sec */
|
||||
rate = rate << 10;
|
||||
|
||||
/* Check whether rate in valid range, 0 is always valid */
|
||||
if (rate && !mlx5_rl_is_in_range(mdev, rate)) {
|
||||
netdev_err(dev, "TX rate %u, is not in range\n", rate);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->state_lock);
|
||||
if (test_bit(MLX5E_STATE_OPENED, &priv->state))
|
||||
err = mlx5e_set_sq_maxrate(dev, sq, rate);
|
||||
if (!err)
|
||||
priv->tx_rates[index] = rate;
|
||||
mutex_unlock(&priv->state_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
||||
struct mlx5e_channel_param *cparam,
|
||||
struct mlx5e_channel **cp)
|
||||
{
|
||||
struct mlx5e_cq_moder icosq_cq_moder = {0, 0};
|
||||
struct net_device *netdev = priv->netdev;
|
||||
struct mlx5e_cq_moder rx_cq_profile;
|
||||
int cpu = mlx5e_get_cpu(priv, ix);
|
||||
struct mlx5e_channel *c;
|
||||
struct mlx5e_sq *sq;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
|
||||
if (!c)
|
||||
|
@ -1045,11 +1140,16 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
|||
c->mkey_be = cpu_to_be32(priv->mkey.key);
|
||||
c->num_tc = priv->params.num_tc;
|
||||
|
||||
if (priv->params.rx_am_enabled)
|
||||
rx_cq_profile = mlx5e_am_get_def_profile(priv->params.rx_cq_period_mode);
|
||||
else
|
||||
rx_cq_profile = priv->params.rx_cq_moderation;
|
||||
|
||||
mlx5e_build_channeltc_to_txq_map(priv, ix);
|
||||
|
||||
netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
|
||||
|
||||
err = mlx5e_open_cq(c, &cparam->icosq_cq, &c->icosq.cq, 0, 0);
|
||||
err = mlx5e_open_cq(c, &cparam->icosq_cq, &c->icosq.cq, icosq_cq_moder);
|
||||
if (err)
|
||||
goto err_napi_del;
|
||||
|
||||
|
@ -1058,8 +1158,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
|||
goto err_close_icosq_cq;
|
||||
|
||||
err = mlx5e_open_cq(c, &cparam->rx_cq, &c->rq.cq,
|
||||
priv->params.rx_cq_moderation_usec,
|
||||
priv->params.rx_cq_moderation_pkts);
|
||||
rx_cq_profile);
|
||||
if (err)
|
||||
goto err_close_tx_cqs;
|
||||
|
||||
|
@ -1073,6 +1172,16 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
|||
if (err)
|
||||
goto err_close_icosq;
|
||||
|
||||
for (i = 0; i < priv->params.num_tc; i++) {
|
||||
u32 txq_ix = priv->channeltc_to_txq_map[ix][i];
|
||||
|
||||
if (priv->tx_rates[txq_ix]) {
|
||||
sq = priv->txq_to_sq_map[txq_ix];
|
||||
mlx5e_set_sq_maxrate(priv->netdev, sq,
|
||||
priv->tx_rates[txq_ix]);
|
||||
}
|
||||
}
|
||||
|
||||
err = mlx5e_open_rq(c, &cparam->rq, &c->rq);
|
||||
if (err)
|
||||
goto err_close_sqs;
|
||||
|
@ -1149,6 +1258,8 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
|
|||
|
||||
param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev);
|
||||
param->wq.linear = 1;
|
||||
|
||||
param->am_enabled = priv->params.rx_am_enabled;
|
||||
}
|
||||
|
||||
static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param)
|
||||
|
@ -1214,6 +1325,8 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
|
|||
}
|
||||
|
||||
mlx5e_build_common_cq_param(priv, param);
|
||||
|
||||
param->cq_period_mode = priv->params.rx_cq_period_mode;
|
||||
}
|
||||
|
||||
static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
|
||||
|
@ -1224,6 +1337,8 @@ static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
|
|||
MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_sq_size);
|
||||
|
||||
mlx5e_build_common_cq_param(priv, param);
|
||||
|
||||
param->cq_period_mode = MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
|
||||
}
|
||||
|
||||
static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
|
||||
|
@ -1235,6 +1350,8 @@ static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
|
|||
MLX5_SET(cqc, cqc, log_cq_size, log_wq_size);
|
||||
|
||||
mlx5e_build_common_cq_param(priv, param);
|
||||
|
||||
param->cq_period_mode = MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
|
||||
}
|
||||
|
||||
static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
|
||||
|
@ -2611,6 +2728,7 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = {
|
|||
.ndo_set_features = mlx5e_set_features,
|
||||
.ndo_change_mtu = mlx5e_change_mtu,
|
||||
.ndo_do_ioctl = mlx5e_ioctl,
|
||||
.ndo_set_tx_maxrate = mlx5e_set_tx_maxrate,
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
.ndo_rx_flow_steer = mlx5e_rx_flow_steer,
|
||||
#endif
|
||||
|
@ -2632,6 +2750,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
|
|||
.ndo_do_ioctl = mlx5e_ioctl,
|
||||
.ndo_udp_tunnel_add = mlx5e_add_vxlan_port,
|
||||
.ndo_udp_tunnel_del = mlx5e_del_vxlan_port,
|
||||
.ndo_set_tx_maxrate = mlx5e_set_tx_maxrate,
|
||||
.ndo_features_check = mlx5e_features_check,
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
.ndo_rx_flow_steer = mlx5e_rx_flow_steer,
|
||||
|
@ -2760,6 +2879,20 @@ static bool cqe_compress_heuristic(u32 link_speed, u32 pci_bw)
|
|||
(pci_bw < 40000) && (pci_bw < link_speed));
|
||||
}
|
||||
|
||||
void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
|
||||
{
|
||||
params->rx_cq_period_mode = cq_period_mode;
|
||||
|
||||
params->rx_cq_moderation.pkts =
|
||||
MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
|
||||
params->rx_cq_moderation.usec =
|
||||
MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
|
||||
|
||||
if (cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE)
|
||||
params->rx_cq_moderation.usec =
|
||||
MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE;
|
||||
}
|
||||
|
||||
static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
|
||||
struct net_device *netdev,
|
||||
int num_channels)
|
||||
|
@ -2767,6 +2900,9 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
|
|||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
u32 link_speed = 0;
|
||||
u32 pci_bw = 0;
|
||||
u8 cq_period_mode = MLX5_CAP_GEN(mdev, cq_period_start_from_cqe) ?
|
||||
MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
|
||||
MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
|
||||
|
||||
priv->params.log_sq_size =
|
||||
MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
|
||||
|
@ -2812,13 +2948,13 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
|
|||
|
||||
priv->params.min_rx_wqes = mlx5_min_rx_wqes(priv->params.rq_wq_type,
|
||||
BIT(priv->params.log_rq_size));
|
||||
priv->params.rx_cq_moderation_usec =
|
||||
MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
|
||||
priv->params.rx_cq_moderation_pkts =
|
||||
MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
|
||||
priv->params.tx_cq_moderation_usec =
|
||||
|
||||
priv->params.rx_am_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
|
||||
mlx5e_set_rx_cq_mode_params(&priv->params, cq_period_mode);
|
||||
|
||||
priv->params.tx_cq_moderation.usec =
|
||||
MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC;
|
||||
priv->params.tx_cq_moderation_pkts =
|
||||
priv->params.tx_cq_moderation.pkts =
|
||||
MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
|
||||
priv->params.tx_max_inline = mlx5e_get_max_inline_cap(mdev);
|
||||
priv->params.num_tc = 1;
|
||||
|
@ -2833,6 +2969,10 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
|
|||
priv->params.lro_wqe_sz =
|
||||
MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
|
||||
|
||||
/* 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);
|
||||
|
||||
priv->mdev = mdev;
|
||||
priv->netdev = netdev;
|
||||
priv->params.num_channels = num_channels;
|
||||
|
@ -3240,6 +3380,7 @@ static struct mlx5_interface mlx5e_interface = {
|
|||
|
||||
void mlx5e_init(void)
|
||||
{
|
||||
mlx5e_build_ptys2ethtool_map();
|
||||
mlx5_register_interface(&mlx5e_interface);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Mellanox Technologies. 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 "en.h"
|
||||
|
||||
/* Adaptive moderation profiles */
|
||||
#define MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
|
||||
#define MLX5E_RX_AM_DEF_PROFILE_CQE 1
|
||||
#define MLX5E_RX_AM_DEF_PROFILE_EQE 1
|
||||
#define MLX5E_PARAMS_AM_NUM_PROFILES 5
|
||||
|
||||
/* All profiles sizes must be MLX5E_PARAMS_AM_NUM_PROFILES */
|
||||
#define MLX5_AM_EQE_PROFILES { \
|
||||
{1, MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
|
||||
{8, MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
|
||||
{64, MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
|
||||
{128, MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
|
||||
{256, MLX5E_AM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
|
||||
}
|
||||
|
||||
#define MLX5_AM_CQE_PROFILES { \
|
||||
{2, 256}, \
|
||||
{8, 128}, \
|
||||
{16, 64}, \
|
||||
{32, 64}, \
|
||||
{64, 64} \
|
||||
}
|
||||
|
||||
static const struct mlx5e_cq_moder
|
||||
profile[MLX5_CQ_PERIOD_NUM_MODES][MLX5E_PARAMS_AM_NUM_PROFILES] = {
|
||||
MLX5_AM_EQE_PROFILES,
|
||||
MLX5_AM_CQE_PROFILES,
|
||||
};
|
||||
|
||||
static inline struct mlx5e_cq_moder mlx5e_am_get_profile(u8 cq_period_mode, int ix)
|
||||
{
|
||||
return profile[cq_period_mode][ix];
|
||||
}
|
||||
|
||||
struct mlx5e_cq_moder mlx5e_am_get_def_profile(u8 rx_cq_period_mode)
|
||||
{
|
||||
int default_profile_ix;
|
||||
|
||||
if (rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE)
|
||||
default_profile_ix = MLX5E_RX_AM_DEF_PROFILE_CQE;
|
||||
else /* MLX5_CQ_PERIOD_MODE_START_FROM_EQE */
|
||||
default_profile_ix = MLX5E_RX_AM_DEF_PROFILE_EQE;
|
||||
|
||||
return profile[rx_cq_period_mode][default_profile_ix];
|
||||
}
|
||||
|
||||
/* Adaptive moderation logic */
|
||||
enum {
|
||||
MLX5E_AM_START_MEASURE,
|
||||
MLX5E_AM_MEASURE_IN_PROGRESS,
|
||||
MLX5E_AM_APPLY_NEW_PROFILE,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5E_AM_PARKING_ON_TOP,
|
||||
MLX5E_AM_PARKING_TIRED,
|
||||
MLX5E_AM_GOING_RIGHT,
|
||||
MLX5E_AM_GOING_LEFT,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5E_AM_STATS_WORSE,
|
||||
MLX5E_AM_STATS_SAME,
|
||||
MLX5E_AM_STATS_BETTER,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5E_AM_STEPPED,
|
||||
MLX5E_AM_TOO_TIRED,
|
||||
MLX5E_AM_ON_EDGE,
|
||||
};
|
||||
|
||||
static bool mlx5e_am_on_top(struct mlx5e_rx_am *am)
|
||||
{
|
||||
switch (am->tune_state) {
|
||||
case MLX5E_AM_PARKING_ON_TOP:
|
||||
case MLX5E_AM_PARKING_TIRED:
|
||||
WARN_ONCE(true, "mlx5e_am_on_top: PARKING\n");
|
||||
return true;
|
||||
case MLX5E_AM_GOING_RIGHT:
|
||||
return (am->steps_left > 1) && (am->steps_right == 1);
|
||||
default: /* MLX5E_AM_GOING_LEFT */
|
||||
return (am->steps_right > 1) && (am->steps_left == 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void mlx5e_am_turn(struct mlx5e_rx_am *am)
|
||||
{
|
||||
switch (am->tune_state) {
|
||||
case MLX5E_AM_PARKING_ON_TOP:
|
||||
case MLX5E_AM_PARKING_TIRED:
|
||||
WARN_ONCE(true, "mlx5e_am_turn: PARKING\n");
|
||||
break;
|
||||
case MLX5E_AM_GOING_RIGHT:
|
||||
am->tune_state = MLX5E_AM_GOING_LEFT;
|
||||
am->steps_left = 0;
|
||||
break;
|
||||
case MLX5E_AM_GOING_LEFT:
|
||||
am->tune_state = MLX5E_AM_GOING_RIGHT;
|
||||
am->steps_right = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mlx5e_am_step(struct mlx5e_rx_am *am)
|
||||
{
|
||||
if (am->tired == (MLX5E_PARAMS_AM_NUM_PROFILES * 2))
|
||||
return MLX5E_AM_TOO_TIRED;
|
||||
|
||||
switch (am->tune_state) {
|
||||
case MLX5E_AM_PARKING_ON_TOP:
|
||||
case MLX5E_AM_PARKING_TIRED:
|
||||
WARN_ONCE(true, "mlx5e_am_step: PARKING\n");
|
||||
break;
|
||||
case MLX5E_AM_GOING_RIGHT:
|
||||
if (am->profile_ix == (MLX5E_PARAMS_AM_NUM_PROFILES - 1))
|
||||
return MLX5E_AM_ON_EDGE;
|
||||
am->profile_ix++;
|
||||
am->steps_right++;
|
||||
break;
|
||||
case MLX5E_AM_GOING_LEFT:
|
||||
if (am->profile_ix == 0)
|
||||
return MLX5E_AM_ON_EDGE;
|
||||
am->profile_ix--;
|
||||
am->steps_left++;
|
||||
break;
|
||||
}
|
||||
|
||||
am->tired++;
|
||||
return MLX5E_AM_STEPPED;
|
||||
}
|
||||
|
||||
static void mlx5e_am_park_on_top(struct mlx5e_rx_am *am)
|
||||
{
|
||||
am->steps_right = 0;
|
||||
am->steps_left = 0;
|
||||
am->tired = 0;
|
||||
am->tune_state = MLX5E_AM_PARKING_ON_TOP;
|
||||
}
|
||||
|
||||
static void mlx5e_am_park_tired(struct mlx5e_rx_am *am)
|
||||
{
|
||||
am->steps_right = 0;
|
||||
am->steps_left = 0;
|
||||
am->tune_state = MLX5E_AM_PARKING_TIRED;
|
||||
}
|
||||
|
||||
static void mlx5e_am_exit_parking(struct mlx5e_rx_am *am)
|
||||
{
|
||||
am->tune_state = am->profile_ix ? MLX5E_AM_GOING_LEFT :
|
||||
MLX5E_AM_GOING_RIGHT;
|
||||
mlx5e_am_step(am);
|
||||
}
|
||||
|
||||
static int mlx5e_am_stats_compare(struct mlx5e_rx_am_stats *curr,
|
||||
struct mlx5e_rx_am_stats *prev)
|
||||
{
|
||||
int diff;
|
||||
|
||||
if (!prev->ppms)
|
||||
return curr->ppms ? MLX5E_AM_STATS_BETTER :
|
||||
MLX5E_AM_STATS_SAME;
|
||||
|
||||
diff = curr->ppms - prev->ppms;
|
||||
if (((100 * abs(diff)) / prev->ppms) > 10) /* more than 10% diff */
|
||||
return (diff > 0) ? MLX5E_AM_STATS_BETTER :
|
||||
MLX5E_AM_STATS_WORSE;
|
||||
|
||||
if (!prev->epms)
|
||||
return curr->epms ? MLX5E_AM_STATS_WORSE :
|
||||
MLX5E_AM_STATS_SAME;
|
||||
|
||||
diff = curr->epms - prev->epms;
|
||||
if (((100 * abs(diff)) / prev->epms) > 10) /* more than 10% diff */
|
||||
return (diff < 0) ? MLX5E_AM_STATS_BETTER :
|
||||
MLX5E_AM_STATS_WORSE;
|
||||
|
||||
return MLX5E_AM_STATS_SAME;
|
||||
}
|
||||
|
||||
static bool mlx5e_am_decision(struct mlx5e_rx_am_stats *curr_stats,
|
||||
struct mlx5e_rx_am *am)
|
||||
{
|
||||
int prev_state = am->tune_state;
|
||||
int prev_ix = am->profile_ix;
|
||||
int stats_res;
|
||||
int step_res;
|
||||
|
||||
switch (am->tune_state) {
|
||||
case MLX5E_AM_PARKING_ON_TOP:
|
||||
stats_res = mlx5e_am_stats_compare(curr_stats, &am->prev_stats);
|
||||
if (stats_res != MLX5E_AM_STATS_SAME)
|
||||
mlx5e_am_exit_parking(am);
|
||||
break;
|
||||
|
||||
case MLX5E_AM_PARKING_TIRED:
|
||||
am->tired--;
|
||||
if (!am->tired)
|
||||
mlx5e_am_exit_parking(am);
|
||||
break;
|
||||
|
||||
case MLX5E_AM_GOING_RIGHT:
|
||||
case MLX5E_AM_GOING_LEFT:
|
||||
stats_res = mlx5e_am_stats_compare(curr_stats, &am->prev_stats);
|
||||
if (stats_res != MLX5E_AM_STATS_BETTER)
|
||||
mlx5e_am_turn(am);
|
||||
|
||||
if (mlx5e_am_on_top(am)) {
|
||||
mlx5e_am_park_on_top(am);
|
||||
break;
|
||||
}
|
||||
|
||||
step_res = mlx5e_am_step(am);
|
||||
switch (step_res) {
|
||||
case MLX5E_AM_ON_EDGE:
|
||||
mlx5e_am_park_on_top(am);
|
||||
break;
|
||||
case MLX5E_AM_TOO_TIRED:
|
||||
mlx5e_am_park_tired(am);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((prev_state != MLX5E_AM_PARKING_ON_TOP) ||
|
||||
(am->tune_state != MLX5E_AM_PARKING_ON_TOP))
|
||||
am->prev_stats = *curr_stats;
|
||||
|
||||
return am->profile_ix != prev_ix;
|
||||
}
|
||||
|
||||
static void mlx5e_am_sample(struct mlx5e_rq *rq,
|
||||
struct mlx5e_rx_am_sample *s)
|
||||
{
|
||||
s->time = ktime_get();
|
||||
s->pkt_ctr = rq->stats.packets;
|
||||
s->event_ctr = rq->cq.event_ctr;
|
||||
}
|
||||
|
||||
#define MLX5E_AM_NEVENTS 64
|
||||
|
||||
static void mlx5e_am_calc_stats(struct mlx5e_rx_am_sample *start,
|
||||
struct mlx5e_rx_am_sample *end,
|
||||
struct mlx5e_rx_am_stats *curr_stats)
|
||||
{
|
||||
/* u32 holds up to 71 minutes, should be enough */
|
||||
u32 delta_us = ktime_us_delta(end->time, start->time);
|
||||
unsigned int npkts = end->pkt_ctr - start->pkt_ctr;
|
||||
|
||||
if (!delta_us) {
|
||||
WARN_ONCE(true, "mlx5e_am_calc_stats: delta_us=0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
curr_stats->ppms = (npkts * USEC_PER_MSEC) / delta_us;
|
||||
curr_stats->epms = (MLX5E_AM_NEVENTS * USEC_PER_MSEC) / delta_us;
|
||||
}
|
||||
|
||||
void mlx5e_rx_am_work(struct work_struct *work)
|
||||
{
|
||||
struct mlx5e_rx_am *am = container_of(work, struct mlx5e_rx_am,
|
||||
work);
|
||||
struct mlx5e_rq *rq = container_of(am, struct mlx5e_rq, am);
|
||||
struct mlx5e_cq_moder cur_profile = profile[am->mode][am->profile_ix];
|
||||
|
||||
mlx5_core_modify_cq_moderation(rq->priv->mdev, &rq->cq.mcq,
|
||||
cur_profile.usec, cur_profile.pkts);
|
||||
|
||||
am->state = MLX5E_AM_START_MEASURE;
|
||||
}
|
||||
|
||||
void mlx5e_rx_am(struct mlx5e_rq *rq)
|
||||
{
|
||||
struct mlx5e_rx_am *am = &rq->am;
|
||||
struct mlx5e_rx_am_sample end_sample;
|
||||
struct mlx5e_rx_am_stats curr_stats;
|
||||
u16 nevents;
|
||||
|
||||
switch (am->state) {
|
||||
case MLX5E_AM_MEASURE_IN_PROGRESS:
|
||||
nevents = rq->cq.event_ctr - am->start_sample.event_ctr;
|
||||
if (nevents < MLX5E_AM_NEVENTS)
|
||||
break;
|
||||
mlx5e_am_sample(rq, &end_sample);
|
||||
mlx5e_am_calc_stats(&am->start_sample, &end_sample,
|
||||
&curr_stats);
|
||||
if (mlx5e_am_decision(&curr_stats, am)) {
|
||||
am->state = MLX5E_AM_APPLY_NEW_PROFILE;
|
||||
schedule_work(&am->work);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case MLX5E_AM_START_MEASURE:
|
||||
mlx5e_am_sample(rq, &am->start_sample);
|
||||
am->state = MLX5E_AM_MEASURE_IN_PROGRESS;
|
||||
break;
|
||||
case MLX5E_AM_APPLY_NEW_PROFILE:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -136,6 +136,10 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
|
|||
|
||||
for (i = 0; i < c->num_tc; i++)
|
||||
mlx5e_cq_arm(&c->sq[i].cq);
|
||||
|
||||
if (test_bit(MLX5E_RQ_STATE_AM, &c->rq.state))
|
||||
mlx5e_rx_am(&c->rq);
|
||||
|
||||
mlx5e_cq_arm(&c->rq.cq);
|
||||
mlx5e_cq_arm(&c->icosq.cq);
|
||||
|
||||
|
@ -146,6 +150,7 @@ void mlx5e_completion_event(struct mlx5_core_cq *mcq)
|
|||
{
|
||||
struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
|
||||
|
||||
cq->event_ctr++;
|
||||
set_bit(MLX5E_CHANNEL_NAPI_SCHED, &cq->channel->flags);
|
||||
napi_schedule(cq->napi);
|
||||
}
|
||||
|
|
|
@ -151,6 +151,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (MLX5_CAP_GEN(dev, qos)) {
|
||||
err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1144,6 +1144,13 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
|
|||
dev_err(&pdev->dev, "Failed to init flow steering\n");
|
||||
goto err_fs;
|
||||
}
|
||||
|
||||
err = mlx5_init_rl_table(dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to init rate limiting\n");
|
||||
goto err_rl;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
err = mlx5_eswitch_init(dev);
|
||||
if (err) {
|
||||
|
@ -1183,6 +1190,8 @@ err_sriov:
|
|||
mlx5_eswitch_cleanup(dev->priv.eswitch);
|
||||
#endif
|
||||
err_reg_dev:
|
||||
mlx5_cleanup_rl_table(dev);
|
||||
err_rl:
|
||||
mlx5_cleanup_fs(dev);
|
||||
err_fs:
|
||||
mlx5_cleanup_mkey_table(dev);
|
||||
|
@ -1253,6 +1262,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
|
|||
mlx5_eswitch_cleanup(dev->priv.eswitch);
|
||||
#endif
|
||||
|
||||
mlx5_cleanup_rl_table(dev);
|
||||
mlx5_cleanup_fs(dev);
|
||||
mlx5_cleanup_mkey_table(dev);
|
||||
mlx5_cleanup_srq_table(dev);
|
||||
|
|
|
@ -202,15 +202,24 @@ int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper);
|
||||
|
||||
int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
|
||||
int proto_mask)
|
||||
int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
|
||||
u32 proto_admin, int proto_mask)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(ptys_reg)];
|
||||
u32 out[MLX5_ST_SZ_DW(ptys_reg)];
|
||||
u32 in[MLX5_ST_SZ_DW(ptys_reg)];
|
||||
u8 an_disable_admin;
|
||||
u8 an_disable_cap;
|
||||
u8 an_status;
|
||||
|
||||
mlx5_query_port_autoneg(dev, proto_mask, &an_status,
|
||||
&an_disable_cap, &an_disable_admin);
|
||||
if (!an_disable_cap && an_disable)
|
||||
return -EPERM;
|
||||
|
||||
memset(in, 0, sizeof(in));
|
||||
|
||||
MLX5_SET(ptys_reg, in, local_port, 1);
|
||||
MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
|
||||
MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
|
||||
if (proto_mask == MLX5_PTYS_EN)
|
||||
MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
|
||||
|
@ -220,7 +229,19 @@ int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
|
|||
return mlx5_core_access_reg(dev, in, sizeof(in), out,
|
||||
sizeof(out), MLX5_REG_PTYS, 0, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
|
||||
EXPORT_SYMBOL_GPL(mlx5_set_port_ptys);
|
||||
|
||||
/* This function should be used after setting a port register only */
|
||||
void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
|
||||
{
|
||||
enum mlx5_port_status ps;
|
||||
|
||||
mlx5_query_port_admin_status(dev, &ps);
|
||||
mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
|
||||
if (ps == MLX5_PORT_UP)
|
||||
mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
|
||||
|
||||
int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
|
||||
enum mlx5_port_status status)
|
||||
|
@ -518,6 +539,25 @@ int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
|
||||
|
||||
void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
|
||||
u8 *an_status,
|
||||
u8 *an_disable_cap, u8 *an_disable_admin)
|
||||
{
|
||||
u32 out[MLX5_ST_SZ_DW(ptys_reg)];
|
||||
|
||||
*an_status = 0;
|
||||
*an_disable_cap = 0;
|
||||
*an_disable_admin = 0;
|
||||
|
||||
if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1))
|
||||
return;
|
||||
|
||||
*an_status = MLX5_GET(ptys_reg, out, an_status);
|
||||
*an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
|
||||
*an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
|
||||
|
||||
int mlx5_max_tc(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, Mellanox Technologies. 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include <linux/mlx5/cmd.h>
|
||||
#include "mlx5_core.h"
|
||||
|
||||
/* Finds an entry where we can register the given rate
|
||||
* If the rate already exists, return the entry where it is registered,
|
||||
* otherwise return the first available entry.
|
||||
* If the table is full, return NULL
|
||||
*/
|
||||
static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table,
|
||||
u32 rate)
|
||||
{
|
||||
struct mlx5_rl_entry *ret_entry = NULL;
|
||||
bool empty_found = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < table->max_size; i++) {
|
||||
if (table->rl_entry[i].rate == rate)
|
||||
return &table->rl_entry[i];
|
||||
if (!empty_found && !table->rl_entry[i].rate) {
|
||||
empty_found = true;
|
||||
ret_entry = &table->rl_entry[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ret_entry;
|
||||
}
|
||||
|
||||
static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev,
|
||||
u32 rate, u16 index)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)];
|
||||
u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)];
|
||||
|
||||
memset(in, 0, sizeof(in));
|
||||
memset(out, 0, sizeof(out));
|
||||
|
||||
MLX5_SET(set_rate_limit_in, in, opcode,
|
||||
MLX5_CMD_OP_SET_RATE_LIMIT);
|
||||
MLX5_SET(set_rate_limit_in, in, rate_limit_index, index);
|
||||
MLX5_SET(set_rate_limit_in, in, rate_limit, rate);
|
||||
|
||||
return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
|
||||
out, sizeof(out));
|
||||
}
|
||||
|
||||
bool mlx5_rl_is_in_range(struct mlx5_core_dev *dev, u32 rate)
|
||||
{
|
||||
struct mlx5_rl_table *table = &dev->priv.rl_table;
|
||||
|
||||
return (rate <= table->max_rate && rate >= table->min_rate);
|
||||
}
|
||||
EXPORT_SYMBOL(mlx5_rl_is_in_range);
|
||||
|
||||
int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u16 *index)
|
||||
{
|
||||
struct mlx5_rl_table *table = &dev->priv.rl_table;
|
||||
struct mlx5_rl_entry *entry;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&table->rl_lock);
|
||||
|
||||
if (!rate || !mlx5_rl_is_in_range(dev, rate)) {
|
||||
mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n",
|
||||
rate, table->min_rate, table->max_rate);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry = find_rl_entry(table, rate);
|
||||
if (!entry) {
|
||||
mlx5_core_err(dev, "Max number of %u rates reached\n",
|
||||
table->max_size);
|
||||
err = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
if (entry->refcount) {
|
||||
/* rate already configured */
|
||||
entry->refcount++;
|
||||
} else {
|
||||
/* new rate limit */
|
||||
err = mlx5_set_rate_limit_cmd(dev, rate, entry->index);
|
||||
if (err) {
|
||||
mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n",
|
||||
rate, err);
|
||||
goto out;
|
||||
}
|
||||
entry->rate = rate;
|
||||
entry->refcount = 1;
|
||||
}
|
||||
*index = entry->index;
|
||||
|
||||
out:
|
||||
mutex_unlock(&table->rl_lock);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mlx5_rl_add_rate);
|
||||
|
||||
void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate)
|
||||
{
|
||||
struct mlx5_rl_table *table = &dev->priv.rl_table;
|
||||
struct mlx5_rl_entry *entry = NULL;
|
||||
|
||||
/* 0 is a reserved value for unlimited rate */
|
||||
if (rate == 0)
|
||||
return;
|
||||
|
||||
mutex_lock(&table->rl_lock);
|
||||
entry = find_rl_entry(table, rate);
|
||||
if (!entry || !entry->refcount) {
|
||||
mlx5_core_warn(dev, "Rate %u is not configured\n", rate);
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry->refcount--;
|
||||
if (!entry->refcount) {
|
||||
/* need to remove rate */
|
||||
mlx5_set_rate_limit_cmd(dev, 0, entry->index);
|
||||
entry->rate = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&table->rl_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mlx5_rl_remove_rate);
|
||||
|
||||
int mlx5_init_rl_table(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_rl_table *table = &dev->priv.rl_table;
|
||||
int i;
|
||||
|
||||
mutex_init(&table->rl_lock);
|
||||
if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) {
|
||||
table->max_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First entry is reserved for unlimited rate */
|
||||
table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1;
|
||||
table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate);
|
||||
table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate);
|
||||
|
||||
table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry),
|
||||
GFP_KERNEL);
|
||||
if (!table->rl_entry)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The index represents the index in HW rate limit table
|
||||
* Index 0 is reserved for unlimited rate
|
||||
*/
|
||||
for (i = 0; i < table->max_size; i++)
|
||||
table->rl_entry[i].index = i + 1;
|
||||
|
||||
/* Index 0 is reserved */
|
||||
mlx5_core_info(dev, "Rate limit: %u rates are supported, range: %uMbps to %uMbps\n",
|
||||
table->max_size,
|
||||
table->min_rate >> 10,
|
||||
table->max_rate >> 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_rl_table *table = &dev->priv.rl_table;
|
||||
int i;
|
||||
|
||||
/* Clear all configured rates */
|
||||
for (i = 0; i < table->max_size; i++)
|
||||
if (table->rl_entry[i].rate)
|
||||
mlx5_set_rate_limit_cmd(dev, 0,
|
||||
table->rl_entry[i].index);
|
||||
|
||||
kfree(dev->priv.rl_table.rl_entry);
|
||||
}
|
|
@ -1330,6 +1330,7 @@ enum mlx5_cap_type {
|
|||
MLX5_CAP_ESWITCH,
|
||||
MLX5_CAP_RESERVED,
|
||||
MLX5_CAP_VECTOR_CALC,
|
||||
MLX5_CAP_QOS,
|
||||
/* NUM OF CAP Types */
|
||||
MLX5_CAP_NUM
|
||||
};
|
||||
|
@ -1414,6 +1415,9 @@ enum mlx5_cap_type {
|
|||
MLX5_GET(vector_calc_cap, \
|
||||
mdev->hca_caps_cur[MLX5_CAP_VECTOR_CALC], cap)
|
||||
|
||||
#define MLX5_CAP_QOS(mdev, cap)\
|
||||
MLX5_GET(qos_cap, mdev->hca_caps_cur[MLX5_CAP_QOS], cap)
|
||||
|
||||
enum {
|
||||
MLX5_CMD_STAT_OK = 0x0,
|
||||
MLX5_CMD_STAT_INT_ERR = 0x1,
|
||||
|
|
|
@ -481,6 +481,21 @@ struct mlx5_fc_stats {
|
|||
|
||||
struct mlx5_eswitch;
|
||||
|
||||
struct mlx5_rl_entry {
|
||||
u32 rate;
|
||||
u16 index;
|
||||
u16 refcount;
|
||||
};
|
||||
|
||||
struct mlx5_rl_table {
|
||||
/* protect rate limit table */
|
||||
struct mutex rl_lock;
|
||||
u16 max_size;
|
||||
u32 max_rate;
|
||||
u32 min_rate;
|
||||
struct mlx5_rl_entry *rl_entry;
|
||||
};
|
||||
|
||||
struct mlx5_priv {
|
||||
char name[MLX5_MAX_NAME_LEN];
|
||||
struct mlx5_eq_table eq_table;
|
||||
|
@ -544,6 +559,7 @@ struct mlx5_priv {
|
|||
struct mlx5_flow_root_namespace *esw_ingress_root_ns;
|
||||
|
||||
struct mlx5_fc_stats fc_stats;
|
||||
struct mlx5_rl_table rl_table;
|
||||
};
|
||||
|
||||
enum mlx5_device_state {
|
||||
|
@ -861,6 +877,12 @@ int mlx5_query_odp_caps(struct mlx5_core_dev *dev,
|
|||
int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
|
||||
u8 port_num, void *out, size_t sz);
|
||||
|
||||
int mlx5_init_rl_table(struct mlx5_core_dev *dev);
|
||||
void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev);
|
||||
int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u16 *index);
|
||||
void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate);
|
||||
bool mlx5_rl_is_in_range(struct mlx5_core_dev *dev, u32 rate);
|
||||
|
||||
static inline int fw_initializing(struct mlx5_core_dev *dev)
|
||||
{
|
||||
return ioread32be(&dev->iseg->initializing) >> 31;
|
||||
|
@ -938,6 +960,11 @@ static inline int mlx5_get_gid_table_len(u16 param)
|
|||
return 8 * (1 << param);
|
||||
}
|
||||
|
||||
static inline bool mlx5_rl_is_supported(struct mlx5_core_dev *dev)
|
||||
{
|
||||
return !!(dev->priv.rl_table.max_size);
|
||||
}
|
||||
|
||||
enum {
|
||||
MLX5_TRIGGERED_CMD_COMP = (u64)1 << 32,
|
||||
};
|
||||
|
|
|
@ -47,6 +47,14 @@ enum mlx5_module_id {
|
|||
MLX5_MODULE_ID_QSFP28 = 0x11,
|
||||
};
|
||||
|
||||
enum mlx5_an_status {
|
||||
MLX5_AN_UNAVAILABLE = 0,
|
||||
MLX5_AN_COMPLETE = 1,
|
||||
MLX5_AN_FAILED = 2,
|
||||
MLX5_AN_LINK_UP = 3,
|
||||
MLX5_AN_LINK_DOWN = 4,
|
||||
};
|
||||
|
||||
#define MLX5_EEPROM_MAX_BYTES 32
|
||||
#define MLX5_EEPROM_IDENTIFIER_BYTE_MASK 0x000000ff
|
||||
#define MLX5_I2C_ADDR_LOW 0x50
|
||||
|
@ -65,13 +73,17 @@ int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
|
|||
int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
|
||||
u8 *proto_oper, int proto_mask,
|
||||
u8 local_port);
|
||||
int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
|
||||
int proto_mask);
|
||||
int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
|
||||
u32 proto_admin, int proto_mask);
|
||||
void mlx5_toggle_port_link(struct mlx5_core_dev *dev);
|
||||
int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
|
||||
enum mlx5_port_status status);
|
||||
int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
|
||||
enum mlx5_port_status *status);
|
||||
int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration);
|
||||
void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
|
||||
u8 *an_status,
|
||||
u8 *an_disable_cap, u8 *an_disable_admin);
|
||||
|
||||
int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port);
|
||||
void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, u8 port);
|
||||
|
|
|
@ -1362,6 +1362,7 @@ enum ethtool_link_mode_bit_indices {
|
|||
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT = 37,
|
||||
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT = 38,
|
||||
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39,
|
||||
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT = 40,
|
||||
|
||||
/* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
|
||||
* 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
|
||||
|
@ -1370,7 +1371,7 @@ enum ethtool_link_mode_bit_indices {
|
|||
*/
|
||||
|
||||
__ETHTOOL_LINK_MODE_LAST
|
||||
= ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
|
||||
= ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
|
||||
};
|
||||
|
||||
#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name) \
|
||||
|
|
Loading…
Reference in New Issue