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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+286 −0
Original line number Diff line number Diff line
// 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);
}
+58 −0
Original line number Diff line number Diff line
/* 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
+106 −1
Original line number Diff line number Diff line
@@ -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);
}
+6 −2
Original line number Diff line number Diff line
@@ -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
Loading