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

Commit fe6f700d authored by Yevgeny Petrilin's avatar Yevgeny Petrilin Committed by David S. Miller
Browse files

net/mlx4_core: Respond to operation request by firmware



This commit adds new firmware command and new firmware event.  The firmware
raises the MLX4_EVENT_TYPE_OP_REQUIRED event in order to signal the driver it
needs to perform an administrative operation throughout the MLX4_CMD_GET_OP_REQ
command. At the moment the supported operation is adding/removing multicast
entries which are used by the firmware for handling NCSI traffic in B0
steering mode.

Also, had to swap the order of mlx4_init_mcg_table() and
mlx4_init_eq_table() to make sure that driver will get events only after
resources are initialized to handle it.

Signed-off-by: default avatarYevgeny Petrilin <yevgenyp@mellanox.com>
Signed-off-by: default avatarJack Morgenstein <jackm@dev.mellanox.com>
Signed-off-by: default avatarEugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: default avatarAmir Vadai <amirv@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2d4b6466
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -809,6 +809,15 @@ int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
	return -EPERM;
}

int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave,
		     struct mlx4_vhcr *vhcr,
		     struct mlx4_cmd_mailbox *inbox,
		     struct mlx4_cmd_mailbox *outbox,
		     struct mlx4_cmd_info *cmd)
{
	return -EPERM;
}

int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
		     struct mlx4_vhcr *vhcr,
		     struct mlx4_cmd_mailbox *inbox,
@@ -1251,6 +1260,15 @@ static struct mlx4_cmd_info cmd_info[] = {
		.verify = NULL,
		.wrapper = MLX4_CMD_UPDATE_QP_wrapper
	},
	{
		.opcode = MLX4_CMD_GET_OP_REQ,
		.has_inbox = false,
		.has_outbox = false,
		.out_is_imm = false,
		.encode_slave_id = false,
		.verify = NULL,
		.wrapper = MLX4_CMD_GET_OP_REQ_wrapper,
	},
	{
		.opcode = MLX4_CMD_CONF_SPECIAL_QP,
		.has_inbox = false,
+9 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ enum {
			       (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
			       (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)	    | \
			       (1ull << MLX4_EVENT_TYPE_CMD)		    | \
			       (1ull << MLX4_EVENT_TYPE_OP_REQUIRED)	    | \
			       (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL)       | \
			       (1ull << MLX4_EVENT_TYPE_FLR_EVENT)	    | \
			       (1ull << MLX4_EVENT_TYPE_FATAL_WARNING))
@@ -629,6 +630,14 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
			mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
			break;

		case MLX4_EVENT_TYPE_OP_REQUIRED:
			atomic_inc(&priv->opreq_count);
			/* FW commands can't be executed from interrupt context
			 * working in deferred task
			 */
			queue_work(mlx4_wq, &priv->opreq_task);
			break;

		case MLX4_EVENT_TYPE_COMM_CHANNEL:
			if (!mlx4_is_master(dev)) {
				mlx4_warn(dev, "Received comm channel event "
+104 −0
Original line number Diff line number Diff line
@@ -1705,3 +1705,107 @@ int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
}
EXPORT_SYMBOL_GPL(mlx4_wol_write);

enum {
	ADD_TO_MCG = 0x26,
};


void mlx4_opreq_action(struct work_struct *work)
{
	struct mlx4_priv *priv = container_of(work, struct mlx4_priv,
					      opreq_task);
	struct mlx4_dev *dev = &priv->dev;
	int num_tasks = atomic_read(&priv->opreq_count);
	struct mlx4_cmd_mailbox *mailbox;
	struct mlx4_mgm *mgm;
	u32 *outbox;
	u32 modifier;
	u16 token;
	u16 type_m;
	u16 type;
	int err;
	u32 num_qps;
	struct mlx4_qp qp;
	int i;
	u8 rem_mcg;
	u8 prot;

#define GET_OP_REQ_MODIFIER_OFFSET	0x08
#define GET_OP_REQ_TOKEN_OFFSET		0x14
#define GET_OP_REQ_TYPE_OFFSET		0x1a
#define GET_OP_REQ_DATA_OFFSET		0x20

	mailbox = mlx4_alloc_cmd_mailbox(dev);
	if (IS_ERR(mailbox)) {
		mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n");
		return;
	}
	outbox = mailbox->buf;

	while (num_tasks) {
		err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
				   MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
				   MLX4_CMD_NATIVE);
		if (err) {
			mlx4_err(dev, "Failed to retreive required operation: %d\n",
				 err);
			return;
		}
		MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
		MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
		MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET);
		type_m = type >> 12;
		type &= 0xfff;

		switch (type) {
		case ADD_TO_MCG:
			if (dev->caps.steering_mode ==
			    MLX4_STEERING_MODE_DEVICE_MANAGED) {
				mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n");
				err = EPERM;
				break;
			}
			mgm = (struct mlx4_mgm *)((u8 *)(outbox) +
						  GET_OP_REQ_DATA_OFFSET);
			num_qps = be32_to_cpu(mgm->members_count) &
				  MGM_QPN_MASK;
			rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1;
			prot = ((u8 *)(&mgm->members_count))[0] >> 6;

			for (i = 0; i < num_qps; i++) {
				qp.qpn = be32_to_cpu(mgm->qp[i]);
				if (rem_mcg)
					err = mlx4_multicast_detach(dev, &qp,
								    mgm->gid,
								    prot, 0);
				else
					err = mlx4_multicast_attach(dev, &qp,
								    mgm->gid,
								    mgm->gid[5]
								    , 0, prot,
								    NULL);
				if (err)
					break;
			}
			break;
		default:
			mlx4_warn(dev, "Bad type for required operation\n");
			err = EINVAL;
			break;
		}
		err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
			       1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
			       MLX4_CMD_NATIVE);
		if (err) {
			mlx4_err(dev, "Failed to acknowledge required request: %d\n",
				 err);
			goto out;
		}
		memset(outbox, 0, 0xffc);
		num_tasks = atomic_dec_return(&priv->opreq_count);
	}

out:
	mlx4_free_cmd_mailbox(dev, mailbox);
}
+1 −0
Original line number Diff line number Diff line
@@ -220,5 +220,6 @@ int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
int mlx4_NOP(struct mlx4_dev *dev);
int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg);
void mlx4_opreq_action(struct work_struct *work);

#endif /* MLX4_FW_H */
+19 −16
Original line number Diff line number Diff line
@@ -1692,11 +1692,19 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
		goto err_xrcd_table_free;
	}

	if (!mlx4_is_slave(dev)) {
		err = mlx4_init_mcg_table(dev);
		if (err) {
			mlx4_err(dev, "Failed to initialize multicast group table, aborting.\n");
			goto err_mr_table_free;
		}
	}

	err = mlx4_init_eq_table(dev);
	if (err) {
		mlx4_err(dev, "Failed to initialize "
			 "event queue table, aborting.\n");
		goto err_mr_table_free;
		goto err_mcg_table_free;
	}

	err = mlx4_cmd_use_events(dev);
@@ -1746,19 +1754,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
		goto err_srq_table_free;
	}

	if (!mlx4_is_slave(dev)) {
		err = mlx4_init_mcg_table(dev);
		if (err) {
			mlx4_err(dev, "Failed to initialize "
				 "multicast group table, aborting.\n");
			goto err_qp_table_free;
		}
	}

	err = mlx4_init_counters_table(dev);
	if (err && err != -ENOENT) {
		mlx4_err(dev, "Failed to initialize counters table, aborting.\n");
		goto err_mcg_table_free;
		goto err_qp_table_free;
	}

	if (!mlx4_is_slave(dev)) {
@@ -1803,9 +1802,6 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
err_counters_table_free:
	mlx4_cleanup_counters_table(dev);

err_mcg_table_free:
	mlx4_cleanup_mcg_table(dev);

err_qp_table_free:
	mlx4_cleanup_qp_table(dev);

@@ -1821,6 +1817,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
err_eq_table_free:
	mlx4_cleanup_eq_table(dev);

err_mcg_table_free:
	if (!mlx4_is_slave(dev))
		mlx4_cleanup_mcg_table(dev);

err_mr_table_free:
	mlx4_cleanup_mr_table(dev);

@@ -2197,6 +2197,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
			}
		}

		atomic_set(&priv->opreq_count, 0);
		INIT_WORK(&priv->opreq_task, mlx4_opreq_action);

		/*
		 * Now reset the HCA before we touch the PCI capabilities or
		 * attempt a firmware command, since a boot ROM may have left
@@ -2315,12 +2318,12 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
		mlx4_cleanup_port_info(&priv->port[port]);

	mlx4_cleanup_counters_table(dev);
	mlx4_cleanup_mcg_table(dev);
	mlx4_cleanup_qp_table(dev);
	mlx4_cleanup_srq_table(dev);
	mlx4_cleanup_cq_table(dev);
	mlx4_cmd_use_polling(dev);
	mlx4_cleanup_eq_table(dev);
	mlx4_cleanup_mcg_table(dev);
	mlx4_cleanup_mr_table(dev);
	mlx4_cleanup_xrcd_table(dev);
	mlx4_cleanup_pd_table(dev);
@@ -2403,12 +2406,12 @@ static void mlx4_remove_one(struct pci_dev *pdev)
						   RES_TR_FREE_SLAVES_ONLY);

		mlx4_cleanup_counters_table(dev);
		mlx4_cleanup_mcg_table(dev);
		mlx4_cleanup_qp_table(dev);
		mlx4_cleanup_srq_table(dev);
		mlx4_cleanup_cq_table(dev);
		mlx4_cmd_use_polling(dev);
		mlx4_cleanup_eq_table(dev);
		mlx4_cleanup_mcg_table(dev);
		mlx4_cleanup_mr_table(dev);
		mlx4_cleanup_xrcd_table(dev);
		mlx4_cleanup_pd_table(dev);
Loading