Commit 21cacb51 authored by Chengchang Tang's avatar Chengchang Tang Committed by shiyongbang
Browse files

RDMA/hns: Support write with notify

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



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

This patch adds support for the write with notify operation.
Including support for configuring cq to enable write with notify,
and qp to enable write with notify.

At the same time, a pair of APIs are added in the kernel side,
rdma_register_notify_addr()/rdma_unregister_notify_addr().

Users need to use this API to register the notify address.

Signed-off-by: default avatarChengchang Tang <tangchengchang@huawei.com>
parent aae9bba5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@
#define roce_get_field(origin, mask, shift)                                    \
	((le32_to_cpu(origin) & (mask)) >> (u32)(shift))

#define roce_get_field64(origin, mask, shift)                                    \
	((le64_to_cpu(origin) & (mask)) >> (u32)(shift))

#define roce_get_bit(origin, shift) \
	roce_get_field((origin), (1ul << (shift)), (shift))

+58 −2
Original line number Diff line number Diff line
@@ -332,6 +332,58 @@ static int set_poe_param(struct hns_roce_dev *hr_dev,
	return 0;
}

static bool is_notify_support(struct hns_roce_dev *hr_dev,
			      enum hns_roce_notify_mode notify_mode,
			      enum hns_roce_notify_device_en device_en)
{
	if (!is_write_notify_supported(hr_dev))
		return false;

	/* some configuration is not supported in HIP10 */
	if (hr_dev->pci_dev->revision != PCI_REVISION_ID_HIP10)
		return true;

	if (notify_mode == HNS_ROCE_NOTIFY_MODE_64B_ALIGN ||
	    device_en == HNS_ROCE_NOTIFY_DDR) {
		ibdev_err(&hr_dev->ib_dev, "Unsupported notify_mode.\n");
		return false;
	}

	return true;
}

static int set_write_notify_param(struct hns_roce_dev *hr_dev,
				  struct hns_roce_cq *hr_cq,
				  struct hns_roce_ib_create_cq *ucmd)
{
#define NOTIFY_MODE_MASK 0x3
	const struct {
		u8 mode;
		u8 mem_type;
	} notify_attr[] = {
		{HNS_ROCE_NOTIFY_MODE_64B_ALIGN, HNS_ROCE_NOTIFY_DEV},
		{HNS_ROCE_NOTIFY_MODE_4B_ALIGN, HNS_ROCE_NOTIFY_DEV},
		{HNS_ROCE_NOTIFY_MODE_64B_ALIGN, HNS_ROCE_NOTIFY_DDR},
		{HNS_ROCE_NOTIFY_MODE_4B_ALIGN, HNS_ROCE_NOTIFY_DDR},
	};
	u8 attr = ucmd->notify_mode & NOTIFY_MODE_MASK;

	if (!(ucmd->create_flags & HNS_ROCE_CREATE_CQ_FLAGS_WRITE_WITH_NOTIFY))
		return 0;

	if (!is_notify_support(hr_dev, notify_attr[attr].mode,
			       notify_attr[attr].mem_type))
		return -EOPNOTSUPP;

	hr_cq->flags |= HNS_ROCE_CQ_FLAG_NOTIFY_EN;
	hr_cq->write_notify.notify_addr =
		hr_dev->notify_tbl[ucmd->notify_idx].base_addr;
	hr_cq->write_notify.notify_mode = notify_attr[attr].mode;
	hr_cq->write_notify.notify_device_en = notify_attr[attr].mem_type;

	return 0;
}

static int set_cq_param(struct hns_roce_cq *hr_cq, u32 cq_entries, int vector,
			 struct hns_roce_ib_create_cq *ucmd)
{
@@ -348,14 +400,18 @@ static int set_cq_param(struct hns_roce_cq *hr_cq, u32 cq_entries, int vector,
	INIT_LIST_HEAD(&hr_cq->sq_list);
	INIT_LIST_HEAD(&hr_cq->rq_list);

	if (!(ucmd->create_flags))
	if (!ucmd->create_flags)
		return 0;

	if ((ucmd->create_flags & HNS_ROCE_CREATE_CQ_FLAGS_POE_MODE) &&
	    (ucmd->create_flags & HNS_ROCE_CREATE_CQ_FLAGS_WRITE_WITH_NOTIFY))
		return -EINVAL;

	ret = set_poe_param(hr_dev, hr_cq, ucmd);
	if (ret)
		return ret;

	return 0;
	return set_write_notify_param(hr_dev, hr_cq, ucmd);
}

static int set_cqe_size(struct hns_roce_cq *hr_cq, struct ib_udata *udata,
+30 −0
Original line number Diff line number Diff line
@@ -37,9 +37,11 @@
#include <rdma/ib_verbs.h>
#include <rdma/hns-abi.h>
#include "hns_roce_bond.h"
#include "hns_roce_ext.h"

#define PCI_REVISION_ID_HIP08			0x21
#define PCI_REVISION_ID_HIP09			0x30
#define PCI_REVISION_ID_HIP10			0x32

#define HNS_ROCE_MAX_MSG_LEN			0x80000000

@@ -104,6 +106,8 @@
#define CQ_BANKID_SHIFT 2
#define CQ_BANKID_MASK GENMASK(1, 0)

#define MAX_NOTIFY_MEM_SIZE BIT(24)

#define HNS_ROCE_MEM_BAR 2

enum {
@@ -162,6 +166,7 @@ enum {
	HNS_ROCE_CAP_FLAG_SVE_DIRECT_WQE	= BIT(13),
	HNS_ROCE_CAP_FLAG_SDI_MODE		= BIT(14),
	HNS_ROCE_CAP_FLAG_DCA_MODE		= BIT(15),
	HNS_ROCE_CAP_FLAG_WRITE_NOTIFY          = BIT(16),
	HNS_ROCE_CAP_FLAG_STASH			= BIT(17),
	HNS_ROCE_CAP_FLAG_CQE_INLINE		= BIT(19),
	HNS_ROCE_CAP_FLAG_BOND			= BIT(21),
@@ -488,6 +493,22 @@ struct hns_roce_db {
	unsigned long	order;
};

enum hns_roce_notify_mode {
	HNS_ROCE_NOTIFY_MODE_64B_ALIGN = 0,
	HNS_ROCE_NOTIFY_MODE_4B_ALIGN = 1,
};

enum hns_roce_notify_device_en {
	HNS_ROCE_NOTIFY_DEV = 0,
	HNS_ROCE_NOTIFY_DDR = 1,
};

struct hns_roce_notify_conf {
	u64 notify_addr; /* should be aligned to 4k */
	u8 notify_mode; /* use enum hns_roce_notify_mode */
	u8 notify_device_en; /* use enum hns_roce_notify_device_en */
};

struct hns_roce_cq {
	struct ib_cq			ib_cq;
	struct hns_roce_mtr		mtr;
@@ -509,6 +530,7 @@ struct hns_roce_cq {
	int				is_armed; /* cq is armed */
	struct list_head		node; /* all armed cqs are on a list */
	u8				poe_channel;
	struct hns_roce_notify_conf	write_notify;
};

struct hns_roce_idx_que {
@@ -1154,6 +1176,9 @@ struct hns_roce_dev {
	struct hns_roce_port port_data[HNS_ROCE_MAX_PORTS];
	atomic64_t *dfx_cnt;
	struct hns_roce_poe_ctx poe_ctx; /* poe ch array */

	struct rdma_notify_mem *notify_tbl;
	size_t notify_num;
};

static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
@@ -1316,6 +1341,11 @@ static inline bool poe_is_supported(struct hns_roce_dev *hr_dev)
	return !!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_POE);
}

static inline bool is_write_notify_supported(struct hns_roce_dev *dev)
{
	return !!(dev->caps.flags & HNS_ROCE_CAP_FLAG_WRITE_NOTIFY);
}

void hns_roce_init_uar_table(struct hns_roce_dev *dev);
int hns_roce_uar_alloc(struct hns_roce_dev *dev, struct hns_roce_uar *uar);

+51 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ bool rdma_support_stars(struct ib_device *ib_dev)
	if (!is_hns_roce(ib_dev) || is_hns_roce_vf(hr_dev))
		return false;

	if (poe_is_supported(hr_dev))
	if (poe_is_supported(hr_dev) && is_write_notify_supported(hr_dev))
		return true;

	return false;
@@ -91,3 +91,53 @@ int rdma_query_hw_id(struct ib_device *ib_dev, u32 *chip_id,
}
EXPORT_SYMBOL(rdma_query_hw_id);

int rdma_register_notify_addr(struct ib_device *ib_dev,
			      size_t num, struct rdma_notify_mem *notify_mem)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
	size_t i;

	if (!is_hns_roce(ib_dev) || !is_write_notify_supported(hr_dev))
		return -EOPNOTSUPP;

	if (hr_dev->notify_tbl)
		return -EBUSY;

	if (!num || !notify_mem)
		return -EINVAL;

	for (i = 0; i < num; i++) {
		if (!notify_mem[i].size ||
		    notify_mem[i].size > MAX_NOTIFY_MEM_SIZE)
			return -EINVAL;
		if (!notify_mem[i].base_addr)
			return -EINVAL;
	}

	hr_dev->notify_tbl = kvmalloc_array(num, sizeof(*notify_mem),
					    GFP_KERNEL);
	if (!hr_dev->notify_tbl)
		return -ENOMEM;

	hr_dev->notify_num = num;
	memcpy(hr_dev->notify_tbl, notify_mem, sizeof(*notify_mem) * num);

	return 0;
}
EXPORT_SYMBOL(rdma_register_notify_addr);

int rdma_unregister_notify_addr(struct ib_device *ib_dev)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);

	if (!is_hns_roce(ib_dev) || !is_write_notify_supported(hr_dev))
		return -EOPNOTSUPP;

	if (hr_dev->notify_tbl)
		kvfree(hr_dev->notify_tbl);

	hr_dev->notify_tbl = NULL;

	return 0;
}
EXPORT_SYMBOL(rdma_unregister_notify_addr);
+23 −0
Original line number Diff line number Diff line
@@ -40,4 +40,27 @@ u64 rdma_query_qp_db(struct ib_device *ib_dev, int qp_index);
 */
int rdma_query_hw_id(struct ib_device *ib_dev, u32 *chip_id,
		     u32 *die_id, u32 *func_id);
/**
 * struct rdma_notify_mem
 * @base_addr - The memory region base addr for write with notify operation.
 * @size - size of the notify memory region
 */
struct rdma_notify_mem {
	u64 base_addr;
	u32 size;
};

/**
 * rdma_register_notify_addr - Register an memory region which will be used by
 * write with notify operation.
 * @num - How many elements in array
 * @notify_mem - Notify memory array.
 *
 * If notify_mem has already been registered, re-registration
 * will not be allowed.
 */
int rdma_register_notify_addr(struct ib_device *ib_dev,
			      size_t num, struct rdma_notify_mem *notify_mem);
int rdma_unregister_notify_addr(struct ib_device *ib_dev);

#endif
Loading