Commit 178ed4fc authored by Weibo Zhao's avatar Weibo Zhao Committed by JiangShui
Browse files

hns3 udma: support POE mode.

driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I85R2F


CVE: NA

-----------------------------------------------------

This patch support POE mode of hns3-udma. POE mode is
a way that jfce was report to STARS directly.
In POE mode, doorbell address was passed to STARS so
that STARS can knock doorbell whenever it wants.

Signed-off-by: default avatarWeibo Zhao <zhaoweibo3@huawei.com>
parent b3531280
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -36,10 +36,11 @@ enum {
};

enum udma_jfc_init_attr_mask {
	UDMA_JFC_NOTIFY_CREATE_FLAGS = 1 << 0,
	UDMA_JFC_NOTIFY_OR_POE_CREATE_FLAGS = 1 << 0,
};

enum udma_jfc_create_flags {
	UDMA_JFC_CREATE_ENABLE_POE_MODE = 1 << 0,
	UDMA_JFC_CREATE_ENABLE_NOTIFY = 1 << 1,
};

@@ -67,6 +68,7 @@ struct udma_create_jfr_resp {
struct udma_jfc_attr_ex {
	uint64_t	jfc_ex_mask; /* Use enum udma_jfc_init_attr_mask */
	uint64_t	create_flags; /* Use enum udma_jfc_create_flags */
	uint8_t		poe_channel; /* poe channel to use */
	uint64_t	notify_addr;
	uint8_t		notify_mode; /* Use enum udma_jfc_notify_mode */
};
@@ -146,6 +148,8 @@ struct udma_create_ctx_resp {
	uint32_t max_jfr_sge;
	uint32_t max_jfs_wr;
	uint32_t max_jfs_sge;
	uint32_t poe_ch_num;
	uint64_t db_addr;
};

struct flush_cqe_param {
@@ -153,8 +157,16 @@ struct flush_cqe_param {
	uint32_t sq_producer_idx;
};

struct udma_poe_info {
	uint8_t		en;
	uint8_t		poe_channel;
	uint64_t	poe_addr;
};

enum udma_user_ctl_handlers {
	UDMA_USER_CTL_FLUSH_CQE,
	UDMA_CONFIG_POE_CHANNEL,
	UDMA_QUERY_POE_CHANNEL,
	UDMA_OPCODE_NUM,
};

+15 −0
Original line number Diff line number Diff line
@@ -229,6 +229,8 @@ enum udma_opcode_type {
	UDMA_QUERY_OOR_CAPS				= 0xA002,
	UDMA_OPC_DEID_TBL_ADD				= 0xA110,
	UDMA_OPC_CFG_GMV_TBL				= 0xA140,
	UDMA_OPC_CFG_POE_ADDR				= 0x801B,
	UDMA_OPC_CFG_POE_ATTR				= 0x801C,
	UDMA_OPC_QUERY_PORT_INFO			= 0x7104,
};

@@ -482,6 +484,19 @@ union udma_eid {
	} bit32_data;
};

struct udma_poe_cfg_addr_cmq {
	uint32_t channel_id;
	uint32_t poe_addr_l;
	uint32_t poe_addr_h;
	uint32_t rsv[3];
};

struct udma_poe_cfg_attr_cmq {
	uint32_t channel_id;
	uint32_t rsv_en_outstd;
	uint32_t rsv[4];
};

struct udma_port_info_cmq {
	uint32_t speed;
	uint8_t query_type;
+23 −2
Original line number Diff line number Diff line
@@ -56,6 +56,17 @@ static int check_jfc_cfg(struct udma_dev *udma_dev, const struct ubcore_jfc_cfg
	return 0;
}

static int check_poe_attr(struct udma_dev *udma_dev,
			  struct udma_jfc_attr_ex *jfc_attr_ex)
{
	if (!(udma_dev->caps.flags & UDMA_CAP_FLAG_POE)) {
		dev_err(udma_dev->dev, "Unsupport POE JFC.\n");
		return -EINVAL;
	}

	return 0;
}

static int check_notify_attr(struct udma_dev *udma_dev,
			     struct udma_jfc_attr_ex *jfc_attr_ex)
{
@@ -94,6 +105,9 @@ static int check_jfc_attr_ex(struct udma_dev *udma_dev,
	int ret;

	switch (jfc_attr_ex->create_flags) {
	case UDMA_JFC_CREATE_ENABLE_POE_MODE:
		ret = check_poe_attr(udma_dev, jfc_attr_ex);
		break;
	case UDMA_JFC_CREATE_ENABLE_NOTIFY:
		ret = check_notify_attr(udma_dev, jfc_attr_ex);
		break;
@@ -132,7 +146,7 @@ static int check_create_jfc(struct udma_dev *udma_dev,
	}

	if (ucmd->jfc_attr_ex.jfc_ex_mask &
	    UDMA_JFC_NOTIFY_CREATE_FLAGS) {
	    UDMA_JFC_NOTIFY_OR_POE_CREATE_FLAGS) {
		ret = check_jfc_attr_ex(udma_dev, &ucmd->jfc_attr_ex);
		if (ret) {
			dev_err(udma_dev->dev,
@@ -155,7 +169,7 @@ static void init_jfc(struct udma_jfc *udma_jfc, struct udma_create_jfc_ucmd *ucm
	spin_lock_init(&udma_jfc->lock);
	INIT_LIST_HEAD(&udma_jfc->sq_list);
	INIT_LIST_HEAD(&udma_jfc->rq_list);
	if (ucmd->jfc_attr_ex.jfc_ex_mask & UDMA_JFC_NOTIFY_CREATE_FLAGS)
	if (ucmd->jfc_attr_ex.jfc_ex_mask & UDMA_JFC_NOTIFY_OR_POE_CREATE_FLAGS)
		udma_jfc->jfc_attr_ex = ucmd->jfc_attr_ex;
}

@@ -315,6 +329,13 @@ static void udma_write_jfc_cqc(struct udma_dev *udma_dev, struct udma_jfc *udma_
			       upper_32_bits(udma_jfc->db.dma));
	}

	if (udma_jfc->jfc_attr_ex.create_flags ==
	    UDMA_JFC_CREATE_ENABLE_POE_MODE) {
		udma_reg_enable(jfc_context, CQC_POE_EN);
		udma_reg_write(jfc_context, CQC_POE_NUM,
			       udma_jfc->jfc_attr_ex.poe_channel);
	}

	if (udma_jfc->jfc_attr_ex.create_flags == UDMA_JFC_CREATE_ENABLE_NOTIFY)
		set_write_notify_param(udma_dev, udma_jfc, jfc_context);
}
+208 −0
Original line number Diff line number Diff line
@@ -85,6 +85,9 @@ static int udma_init_ctx_resp(struct udma_dev *dev, struct ubcore_udrv_priv *udr
	resp.max_jfr_sge = dev->caps.max_srq_sges;
	resp.max_jfs_wr = dev->caps.max_wqes;
	resp.max_jfs_sge = dev->caps.max_sq_sg;
	resp.poe_ch_num = dev->caps.poe_ch_num;
	resp.db_addr = pci_resource_start(dev->pci_dev, UDMA_DEV_START_OFFSET) +
		       UDMA_DB_ADDR_OFFSET;

	ret = copy_to_user((void *)udrv_data->out_addr, &resp,
			   min(udrv_data->out_len, (uint32_t)sizeof(resp)));
@@ -356,6 +359,202 @@ int udma_user_ctl_flush_cqe(struct ubcore_ucontext *uctx, struct ubcore_user_ctl
	return ret;
}

static int config_poe_addr(struct udma_dev *udma_device, uint8_t id,
			   uint64_t addr)
{
	struct udma_poe_cfg_addr_cmq *cmd;
	struct udma_cmq_desc desc;
	int ret;

	udma_cmq_setup_basic_desc(&desc, UDMA_OPC_CFG_POE_ADDR, false);
	cmd = (struct udma_poe_cfg_addr_cmq *)desc.data;
	cmd->channel_id = cpu_to_le32(id);
	cmd->poe_addr_l = cpu_to_le32(lower_32_bits(addr));
	cmd->poe_addr_h = cpu_to_le32(upper_32_bits(addr));

	ret = udma_cmq_send(udma_device, &desc, 1);
	if (ret)
		dev_err(udma_device->dev,
			"configure poe channel %u addr failed, ret = %d.\n",
			id, ret);
	return ret;
}

static int config_poe_attr(struct udma_dev *udma_device, uint8_t id, bool en)
{
	struct udma_poe_cfg_attr_cmq *cmd;
	struct udma_cmq_desc desc;
	int ret;

	udma_cmq_setup_basic_desc(&desc, UDMA_OPC_CFG_POE_ATTR, false);
	cmd = (struct udma_poe_cfg_attr_cmq *)desc.data;
	cmd->channel_id = cpu_to_le32(id);
	cmd->rsv_en_outstd = en ? 1 : 0;

	ret = udma_cmq_send(udma_device, &desc, 1);
	if (ret)
		dev_err(udma_device->dev,
			"configure poe channel %u attr failed, ret = %d.\n",
			id, ret);
	return ret;
}

static int check_poe_channel(struct udma_dev *udma_device, uint8_t poe_ch)
{
	if (poe_ch >= udma_device->caps.poe_ch_num) {
		dev_err(udma_device->dev, "invalid POE channel %u.\n", poe_ch);
		return -EINVAL;
	}

	return 0;
}

int udma_user_ctl_config_poe(struct ubcore_ucontext *uctx, struct ubcore_user_ctl_in *in,
			     struct ubcore_user_ctl_out *out,
			     struct ubcore_udrv_priv *udrv_data)
{
	struct udma_poe_info poe_info;
	struct udma_dev *udma_device;
	int ret;

	udma_device = to_udma_dev(uctx->ub_dev);
	ret = (int)copy_from_user(&poe_info,
				  (void *)in->addr,
				  sizeof(struct udma_poe_info));
	if (ret) {
		dev_err(udma_device->dev, "cp from user failed in config poe, ret:%d.\n",
			ret);
		return -EFAULT;
	}

	ret = check_poe_channel(udma_device, poe_info.poe_channel);
	if (ret) {
		dev_err(udma_device->dev, "check channel failed in config poe, ret:%d.\n",
			ret);
		return ret;
	}

	ret = config_poe_attr(udma_device, poe_info.poe_channel,
			      !!poe_info.poe_addr);
	if (ret) {
		dev_err(udma_device->dev, "config attr failed in config poe, ret:%d.\n",
			ret);
		config_poe_addr(udma_device, poe_info.poe_channel, 0);
		return ret;
	}

	ret = config_poe_addr(udma_device, poe_info.poe_channel,
			      poe_info.poe_addr);
	if (ret)
		dev_err(udma_device->dev, "config addr failed in config poe, ret:%d.\n",
		ret);

	return ret;
}

static int query_poe_addr(struct udma_dev *udma_device, uint8_t id,
			  uint64_t *addr)
{
#define POE_ADDR_H_SHIFT 32
	struct udma_poe_cfg_addr_cmq *resp;
	struct udma_cmq_desc desc;
	int ret;

	udma_cmq_setup_basic_desc(&desc, UDMA_OPC_CFG_POE_ADDR, true);
	resp = (struct udma_poe_cfg_addr_cmq *)desc.data;
	resp->channel_id = cpu_to_le32(id);

	ret = udma_cmq_send(udma_device, &desc, 1);
	if (ret) {
		dev_err(udma_device->dev,
			"Query poe channel %u addr failed, ret = %d.\n",
			id, ret);
		return ret;
	}

	*addr = resp->poe_addr_l | ((uint64_t)resp->poe_addr_h <<
				    POE_ADDR_H_SHIFT);

	return ret;
}

static int query_poe_attr(struct udma_dev *udma_device, uint8_t id, bool *en)
{
	struct udma_poe_cfg_attr_cmq *resp;
	struct udma_cmq_desc desc;
	int ret;

	udma_cmq_setup_basic_desc(&desc, UDMA_OPC_CFG_POE_ATTR, true);
	resp = (struct udma_poe_cfg_attr_cmq *)desc.data;
	resp->channel_id = cpu_to_le32(id);

	ret = udma_cmq_send(udma_device, &desc, 1);
	if (ret) {
		dev_err(udma_device->dev,
			"Query poe channel %u attr failed, ret = %d.\n",
			id, ret);
		return ret;
	}

	*en = !!resp->rsv_en_outstd;

	return ret;
}

int udma_user_ctl_query_poe(struct ubcore_ucontext *uctx, struct ubcore_user_ctl_in *in,
			    struct ubcore_user_ctl_out *out,
			    struct ubcore_udrv_priv *udrv_data)
{
	struct udma_poe_info poe_info_out;
	struct udma_poe_info poe_info_in;
	struct udma_dev *udma_device;
	uint64_t poe_addr;
	bool poe_en;
	int ret;

	udma_device = to_udma_dev(uctx->ub_dev);
	ret = (int)copy_from_user(&poe_info_in, (void *)in->addr,
				  sizeof(struct udma_poe_info));
	if (ret) {
		dev_err(udma_device->dev, "cp from user failed in query poe, ret:%d.\n",
			ret);
		return -EFAULT;
	}

	ret = check_poe_channel(udma_device, poe_info_in.poe_channel);
	if (ret) {
		dev_err(udma_device->dev, "check channel failed in query poe, ret:%d.\n",
			ret);
		return ret;
	}

	ret = query_poe_attr(udma_device, poe_info_in.poe_channel, &poe_en);
	if (ret) {
		dev_err(udma_device->dev, "query attr failed in query poe, ret:%d.\n",
			ret);
		return ret;
	}

	ret = query_poe_addr(udma_device, poe_info_in.poe_channel, &poe_addr);
	if (ret) {
		dev_err(udma_device->dev, "query addr failed in query poe, ret:%d.\n",
			ret);
		return ret;
	}

	poe_info_out.en = poe_en ? 1 : 0;
	poe_info_out.poe_addr = poe_addr;
	ret = (int)copy_to_user((void *)out->addr, &poe_info_out,
			   min(out->len,
			       (uint32_t)sizeof(struct udma_poe_info)));
	if (ret != 0) {
		dev_err(udma_device->dev, "cp to user failed in query poe, ret:%d.\n",
			ret);
		return -EFAULT;
	}
	return ret;
}

typedef int (*udma_user_ctl_opcode)(struct ubcore_ucontext *uctx,
				    struct ubcore_user_ctl_in *in,
				    struct ubcore_user_ctl_out *out,
@@ -363,6 +562,8 @@ typedef int (*udma_user_ctl_opcode)(struct ubcore_ucontext *uctx,

static udma_user_ctl_opcode g_udma_user_ctl_opcodes[] = {
	[UDMA_USER_CTL_FLUSH_CQE] = udma_user_ctl_flush_cqe,
	[UDMA_CONFIG_POE_CHANNEL] = udma_user_ctl_config_poe,
	[UDMA_QUERY_POE_CHANNEL] = udma_user_ctl_query_poe,
};

int udma_user_ctl(struct ubcore_user_ctl *k_user_ctl)
@@ -844,6 +1045,12 @@ static void udma_cleanup_hem(struct udma_dev *udma_dev)
	udma_cleanup_common_hem(udma_dev);
}

void udma_set_poe_ch_num(struct udma_dev *dev)
{
#define UDMA_POE_CH_NUM 4

	dev->caps.poe_ch_num = UDMA_POE_CH_NUM;
}

static void udma_set_devname(struct udma_dev *udma_dev,
			     struct ubcore_device *ub_dev)
@@ -938,6 +1145,7 @@ int udma_hnae_client_init(struct udma_dev *udma_dev)
		goto error_failed_engine_init;
	}

	udma_set_poe_ch_num(udma_dev);
	ret = udma_register_device(udma_dev);
	if (ret) {
		dev_err(dev, "udma register device failed!\n");