Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4f287c4 authored by Saeed Mahameed's avatar Saeed Mahameed Committed by Leon Romanovsky
Browse files

net/mlx5: Unify and improve command interface



Now as all commands use mlx5 ifc interface, instead of doing two calls
for executing a command we embed command status checking into
mlx5_cmd_exec to simplify the interface.

Also we do here some cleanup for redundant software structures
(inbox/outbox) and functions and improved command failure output.

Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
parent 1a412fb1
Loading
Loading
Loading
Loading
+3 −7
Original line number Diff line number Diff line
@@ -234,22 +234,18 @@ static int set_roce_addr(struct ib_device *device, u8 port_num,
			 const struct ib_gid_attr *attr)
{
	struct mlx5_ib_dev *dev = to_mdev(device);
	u32  in[MLX5_ST_SZ_DW(set_roce_address_in)];
	u32 out[MLX5_ST_SZ_DW(set_roce_address_out)];
	u32  in[MLX5_ST_SZ_DW(set_roce_address_in)]  = {0};
	u32 out[MLX5_ST_SZ_DW(set_roce_address_out)] = {0};
	void *in_addr = MLX5_ADDR_OF(set_roce_address_in, in, roce_address);
	enum rdma_link_layer ll = mlx5_ib_port_link_layer(device, port_num);

	if (ll != IB_LINK_LAYER_ETHERNET)
		return -EINVAL;

	memset(in, 0, sizeof(in));

	ib_gid_to_mlx5_roce_addr(gid, attr, in_addr);

	MLX5_SET(set_roce_address_in, in, roce_address_index, index);
	MLX5_SET(set_roce_address_in, in, opcode, MLX5_CMD_OP_SET_ROCE_ADDRESS);

	memset(out, 0, sizeof(out));
	return mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out));
}

+1 −4
Original line number Diff line number Diff line
@@ -1007,13 +1007,10 @@ static int is_connected(enum ib_qp_type qp_type)
static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
				    struct mlx5_ib_sq *sq, u32 tdn)
{
	u32 in[MLX5_ST_SZ_DW(create_tis_in)];
	u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
	void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);

	memset(in, 0, sizeof(in));

	MLX5_SET(tisc, tisc, transport_domain, tdn);

	return mlx5_core_create_tis(dev->mdev, in, sizeof(in), &sq->tisn);
}

+131 −120
Original line number Diff line number Diff line
@@ -554,11 +554,124 @@ const char *mlx5_command_str(int command)
	}
}

static const char *cmd_status_str(u8 status)
{
	switch (status) {
	case MLX5_CMD_STAT_OK:
		return "OK";
	case MLX5_CMD_STAT_INT_ERR:
		return "internal error";
	case MLX5_CMD_STAT_BAD_OP_ERR:
		return "bad operation";
	case MLX5_CMD_STAT_BAD_PARAM_ERR:
		return "bad parameter";
	case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:
		return "bad system state";
	case MLX5_CMD_STAT_BAD_RES_ERR:
		return "bad resource";
	case MLX5_CMD_STAT_RES_BUSY:
		return "resource busy";
	case MLX5_CMD_STAT_LIM_ERR:
		return "limits exceeded";
	case MLX5_CMD_STAT_BAD_RES_STATE_ERR:
		return "bad resource state";
	case MLX5_CMD_STAT_IX_ERR:
		return "bad index";
	case MLX5_CMD_STAT_NO_RES_ERR:
		return "no resources";
	case MLX5_CMD_STAT_BAD_INP_LEN_ERR:
		return "bad input length";
	case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:
		return "bad output length";
	case MLX5_CMD_STAT_BAD_QP_STATE_ERR:
		return "bad QP state";
	case MLX5_CMD_STAT_BAD_PKT_ERR:
		return "bad packet (discarded)";
	case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:
		return "bad size too many outstanding CQEs";
	default:
		return "unknown status";
	}
}

static int cmd_status_to_err(u8 status)
{
	switch (status) {
	case MLX5_CMD_STAT_OK:				return 0;
	case MLX5_CMD_STAT_INT_ERR:			return -EIO;
	case MLX5_CMD_STAT_BAD_OP_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_BAD_PARAM_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_RES_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_RES_BUSY:			return -EBUSY;
	case MLX5_CMD_STAT_LIM_ERR:			return -ENOMEM;
	case MLX5_CMD_STAT_BAD_RES_STATE_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_IX_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_NO_RES_ERR:			return -EAGAIN;
	case MLX5_CMD_STAT_BAD_INP_LEN_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_QP_STATE_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_BAD_PKT_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:	return -EINVAL;
	default:					return -EIO;
	}
}

struct mlx5_ifc_mbox_out_bits {
	u8         status[0x8];
	u8         reserved_at_8[0x18];

	u8         syndrome[0x20];

	u8         reserved_at_40[0x40];
};

struct mlx5_ifc_mbox_in_bits {
	u8         opcode[0x10];
	u8         reserved_at_10[0x10];

	u8         reserved_at_20[0x10];
	u8         op_mod[0x10];

	u8         reserved_at_40[0x40];
};

void mlx5_cmd_mbox_status(void *out, u8 *status, u32 *syndrome)
{
	*status = MLX5_GET(mbox_out, out, status);
	*syndrome = MLX5_GET(mbox_out, out, syndrome);
}

static int mlx5_cmd_check(struct mlx5_core_dev *dev, void *in, void *out)
{
	u32 syndrome;
	u8  status;
	u16 opcode;
	u16 op_mod;

	mlx5_cmd_mbox_status(out, &status, &syndrome);
	if (!status)
		return 0;

	opcode = MLX5_GET(mbox_in, in, opcode);
	op_mod = MLX5_GET(mbox_in, in, op_mod);

	mlx5_core_err(dev,
		      "%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x)\n",
		      mlx5_command_str(opcode),
		      opcode, op_mod,
		      cmd_status_str(status),
		      status,
		      syndrome);

	return cmd_status_to_err(status);
}

static void dump_command(struct mlx5_core_dev *dev,
			 struct mlx5_cmd_work_ent *ent, int input)
{
	u16 op = be16_to_cpu(((struct mlx5_inbox_hdr *)(ent->lay->in))->opcode);
	struct mlx5_cmd_msg *msg = input ? ent->in : ent->out;
	u16 op = MLX5_GET(mbox_in, ent->lay->in, opcode);
	struct mlx5_cmd_mailbox *next = msg->next;
	int data_only;
	u32 offset = 0;
@@ -608,9 +721,7 @@ static void dump_command(struct mlx5_core_dev *dev,

static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
{
	struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data);

	return be16_to_cpu(hdr->opcode);
	return MLX5_GET(mbox_in, in->first.data, opcode);
}

static void cb_timeout_handler(struct work_struct *work)
@@ -749,16 +860,6 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
	return err;
}

static __be32 *get_synd_ptr(struct mlx5_outbox_hdr *out)
{
	return &out->syndrome;
}

static u8 *get_status_ptr(struct mlx5_outbox_hdr *out)
{
	return &out->status;
}

/*  Notes:
 *    1. Callback functions may not sleep
 *    2. page queue commands do not support asynchrous completion
@@ -804,7 +905,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
		goto out_free;

	ds = ent->ts2 - ent->ts1;
	op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
	op = MLX5_GET(mbox_in, in->first.data, opcode);
	if (op < ARRAY_SIZE(cmd->stats)) {
		stats = &cmd->stats[op];
		spin_lock_irq(&stats->lock);
@@ -1305,7 +1406,10 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec)
					err = mlx5_copy_from_msg(ent->uout,
								 ent->out,
								 ent->uout_size);
					err = err ? err : mlx5_cmd_status_to_err_v2(ent->uout);

					err = err ? err : mlx5_cmd_check(dev,
									ent->in->first.data,
									ent->uout);
				}

				mlx5_free_cmd_msg(dev, ent->out);
@@ -1359,14 +1463,9 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
	return msg;
}

static u16 opcode_from_in(struct mlx5_inbox_hdr *in)
{
	return be16_to_cpu(in->opcode);
}

static int is_manage_pages(struct mlx5_inbox_hdr *in)
static int is_manage_pages(void *in)
{
	return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES;
	return MLX5_GET(mbox_in, in, opcode) == MLX5_CMD_OP_MANAGE_PAGES;
}

static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
@@ -1382,9 +1481,11 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,

	if (pci_channel_offline(dev->pdev) ||
	    dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
		err = mlx5_internal_err_ret_value(dev, opcode_from_in(in), &drv_synd, &status);
		*get_synd_ptr(out) = cpu_to_be32(drv_synd);
		*get_status_ptr(out) = status;
		u16 opcode = MLX5_GET(mbox_in, in, opcode);

		err = mlx5_internal_err_ret_value(dev, opcode, &drv_synd, &status);
		MLX5_SET(mbox_out, out, status, status);
		MLX5_SET(mbox_out, out, syndrome, drv_synd);
		return err;
	}

@@ -1436,7 +1537,10 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
		  int out_size)
{
	return cmd_exec(dev, in, in_size, out, out_size, NULL, NULL);
	int err;

	err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL);
	return err ? : mlx5_cmd_check(dev, in, out);
}
EXPORT_SYMBOL(mlx5_cmd_exec);

@@ -1673,96 +1777,3 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
	pci_pool_destroy(cmd->pool);
}
EXPORT_SYMBOL(mlx5_cmd_cleanup);

static const char *cmd_status_str(u8 status)
{
	switch (status) {
	case MLX5_CMD_STAT_OK:
		return "OK";
	case MLX5_CMD_STAT_INT_ERR:
		return "internal error";
	case MLX5_CMD_STAT_BAD_OP_ERR:
		return "bad operation";
	case MLX5_CMD_STAT_BAD_PARAM_ERR:
		return "bad parameter";
	case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:
		return "bad system state";
	case MLX5_CMD_STAT_BAD_RES_ERR:
		return "bad resource";
	case MLX5_CMD_STAT_RES_BUSY:
		return "resource busy";
	case MLX5_CMD_STAT_LIM_ERR:
		return "limits exceeded";
	case MLX5_CMD_STAT_BAD_RES_STATE_ERR:
		return "bad resource state";
	case MLX5_CMD_STAT_IX_ERR:
		return "bad index";
	case MLX5_CMD_STAT_NO_RES_ERR:
		return "no resources";
	case MLX5_CMD_STAT_BAD_INP_LEN_ERR:
		return "bad input length";
	case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:
		return "bad output length";
	case MLX5_CMD_STAT_BAD_QP_STATE_ERR:
		return "bad QP state";
	case MLX5_CMD_STAT_BAD_PKT_ERR:
		return "bad packet (discarded)";
	case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:
		return "bad size too many outstanding CQEs";
	default:
		return "unknown status";
	}
}

static int cmd_status_to_err(u8 status)
{
	switch (status) {
	case MLX5_CMD_STAT_OK:				return 0;
	case MLX5_CMD_STAT_INT_ERR:			return -EIO;
	case MLX5_CMD_STAT_BAD_OP_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_BAD_PARAM_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_RES_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_RES_BUSY:			return -EBUSY;
	case MLX5_CMD_STAT_LIM_ERR:			return -ENOMEM;
	case MLX5_CMD_STAT_BAD_RES_STATE_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_IX_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_NO_RES_ERR:			return -EAGAIN;
	case MLX5_CMD_STAT_BAD_INP_LEN_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_OUTP_LEN_ERR:		return -EIO;
	case MLX5_CMD_STAT_BAD_QP_STATE_ERR:		return -EINVAL;
	case MLX5_CMD_STAT_BAD_PKT_ERR:			return -EINVAL;
	case MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR:	return -EINVAL;
	default:					return -EIO;
	}
}

/* this will be available till all the commands use set/get macros */
int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)
{
	if (!hdr->status)
		return 0;

	pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n",
		cmd_status_str(hdr->status), hdr->status,
		be32_to_cpu(hdr->syndrome));

	return cmd_status_to_err(hdr->status);
}

int mlx5_cmd_status_to_err_v2(void *ptr)
{
	u32	syndrome;
	u8	status;

	status = be32_to_cpu(*(__be32 *)ptr) >> 24;
	if (!status)
		return 0;

	syndrome = be32_to_cpu(*(__be32 *)(ptr + 4));

	pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n",
		cmd_status_str(status), status, syndrome);

	return cmd_status_to_err(status);
}
+4 −12
Original line number Diff line number Diff line
@@ -153,7 +153,6 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
	memset(out, 0, sizeof(out));
	MLX5_SET(create_cq_in, in, opcode, MLX5_CMD_OP_CREATE_CQ);
	err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
	err = err ? : mlx5_cmd_status_to_err_v2(out);
	if (err)
		return err;

@@ -187,9 +186,8 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
	memset(dout, 0, sizeof(dout));
	MLX5_SET(destroy_cq_in, din, opcode, MLX5_CMD_OP_DESTROY_CQ);
	MLX5_SET(destroy_cq_in, din, cqn, cq->cqn);
	err = mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout));
	return err ? : mlx5_cmd_status_to_err_v2(out);

	mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout));
	return err;
}
EXPORT_SYMBOL(mlx5_core_create_cq);

@@ -216,7 +214,6 @@ int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
	MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
	MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
	err = err ? : mlx5_cmd_status_to_err_v2(out);
	if (err)
		return err;

@@ -235,13 +232,10 @@ int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
		       u32 *out, int outlen)
{
	u32 in[MLX5_ST_SZ_DW(query_cq_in)] = {0};
	int err;

	MLX5_SET(query_cq_in, in, opcode, MLX5_CMD_OP_QUERY_CQ);
	MLX5_SET(query_cq_in, in, cqn, cq->cqn);

	err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
	return err ? : mlx5_cmd_status_to_err_v2(out);
	return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
}
EXPORT_SYMBOL(mlx5_core_query_cq);

@@ -249,11 +243,9 @@ int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
			u32 *in, int inlen)
{
	u32 out[MLX5_ST_SZ_DW(modify_cq_out)] = {0};
	int err;

	MLX5_SET(modify_cq_in, in, opcode, MLX5_CMD_OP_MODIFY_CQ);
	err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
	return err ? : mlx5_cmd_status_to_err_v2(out);
	return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
}
EXPORT_SYMBOL(mlx5_core_modify_cq);

+1 −2
Original line number Diff line number Diff line
@@ -726,7 +726,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
{
	struct mlx5e_priv *priv    = netdev_priv(netdev);
	struct mlx5_core_dev *mdev = priv->mdev;
	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
	u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0};
	u32 eth_proto_cap;
	u32 eth_proto_admin;
	u32 eth_proto_lp;
@@ -736,7 +736,6 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
	int err;

	err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1);

	if (err) {
		netdev_err(netdev, "%s: query port ptys failed: %d\n",
			   __func__, err);
Loading