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

Merge tag 'mlx5-updates-2020-01-24' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
This series adds two moderate updates and some misc small patches to
mlx5 driver.

1) From Aya, Add the missing devlink health dump callbacks support for
both rx and tx health reporters.

First patch of the series is extending devlink API to set binary fmsg
data.

All others patches in the series are adding the mlx5 devlink health
callbacks support and the needed FW commands.

2) Also from Aya, Support for FEC modes based on 50G per lane links.
Part of this series, Aya adds one missing link mode define "FEC_LLRS"
to include/uapi/linux/ethtool.h.

3) From Joe, Use proper logging and tracing line terminations

4) From Christophe, Remove a useless 'drain_workqueue()'
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 00796b92 0120936a
......@@ -16,7 +16,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
lib/devcom.o lib/pci_vsc.o lib/dm.o diag/fs_tracepoint.o \
diag/fw_tracer.o diag/crdump.o devlink.o
diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o
#
# Netdev basic
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2019 Mellanox Technologies. */
#include "rsc_dump.h"
#include "lib/mlx5.h"
#define MLX5_SGMT_TYPE(SGMT) MLX5_SGMT_TYPE_##SGMT
#define MLX5_SGMT_STR_ASSING(SGMT)[MLX5_SGMT_TYPE(SGMT)] = #SGMT
static const char *const mlx5_rsc_sgmt_name[] = {
MLX5_SGMT_STR_ASSING(HW_CQPC),
MLX5_SGMT_STR_ASSING(HW_SQPC),
MLX5_SGMT_STR_ASSING(HW_RQPC),
MLX5_SGMT_STR_ASSING(FULL_SRQC),
MLX5_SGMT_STR_ASSING(FULL_CQC),
MLX5_SGMT_STR_ASSING(FULL_EQC),
MLX5_SGMT_STR_ASSING(FULL_QPC),
MLX5_SGMT_STR_ASSING(SND_BUFF),
MLX5_SGMT_STR_ASSING(RCV_BUFF),
MLX5_SGMT_STR_ASSING(SRQ_BUFF),
MLX5_SGMT_STR_ASSING(CQ_BUFF),
MLX5_SGMT_STR_ASSING(EQ_BUFF),
MLX5_SGMT_STR_ASSING(SX_SLICE),
MLX5_SGMT_STR_ASSING(SX_SLICE_ALL),
MLX5_SGMT_STR_ASSING(RDB),
MLX5_SGMT_STR_ASSING(RX_SLICE_ALL),
};
struct mlx5_rsc_dump {
u32 pdn;
struct mlx5_core_mkey mkey;
u16 fw_segment_type[MLX5_SGMT_TYPE_NUM];
};
struct mlx5_rsc_dump_cmd {
u64 mem_size;
u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)];
};
static int mlx5_rsc_dump_sgmt_get_by_name(char *name)
{
int i;
for (i = 0; i < ARRAY_SIZE(mlx5_rsc_sgmt_name); i++)
if (!strcmp(name, mlx5_rsc_sgmt_name[i]))
return i;
return -EINVAL;
}
static void mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump *rsc_dump, struct page *page)
{
void *data = page_address(page);
enum mlx5_sgmt_type sgmt_idx;
int num_of_items;
char *sgmt_name;
void *member;
void *menu;
int i;
menu = MLX5_ADDR_OF(menu_resource_dump_response, data, menu);
num_of_items = MLX5_GET(resource_dump_menu_segment, menu, num_of_records);
for (i = 0; i < num_of_items; i++) {
member = MLX5_ADDR_OF(resource_dump_menu_segment, menu, record[i]);
sgmt_name = MLX5_ADDR_OF(resource_dump_menu_record, member, segment_name);
sgmt_idx = mlx5_rsc_dump_sgmt_get_by_name(sgmt_name);
if (sgmt_idx == -EINVAL)
continue;
rsc_dump->fw_segment_type[sgmt_idx] = MLX5_GET(resource_dump_menu_record,
member, segment_type);
}
}
static int mlx5_rsc_dump_trigger(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
struct page *page)
{
struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
struct device *ddev = &dev->pdev->dev;
u32 out_seq_num;
u32 in_seq_num;
dma_addr_t dma;
int err;
dma = dma_map_page(ddev, page, 0, cmd->mem_size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(ddev, dma)))
return -ENOMEM;
in_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
MLX5_SET(resource_dump, cmd->cmd, mkey, rsc_dump->mkey.key);
MLX5_SET64(resource_dump, cmd->cmd, address, dma);
err = mlx5_core_access_reg(dev, cmd->cmd, sizeof(cmd->cmd), cmd->cmd,
sizeof(cmd->cmd), MLX5_REG_RESOURCE_DUMP, 0, 1);
if (err) {
mlx5_core_err(dev, "Resource dump: Failed to access err %d\n", err);
goto out;
}
out_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
if (out_seq_num && (in_seq_num + 1 != out_seq_num))
err = -EIO;
out:
dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE);
return err;
}
struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev,
struct mlx5_rsc_key *key)
{
struct mlx5_rsc_dump_cmd *cmd;
int sgmt_type;
if (IS_ERR_OR_NULL(dev->rsc_dump))
return ERR_PTR(-EOPNOTSUPP);
sgmt_type = dev->rsc_dump->fw_segment_type[key->rsc];
if (!sgmt_type && key->rsc != MLX5_SGMT_TYPE_MENU)
return ERR_PTR(-EOPNOTSUPP);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
mlx5_core_err(dev, "Resource dump: Failed to allocate command\n");
return ERR_PTR(-ENOMEM);
}
MLX5_SET(resource_dump, cmd->cmd, segment_type, sgmt_type);
MLX5_SET(resource_dump, cmd->cmd, index1, key->index1);
MLX5_SET(resource_dump, cmd->cmd, index2, key->index2);
MLX5_SET(resource_dump, cmd->cmd, num_of_obj1, key->num_of_obj1);
MLX5_SET(resource_dump, cmd->cmd, num_of_obj2, key->num_of_obj2);
MLX5_SET(resource_dump, cmd->cmd, size, key->size);
cmd->mem_size = key->size;
return cmd;
}
void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd)
{
kfree(cmd);
}
int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
struct page *page, int *size)
{
bool more_dump;
int err;
if (IS_ERR_OR_NULL(dev->rsc_dump))
return -EOPNOTSUPP;
err = mlx5_rsc_dump_trigger(dev, cmd, page);
if (err) {
mlx5_core_err(dev, "Resource dump: Failed to trigger dump, %d\n", err);
return err;
}
*size = MLX5_GET(resource_dump, cmd->cmd, size);
more_dump = MLX5_GET(resource_dump, cmd->cmd, more_dump);
return more_dump;
}
#define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff
static int mlx5_rsc_dump_menu(struct mlx5_core_dev *dev)
{
struct mlx5_rsc_dump_cmd *cmd = NULL;
struct mlx5_rsc_key key = {};
struct page *page;
int size;
int err;
page = alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
key.rsc = MLX5_SGMT_TYPE_MENU;
key.size = PAGE_SIZE;
cmd = mlx5_rsc_dump_cmd_create(dev, &key);
if (IS_ERR(cmd)) {
err = PTR_ERR(cmd);
goto free_page;
}
MLX5_SET(resource_dump, cmd->cmd, segment_type, MLX5_RSC_DUMP_MENU_SEGMENT);
do {
err = mlx5_rsc_dump_next(dev, cmd, page, &size);
if (err < 0)
goto destroy_cmd;
mlx5_rsc_dump_read_menu_sgmt(dev->rsc_dump, page);
} while (err > 0);
destroy_cmd:
mlx5_rsc_dump_cmd_destroy(cmd);
free_page:
__free_page(page);
return err;
}
static int mlx5_rsc_dump_create_mkey(struct mlx5_core_dev *mdev, u32 pdn,
struct mlx5_core_mkey *mkey)
{
int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
void *mkc;
u32 *in;
int err;
in = kvzalloc(inlen, GFP_KERNEL);
if (!in)
return -ENOMEM;
mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
MLX5_SET(mkc, mkc, lw, 1);
MLX5_SET(mkc, mkc, lr, 1);
MLX5_SET(mkc, mkc, pd, pdn);
MLX5_SET(mkc, mkc, length64, 1);
MLX5_SET(mkc, mkc, qpn, 0xffffff);
err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
kvfree(in);
return err;
}
struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev)
{
struct mlx5_rsc_dump *rsc_dump;
if (!MLX5_CAP_DEBUG(dev, resource_dump)) {
mlx5_core_dbg(dev, "Resource dump: capability not present\n");
return NULL;
}
rsc_dump = kzalloc(sizeof(*rsc_dump), GFP_KERNEL);
if (!rsc_dump)
return ERR_PTR(-ENOMEM);
return rsc_dump;
}
void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev)
{
if (IS_ERR_OR_NULL(dev->rsc_dump))
return;
kfree(dev->rsc_dump);
}
int mlx5_rsc_dump_init(struct mlx5_core_dev *dev)
{
struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
int err;
if (IS_ERR_OR_NULL(dev->rsc_dump))
return 0;
err = mlx5_core_alloc_pd(dev, &rsc_dump->pdn);
if (err) {
mlx5_core_warn(dev, "Resource dump: Failed to allocate PD %d\n", err);
return err;
}
err = mlx5_rsc_dump_create_mkey(dev, rsc_dump->pdn, &rsc_dump->mkey);
if (err) {
mlx5_core_err(dev, "Resource dump: Failed to create mkey, %d\n", err);
goto free_pd;
}
err = mlx5_rsc_dump_menu(dev);
if (err) {
mlx5_core_err(dev, "Resource dump: Failed to read menu, %d\n", err);
goto destroy_mkey;
}
return err;
destroy_mkey:
mlx5_core_destroy_mkey(dev, &rsc_dump->mkey);
free_pd:
mlx5_core_dealloc_pd(dev, rsc_dump->pdn);
return err;
}
void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev)
{
if (IS_ERR_OR_NULL(dev->rsc_dump))
return;
mlx5_core_destroy_mkey(dev, &dev->rsc_dump->mkey);
mlx5_core_dealloc_pd(dev, dev->rsc_dump->pdn);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 Mellanox Technologies. */
#ifndef __MLX5_RSC_DUMP_H
#define __MLX5_RSC_DUMP__H
#include <linux/mlx5/driver.h>
#include "mlx5_core.h"
enum mlx5_sgmt_type {
MLX5_SGMT_TYPE_HW_CQPC,
MLX5_SGMT_TYPE_HW_SQPC,
MLX5_SGMT_TYPE_HW_RQPC,
MLX5_SGMT_TYPE_FULL_SRQC,
MLX5_SGMT_TYPE_FULL_CQC,
MLX5_SGMT_TYPE_FULL_EQC,
MLX5_SGMT_TYPE_FULL_QPC,
MLX5_SGMT_TYPE_SND_BUFF,
MLX5_SGMT_TYPE_RCV_BUFF,
MLX5_SGMT_TYPE_SRQ_BUFF,
MLX5_SGMT_TYPE_CQ_BUFF,
MLX5_SGMT_TYPE_EQ_BUFF,
MLX5_SGMT_TYPE_SX_SLICE,
MLX5_SGMT_TYPE_SX_SLICE_ALL,
MLX5_SGMT_TYPE_RDB,
MLX5_SGMT_TYPE_RX_SLICE_ALL,
MLX5_SGMT_TYPE_MENU,
MLX5_SGMT_TYPE_TERMINATE,
MLX5_SGMT_TYPE_NUM, /* Keep last */
};
struct mlx5_rsc_key {
enum mlx5_sgmt_type rsc;
int index1;
int index2;
int num_of_obj1;
int num_of_obj2;
int size;
};
#define MLX5_RSC_DUMP_ALL 0xFFFF
struct mlx5_rsc_dump_cmd;
struct mlx5_rsc_dump;
struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev);
void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev);
int mlx5_rsc_dump_init(struct mlx5_core_dev *dev);
void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev);
struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev,
struct mlx5_rsc_key *key);
void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd);
int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
struct page *page, int *size);
#endif
......@@ -3,6 +3,7 @@
#include "health.h"
#include "lib/eq.h"
#include "lib/mlx5.h"
int mlx5e_reporter_named_obj_nest_start(struct devlink_fmsg *fmsg, char *name)
{
......@@ -197,10 +198,114 @@ int mlx5e_health_report(struct mlx5e_priv *priv,
struct devlink_health_reporter *reporter, char *err_str,
struct mlx5e_err_ctx *err_ctx)
{
netdev_err(priv->netdev, err_str);
netdev_err(priv->netdev, "%s\n", err_str);
if (!reporter)
return err_ctx->recover(&err_ctx->ctx);
return devlink_health_report(reporter, err_str, err_ctx);
}
#define MLX5_HEALTH_DEVLINK_MAX_SIZE 1024
static int mlx5e_health_rsc_fmsg_binary(struct devlink_fmsg *fmsg,
const void *value, u32 value_len)
{
u32 data_size;
u32 offset;
int err;
for (offset = 0; offset < value_len; offset += data_size) {
data_size = value_len - offset;
if (data_size > MLX5_HEALTH_DEVLINK_MAX_SIZE)
data_size = MLX5_HEALTH_DEVLINK_MAX_SIZE;
err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
if (err)
break;
}
return err;
}
int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key,
struct devlink_fmsg *fmsg)
{
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_rsc_dump_cmd *cmd;
struct page *page;
int cmd_err, err;
int end_err;
int size;
if (IS_ERR_OR_NULL(mdev->rsc_dump))
return -EOPNOTSUPP;
page = alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
err = devlink_fmsg_binary_pair_nest_start(fmsg, "data");
if (err)
return err;
cmd = mlx5_rsc_dump_cmd_create(mdev, key);
if (IS_ERR(cmd)) {
err = PTR_ERR(cmd);
goto free_page;
}
do {
cmd_err = mlx5_rsc_dump_next(mdev, cmd, page, &size);
if (cmd_err < 0) {
err = cmd_err;
goto destroy_cmd;
}
err = mlx5e_health_rsc_fmsg_binary(fmsg, page_address(page), size);
if (err)
goto destroy_cmd;
} while (cmd_err > 0);
destroy_cmd:
mlx5_rsc_dump_cmd_destroy(cmd);
end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
if (end_err)
err = end_err;
free_page:
__free_page(page);
return err;
}
int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
int queue_idx, char *lbl)
{
struct mlx5_rsc_key key = {};
int err;
key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
key.index1 = queue_idx;
key.size = PAGE_SIZE;
key.num_of_obj1 = 1;
err = devlink_fmsg_obj_nest_start(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, lbl);
if (err)
return err;
err = devlink_fmsg_u32_pair_put(fmsg, "index", queue_idx);
if (err)
return err;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
return devlink_fmsg_obj_nest_end(fmsg);
}
......@@ -5,6 +5,7 @@
#define __MLX5E_EN_HEALTH_H
#include "en.h"
#include "diag/rsc_dump.h"
#define MLX5E_RX_ERR_CQE(cqe) (get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND)
......@@ -36,6 +37,7 @@ void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq);
struct mlx5e_err_ctx {
int (*recover)(void *ctx);
int (*dump)(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg, void *ctx);
void *ctx;
};
......@@ -48,6 +50,8 @@ int mlx5e_health_report(struct mlx5e_priv *priv,
int mlx5e_health_create_reporters(struct mlx5e_priv *priv);
void mlx5e_health_destroy_reporters(struct mlx5e_priv *priv);
void mlx5e_health_channels_update(struct mlx5e_priv *priv);
int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key,
struct devlink_fmsg *fmsg);
int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
int queue_idx, char *lbl);
#endif
......@@ -343,64 +343,76 @@ int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
return err;
}
static u32 fec_supported_speeds[] = {
10000,
40000,
25000,
50000,
56000,
100000
enum mlx5e_fec_supported_link_mode {
MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G,
MLX5E_FEC_SUPPORTED_LINK_MODES_25G,
MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
};
#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds)
#define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
#define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link) \
do { \
u16 *_policy = &(policy); \
u32 *_buf = buf; \
\
if (write) \
MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy); \
else \
*_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link); \
} while (0)
#define MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(buf, policy, write, link) \
do { \
u16 *__policy = &(policy); \
bool _write = (write); \
\
if (_write && *__policy) \
*__policy = find_first_bit((u_long *)__policy, \
sizeof(u16) * BITS_PER_BYTE);\
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, *__policy, _write, link); \
if (!_write && *__policy) \
*__policy = 1 << *__policy; \
} while (0)
/* get/set FEC admin field for a given speed */
static int mlx5e_fec_admin_field(u32 *pplm,
u8 *fec_policy,
bool write,
u32 speed)
static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
enum mlx5e_fec_supported_link_mode link_mode)
{
switch (speed) {
case 10000:
case 40000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_10g_40g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_10g_40g, *fec_policy);
switch (link_mode) {
case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g);
break;
case 25000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_25g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_25g, *fec_policy);
case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g);
break;
case 50000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_50g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_50g, *fec_policy);
case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g);
break;
case 56000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_56g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_56g, *fec_policy);
case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g);
break;
case 100000:
if (!write)
*fec_policy = MLX5_GET(pplm_reg, pplm,
fec_override_admin_100g);
else
MLX5_SET(pplm_reg, pplm,
fec_override_admin_100g, *fec_policy);
case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 50g_1x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 100g_2x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 200g_4x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 400g_8x);
break;
default:
return -EINVAL;
......@@ -408,32 +420,40 @@ static int mlx5e_fec_admin_field(u32 *pplm,
return 0;
}
#define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link) \
MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
/* returns FEC capabilities for a given speed */
static int mlx5e_get_fec_cap_field(u32 *pplm,
u8 *fec_cap,
u32 speed)
static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
enum mlx5e_fec_supported_link_mode link_mode)
{
switch (speed) {
case 10000:
case 40000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_10g_40g);
switch (link_mode) {
case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g);
break;
case 25000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_25g);
case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g);
break;
case 50000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_50g);
case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g);
break;
case 56000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_56g);
case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
break;
case 100000:
*fec_cap = MLX5_GET(pplm_reg, pplm,
fec_override_cap_100g);
case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
break;
case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
break;
default:
return -EINVAL;
......@@ -441,13 +461,14 @@ static int mlx5e_get_fec_cap_field(u32 *pplm,
return 0;
}
int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
{
bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u32 current_fec_speed;
int err;
int i;
if (!MLX5_CAP_GEN(dev, pcam_reg))
return -EOPNOTSUPP;
......@@ -458,23 +479,30 @@ int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
return err;
return false;
err = mlx5e_port_linkspeed(dev, &current_fec_speed);
if (err)
return err;
for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
u16 fec_caps;
return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed);
if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
break;
mlx5e_get_fec_cap_field(out, &fec_caps, i);
if (fec_caps & fec_policy)
return true;
}
return false;
}
int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
u8 *fec_configured_mode)
u16 *fec_configured_mode)
{
bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u32 link_speed;
int err;
int i;
if (!MLX5_CAP_GEN(dev, pcam_reg))
return -EOPNOTSUPP;
......@@ -490,24 +518,28 @@ int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
*fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
if (!fec_configured_mode)
return 0;
goto out;
err = mlx5e_port_linkspeed(dev, &link_speed);
if (err)
return err;
*fec_configured_mode = 0;
for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
break;
return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed);
mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
if (*fec_configured_mode != 0)
goto out;
}
out:
return 0;
}
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
{
u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC);
bool fec_mode_not_supp_in_speed = false;
bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u8 fec_policy_auto = 0;
u8 fec_caps = 0;
u16 fec_policy_auto = 0;
int err;
int i;
......@@ -517,6 +549,9 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
if (!MLX5_CAP_PCAM_REG(dev, pplm))
return -EOPNOTSUPP;
if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
return -EOPNOTSUPP;
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
......@@ -524,25 +559,31 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
MLX5_SET(pplm_reg, out, local_port, 1);
for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) {
mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
/* policy supported for link speed, or policy is auto */
if (fec_caps & fec_policy || fec_policy == fec_policy_auto) {
mlx5e_fec_admin_field(out, &fec_policy, 1,
fec_supported_speeds[i]);
} else {
/* turn off FEC if supported. Else, leave it the same */
if (fec_caps & fec_policy_nofec)
mlx5e_fec_admin_field(out, &fec_policy_nofec, 1,
fec_supported_speeds[i]);
fec_mode_not_supp_in_speed = true;
}
}
for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
u16 conf_fec = fec_policy;
u16 fec_caps = 0;
if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
break;
if (fec_mode_not_supp_in_speed)
mlx5_core_dbg(dev,
"FEC policy 0x%x is not supported for some speeds",
fec_policy);
/* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
* to link modes up to 25G per lane and to
* MLX5E_FEC_RS_544_514 in the new link modes based on
* 50 G per lane
*/
if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
conf_fec = (1 << MLX5E_FEC_RS_544_514);
mlx5e_get_fec_cap_field(out, &fec_caps, i);
/* policy supported for link speed */
if (fec_caps & conf_fec)
mlx5e_fec_admin_field(out, &conf_fec, 1, i);
else
/* set FEC to auto*/
mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
}
return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
}
......@@ -60,15 +60,17 @@ int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps);
bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy);
int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
u8 *fec_configured_mode);
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy);
u16 *fec_configured_mode);
int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy);
enum {
MLX5E_FEC_NOFEC,
MLX5E_FEC_FIRECODE,
MLX5E_FEC_RS_528_514,
MLX5E_FEC_RS_544_514 = 7,
MLX5E_FEC_LLRS_272_257_1 = 9,
};
#endif
......@@ -102,19 +102,6 @@ static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
return err;
}
void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq)
{
struct mlx5e_priv *priv = icosq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = icosq;
err_ctx.recover = mlx5e_rx_reporter_err_icosq_cqe_recover;
sprintf(err_str, "ERR CQE on ICOSQ: 0x%x", icosq->sqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
static int mlx5e_rq_to_ready(struct mlx5e_rq *rq, int curr_state)
{
struct net_device *dev = rq->netdev;
......@@ -171,19 +158,6 @@ static int mlx5e_rx_reporter_err_rq_cqe_recover(void *ctx)
return err;
}
void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq *rq)
{
struct mlx5e_priv *priv = rq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = rq;
err_ctx.recover = mlx5e_rx_reporter_err_rq_cqe_recover;
sprintf(err_str, "ERR CQE on RQ: 0x%x", rq->rqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
static int mlx5e_rx_reporter_timeout_recover(void *ctx)
{
struct mlx5e_icosq *icosq;
......@@ -201,21 +175,6 @@ static int mlx5e_rx_reporter_timeout_recover(void *ctx)
return err;
}
void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq)
{
struct mlx5e_icosq *icosq = &rq->channel->icosq;
struct mlx5e_priv *priv = rq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = rq;
err_ctx.recover = mlx5e_rx_reporter_timeout_recover;
sprintf(err_str, "RX timeout on channel: %d, ICOSQ: 0x%x RQ: 0x%x, CQ: 0x%x\n",
icosq->channel->ix, icosq->sqn, rq->rqn, rq->cq.mcq.cqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
static int mlx5e_rx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx)
{
return err_ctx->recover(err_ctx->ctx);
......@@ -371,10 +330,235 @@ static int mlx5e_rx_reporter_diagnose(struct devlink_health_reporter *reporter,
return err;
}
static int mlx5e_rx_reporter_dump_icosq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
void *ctx)
{
struct mlx5e_txqsq *icosq = ctx;
struct mlx5_rsc_key key = {};
int err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice");
if (err)
return err;
key.size = PAGE_SIZE;
key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "ICOSQ");
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
key.index1 = icosq->sqn;
key.num_of_obj1 = 1;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "send_buff");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_SND_BUFF;
key.num_of_obj2 = MLX5_RSC_DUMP_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
return mlx5e_reporter_named_obj_nest_end(fmsg);
}
static int mlx5e_rx_reporter_dump_rq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
void *ctx)
{
struct mlx5_rsc_key key = {};
struct mlx5e_rq *rq = ctx;
int err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "RX Slice");
if (err)
return err;
key.size = PAGE_SIZE;
key.rsc = MLX5_SGMT_TYPE_RX_SLICE_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "RQ");
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
key.index1 = rq->rqn;
key.num_of_obj1 = 1;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "receive_buff");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_RCV_BUFF;
key.num_of_obj2 = MLX5_RSC_DUMP_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
return mlx5e_reporter_named_obj_nest_end(fmsg);
}
static int mlx5e_rx_reporter_dump_all_rqs(struct mlx5e_priv *priv,
struct devlink_fmsg *fmsg)
{
struct mlx5_rsc_key key = {};
int i, err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "RX Slice");
if (err)
return err;
key.size = PAGE_SIZE;
key.rsc = MLX5_SGMT_TYPE_RX_SLICE_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = devlink_fmsg_arr_pair_nest_start(fmsg, "RQs");
if (err)
return err;
for (i = 0; i < priv->channels.num; i++) {
struct mlx5e_rq *rq = &priv->channels.c[i]->rq;
err = mlx5e_health_queue_dump(priv, fmsg, rq->rqn, "RQ");
if (err)
return err;
}
return devlink_fmsg_arr_pair_nest_end(fmsg);
}
static int mlx5e_rx_reporter_dump_from_ctx(struct mlx5e_priv *priv,
struct mlx5e_err_ctx *err_ctx,
struct devlink_fmsg *fmsg)
{
return err_ctx->dump(priv, fmsg, err_ctx->ctx);
}
static int mlx5e_rx_reporter_dump(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg, void *context,
struct netlink_ext_ack *extack)
{
struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
struct mlx5e_err_ctx *err_ctx = context;
return err_ctx ? mlx5e_rx_reporter_dump_from_ctx(priv, err_ctx, fmsg) :
mlx5e_rx_reporter_dump_all_rqs(priv, fmsg);
}
void mlx5e_reporter_rx_timeout(struct mlx5e_rq *rq)
{
struct mlx5e_icosq *icosq = &rq->channel->icosq;
struct mlx5e_priv *priv = rq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = rq;
err_ctx.recover = mlx5e_rx_reporter_timeout_recover;
err_ctx.dump = mlx5e_rx_reporter_dump_rq;
snprintf(err_str, sizeof(err_str),
"RX timeout on channel: %d, ICOSQ: 0x%x RQ: 0x%x, CQ: 0x%x",
icosq->channel->ix, icosq->sqn, rq->rqn, rq->cq.mcq.cqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq *rq)
{
struct mlx5e_priv *priv = rq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = rq;
err_ctx.recover = mlx5e_rx_reporter_err_rq_cqe_recover;
err_ctx.dump = mlx5e_rx_reporter_dump_rq;
snprintf(err_str, sizeof(err_str), "ERR CQE on RQ: 0x%x", rq->rqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq *icosq)
{
struct mlx5e_priv *priv = icosq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = icosq;
err_ctx.recover = mlx5e_rx_reporter_err_icosq_cqe_recover;
err_ctx.dump = mlx5e_rx_reporter_dump_icosq;
snprintf(err_str, sizeof(err_str), "ERR CQE on ICOSQ: 0x%x", icosq->sqn);
mlx5e_health_report(priv, priv->rx_reporter, err_str, &err_ctx);
}
static const struct devlink_health_reporter_ops mlx5_rx_reporter_ops = {
.name = "rx",
.recover = mlx5e_rx_reporter_recover,
.diagnose = mlx5e_rx_reporter_diagnose,
.dump = mlx5e_rx_reporter_dump,
};
#define MLX5E_REPORTER_RX_GRACEFUL_PERIOD 500
......
......@@ -82,19 +82,6 @@ static int mlx5e_tx_reporter_err_cqe_recover(void *ctx)
return err;
}
void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq)
{
struct mlx5e_priv *priv = sq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {0};
err_ctx.ctx = sq;
err_ctx.recover = mlx5e_tx_reporter_err_cqe_recover;
sprintf(err_str, "ERR CQE on SQ: 0x%x", sq->sqn);
mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
}
static int mlx5e_tx_reporter_timeout_recover(void *ctx)
{
struct mlx5_eq_comp *eq;
......@@ -110,22 +97,6 @@ static int mlx5e_tx_reporter_timeout_recover(void *ctx)
return err;
}
int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq)
{
struct mlx5e_priv *priv = sq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx;
err_ctx.ctx = sq;
err_ctx.recover = mlx5e_tx_reporter_timeout_recover;
sprintf(err_str,
"TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u\n",
sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc,
jiffies_to_usecs(jiffies - sq->txq->trans_start));
return mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
}
/* state lock cannot be grabbed within this function.
* It can cause a dead lock or a read-after-free.
*/
......@@ -275,10 +246,162 @@ static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter,
return err;
}
static int mlx5e_tx_reporter_dump_sq(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
void *ctx)
{
struct mlx5_rsc_key key = {};
struct mlx5e_txqsq *sq = ctx;
int err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice");
if (err)
return err;
key.size = PAGE_SIZE;
key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "SQ");
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "QPC");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
key.index1 = sq->sqn;
key.num_of_obj1 = 1;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "send_buff");
if (err)
return err;
key.rsc = MLX5_SGMT_TYPE_SND_BUFF;
key.num_of_obj2 = MLX5_RSC_DUMP_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
return mlx5e_reporter_named_obj_nest_end(fmsg);
}
static int mlx5e_tx_reporter_dump_all_sqs(struct mlx5e_priv *priv,
struct devlink_fmsg *fmsg)
{
struct mlx5_rsc_key key = {};
int i, tc, err;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
err = mlx5e_reporter_named_obj_nest_start(fmsg, "SX Slice");
if (err)
return err;
key.size = PAGE_SIZE;
key.rsc = MLX5_SGMT_TYPE_SX_SLICE_ALL;
err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
if (err)
return err;
err = mlx5e_reporter_named_obj_nest_end(fmsg);
if (err)
return err;
err = devlink_fmsg_arr_pair_nest_start(fmsg, "SQs");
if (err)
return err;
for (i = 0; i < priv->channels.num; i++) {
struct mlx5e_channel *c = priv->channels.c[i];
for (tc = 0; tc < priv->channels.params.num_tc; tc++) {
struct mlx5e_txqsq *sq = &c->sq[tc];
err = mlx5e_health_queue_dump(priv, fmsg, sq->sqn, "SQ");
if (err)
return err;
}
}
return devlink_fmsg_arr_pair_nest_end(fmsg);
}
static int mlx5e_tx_reporter_dump_from_ctx(struct mlx5e_priv *priv,
struct mlx5e_err_ctx *err_ctx,
struct devlink_fmsg *fmsg)
{
return err_ctx->dump(priv, fmsg, err_ctx->ctx);
}
static int mlx5e_tx_reporter_dump(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg, void *context,
struct netlink_ext_ack *extack)
{
struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
struct mlx5e_err_ctx *err_ctx = context;
return err_ctx ? mlx5e_tx_reporter_dump_from_ctx(priv, err_ctx, fmsg) :
mlx5e_tx_reporter_dump_all_sqs(priv, fmsg);
}
void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq)
{
struct mlx5e_priv *priv = sq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = sq;
err_ctx.recover = mlx5e_tx_reporter_err_cqe_recover;
err_ctx.dump = mlx5e_tx_reporter_dump_sq;
snprintf(err_str, sizeof(err_str), "ERR CQE on SQ: 0x%x", sq->sqn);
mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
}
int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq)
{
struct mlx5e_priv *priv = sq->channel->priv;
char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
struct mlx5e_err_ctx err_ctx = {};
err_ctx.ctx = sq;
err_ctx.recover = mlx5e_tx_reporter_timeout_recover;
err_ctx.dump = mlx5e_tx_reporter_dump_sq;
snprintf(err_str, sizeof(err_str),
"TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u",
sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc,
jiffies_to_usecs(jiffies - sq->txq->trans_start));
return mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
}
static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
.name = "tx",
.recover = mlx5e_tx_reporter_recover,
.diagnose = mlx5e_tx_reporter_diagnose,
.dump = mlx5e_tx_reporter_dump,
};
#define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500
......
......@@ -433,7 +433,6 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv)
if (!ipsec)
return;
drain_workqueue(ipsec->wq);
destroy_workqueue(ipsec->wq);
ida_destroy(&ipsec->halloc);
......
......@@ -633,6 +633,8 @@ static const u32 pplm_fec_2_ethtool[] = {
[MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF,
[MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER,
[MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS,
[MLX5E_FEC_RS_544_514] = ETHTOOL_FEC_RS,
[MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_FEC_LLRS,
};
static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
......@@ -650,45 +652,48 @@ static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
return 0;
}
/* we use ETHTOOL_FEC_* offset and apply it to ETHTOOL_LINK_MODE_FEC_*_BIT */
static u32 ethtool_fec2ethtool_caps(u_long ethtool_fec_code)
{
u32 offset;
offset = find_first_bit(&ethtool_fec_code, sizeof(u32));
offset -= ETHTOOL_FEC_OFF_BIT;
offset += ETHTOOL_LINK_MODE_FEC_NONE_BIT;
#define MLX5E_ADVERTISE_SUPPORTED_FEC(mlx5_fec, ethtool_fec) \
do { \
if (mlx5e_fec_in_caps(dev, 1 << (mlx5_fec))) \
__set_bit(ethtool_fec, \
link_ksettings->link_modes.supported);\
} while (0)
return offset;
}
static const u32 pplm_fec_2_ethtool_linkmodes[] = {
[MLX5E_FEC_NOFEC] = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
[MLX5E_FEC_FIRECODE] = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
[MLX5E_FEC_RS_528_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[MLX5E_FEC_RS_544_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
};
static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
struct ethtool_link_ksettings *link_ksettings)
{
u_long fec_caps = 0;
u32 active_fec = 0;
u32 offset;
u_long active_fec = 0;
u32 bitn;
int err;
err = mlx5e_get_fec_caps(dev, (u8 *)&fec_caps);
err = mlx5e_get_fec_mode(dev, (u32 *)&active_fec, NULL);
if (err)
return (err == -EOPNOTSUPP) ? 0 : err;
err = mlx5e_get_fec_mode(dev, &active_fec, NULL);
if (err)
return err;
for_each_set_bit(bitn, &fec_caps, ARRAY_SIZE(pplm_fec_2_ethtool)) {
u_long ethtool_bitmask = pplm_fec_2_ethtool[bitn];
offset = ethtool_fec2ethtool_caps(ethtool_bitmask);
__set_bit(offset, link_ksettings->link_modes.supported);
}
active_fec = pplm2ethtool_fec(active_fec, sizeof(u32) * BITS_PER_BYTE);
offset = ethtool_fec2ethtool_caps(active_fec);
__set_bit(offset, link_ksettings->link_modes.advertising);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_NOFEC,
ETHTOOL_LINK_MODE_FEC_NONE_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_FIRECODE,
ETHTOOL_LINK_MODE_FEC_BASER_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_528_514,
ETHTOOL_LINK_MODE_FEC_RS_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_LLRS_272_257_1,
ETHTOOL_LINK_MODE_FEC_LLRS_BIT);
/* active fec is a bit set, find out which bit is set and
* advertise the corresponding ethtool bit
*/
bitn = find_first_bit(&active_fec, sizeof(u32) * BITS_PER_BYTE);
if (bitn < ARRAY_SIZE(pplm_fec_2_ethtool_linkmodes))
__set_bit(pplm_fec_2_ethtool_linkmodes[bitn],
link_ksettings->link_modes.advertising);
return 0;
}
......@@ -1511,7 +1516,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev,
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
u8 fec_configured = 0;
u16 fec_configured = 0;
u32 fec_active = 0;
int err;
......@@ -1527,7 +1532,7 @@ static int mlx5e_get_fecparam(struct net_device *netdev,
return -EOPNOTSUPP;
fecparam->fec = pplm2ethtool_fec((u_long)fec_configured,
sizeof(u8) * BITS_PER_BYTE);
sizeof(u16) * BITS_PER_BYTE);
return 0;
}
......@@ -1537,10 +1542,14 @@ static int mlx5e_set_fecparam(struct net_device *netdev,
{
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
u8 fec_policy = 0;
u16 fec_policy = 0;
int mode;
int err;
if (bitmap_weight((unsigned long *)&fecparam->fec,
ETHTOOL_FEC_LLRS_BIT + 1) > 1)
return -EOPNOTSUPP;
for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {
if (!(pplm_fec_2_ethtool[mode] & fecparam->fec))
continue;
......
......@@ -70,6 +70,7 @@
#include "diag/fw_tracer.h"
#include "ecpf.h"
#include "lib/hv_vhca.h"
#include "diag/rsc_dump.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
......@@ -880,6 +881,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
dev->tracer = mlx5_fw_tracer_create(dev);
dev->hv_vhca = mlx5_hv_vhca_create(dev);
dev->rsc_dump = mlx5_rsc_dump_create(dev);
return 0;
......@@ -909,6 +911,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
{
mlx5_rsc_dump_destroy(dev);
mlx5_hv_vhca_destroy(dev->hv_vhca);
mlx5_fw_tracer_destroy(dev->tracer);
mlx5_dm_cleanup(dev);
......@@ -1079,6 +1082,12 @@ static int mlx5_load(struct mlx5_core_dev *dev)
mlx5_hv_vhca_init(dev->hv_vhca);
err = mlx5_rsc_dump_init(dev);
if (err) {
mlx5_core_err(dev, "Failed to init Resource dump\n");
goto err_rsc_dump;
}
err = mlx5_fpga_device_start(dev);
if (err) {
mlx5_core_err(dev, "fpga device start failed %d\n", err);
......@@ -1134,6 +1143,8 @@ static int mlx5_load(struct mlx5_core_dev *dev)
err_ipsec_start:
mlx5_fpga_device_stop(dev);
err_fpga_start:
mlx5_rsc_dump_cleanup(dev);
err_rsc_dump:
mlx5_hv_vhca_cleanup(dev->hv_vhca);
mlx5_fw_tracer_cleanup(dev->tracer);
err_fw_tracer:
......@@ -1155,6 +1166,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
mlx5_accel_ipsec_cleanup(dev);
mlx5_accel_tls_cleanup(dev);
mlx5_fpga_device_stop(dev);
mlx5_rsc_dump_cleanup(dev);
mlx5_hv_vhca_cleanup(dev->hv_vhca);
mlx5_fw_tracer_cleanup(dev->tracer);
mlx5_eq_table_destroy(dev);
......
......@@ -8,7 +8,7 @@
const char *phy_speed_to_str(int speed)
{
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 74,
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 75,
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
"If a speed or mode has been added please update phy_speed_to_str "
"and the PHY settings array.\n");
......
......@@ -722,6 +722,7 @@ struct mlx5_core_dev {
struct mlx5_clock clock;
struct mlx5_ib_clock_info *clock_info;
struct mlx5_fw_tracer *tracer;
struct mlx5_rsc_dump *rsc_dump;
u32 vsc_addr;
struct mlx5_hv_vhca *hv_vhca;
};
......
......@@ -981,12 +981,17 @@ int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg);
int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
const char *name);
int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg);
int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
const char *name);
int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg);
int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value);
int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value);
int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value);
int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value);
int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value);
int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
u16 value_len);
int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
bool value);
......
......@@ -1330,6 +1330,7 @@ enum ethtool_fec_config_bits {
ETHTOOL_FEC_OFF_BIT,
ETHTOOL_FEC_RS_BIT,
ETHTOOL_FEC_BASER_BIT,
ETHTOOL_FEC_LLRS_BIT,
};
#define ETHTOOL_FEC_NONE (1 << ETHTOOL_FEC_NONE_BIT)
......@@ -1337,6 +1338,7 @@ enum ethtool_fec_config_bits {
#define ETHTOOL_FEC_OFF (1 << ETHTOOL_FEC_OFF_BIT)
#define ETHTOOL_FEC_RS (1 << ETHTOOL_FEC_RS_BIT)
#define ETHTOOL_FEC_BASER (1 << ETHTOOL_FEC_BASER_BIT)
#define ETHTOOL_FEC_LLRS (1 << ETHTOOL_FEC_LLRS_BIT)
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* DEPRECATED, Get settings.
......@@ -1521,7 +1523,7 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72,
ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73,
ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74,
/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
};
......
......@@ -4237,6 +4237,12 @@ struct devlink_fmsg_item {
struct devlink_fmsg {
struct list_head item_list;
bool putting_binary; /* This flag forces enclosing of binary data
* in an array brackets. It forces using
* of designated API:
* devlink_fmsg_binary_pair_nest_start()
* devlink_fmsg_binary_pair_nest_end()
*/
};
static struct devlink_fmsg *devlink_fmsg_alloc(void)
......@@ -4280,17 +4286,26 @@ static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
}
int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_nest_end(fmsg);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
......@@ -4301,6 +4316,9 @@ static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
{
struct devlink_fmsg_item *item;
if (fmsg->putting_binary)
return -EINVAL;
if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
return -EMSGSIZE;
......@@ -4321,6 +4339,9 @@ int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
{
int err;
if (fmsg->putting_binary)
return -EINVAL;
err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
if (err)
return err;
......@@ -4335,6 +4356,9 @@ EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_nest_end(fmsg);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
......@@ -4344,6 +4368,9 @@ int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
{
int err;
if (fmsg->putting_binary)
return -EINVAL;
err = devlink_fmsg_pair_nest_start(fmsg, name);
if (err)
return err;
......@@ -4360,6 +4387,9 @@ int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
{
int err;
if (fmsg->putting_binary)
return -EINVAL;
err = devlink_fmsg_nest_end(fmsg);
if (err)
return err;
......@@ -4372,6 +4402,30 @@ int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
}
EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
const char *name)
{
int err;
err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
if (err)
return err;
fmsg->putting_binary = true;
return err;
}
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
{
if (!fmsg->putting_binary)
return -EINVAL;
fmsg->putting_binary = false;
return devlink_fmsg_arr_pair_nest_end(fmsg);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
const void *value, u16 value_len,
u8 value_nla_type)
......@@ -4396,40 +4450,59 @@ static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
{
if (fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
NLA_NUL_STRING);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
static int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
u16 value_len)
{
if (!fmsg->putting_binary)
return -EINVAL;
return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
}
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
bool value)
......@@ -4540,10 +4613,11 @@ int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
const void *value, u32 value_len)
{
u32 data_size;
int end_err;
u32 offset;
int err;
err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
if (err)
return err;
......@@ -4553,14 +4627,18 @@ int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
data_size = DEVLINK_FMSG_MAX_SIZE;
err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
if (err)
return err;
break;
/* Exit from loop with a break (instead of
* return) to make sure putting_binary is turned off in
* devlink_fmsg_binary_pair_nest_end
*/
}
err = devlink_fmsg_arr_pair_nest_end(fmsg);
if (err)
return err;
end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
if (end_err)
err = end_err;
return 0;
return err;
}
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
......
......@@ -168,6 +168,7 @@ const char link_mode_names[][ETH_GSTRING_LEN] = {
__DEFINE_LINK_MODE_NAME(400000, LR8_ER8_FR8, Full),
__DEFINE_LINK_MODE_NAME(400000, DR8, Full),
__DEFINE_LINK_MODE_NAME(400000, CR8, Full),
__DEFINE_SPECIAL_MODE_NAME(FEC_LLRS, "LLRS"),
};
static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
......
......@@ -237,6 +237,7 @@ static const struct link_mode_info link_mode_params[] = {
__DEFINE_LINK_MODE_PARAMS(400000, LR8_ER8_FR8, Full),
__DEFINE_LINK_MODE_PARAMS(400000, DR8, Full),
__DEFINE_LINK_MODE_PARAMS(400000, CR8, Full),
__DEFINE_SPECIAL_MODE_PARAMS(FEC_LLRS),
};
static const struct nla_policy
......
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