Commit 96df0157 authored by Chengchang Tang's avatar Chengchang Tang Committed by shiyongbang
Browse files

RDMA/hns: Support configuring POE channels and creating POE CQs

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



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

This patch provides a pair of APIs rdma_register_poe_channel()/
rdma_unregister_poe_channel() to support register/unregister POE
channels which could be used for CQs.

At the same time, this patch also supports user creation of CQ bound
to a POE channel.

BTW, This patch also add a debugfs for POE to help with problem
diagnosis.

Signed-off-by: default avatarChengchang Tang <tangchengchang@huawei.com>
parent 1470b68f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@ ccflags-y += -I $(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3_common
hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_pd.o \
	hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
	hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o \
	hns_roce_bond.o hns_roce_dca.o hns_roce_debugfs.o hns_roce_sysfs.o
	hns_roce_bond.o hns_roce_dca.o hns_roce_debugfs.o hns_roce_sysfs.o \
	hns_roce_poe.o hns_roce_ext.o

ifdef CONFIG_INFINIBAND_HNS_HIP08
hns-roce-hw-v2-objs := hns_roce_hw_v2.o $(hns-roce-objs)
+56 −2
Original line number Diff line number Diff line
@@ -311,10 +311,32 @@ static int get_cq_ucmd(struct hns_roce_cq *hr_cq, struct ib_udata *udata,
	return 0;
}

static void set_cq_param(struct hns_roce_cq *hr_cq, u32 cq_entries, int vector,
static int set_poe_param(struct hns_roce_dev *hr_dev,
			 struct hns_roce_cq *hr_cq,
			 struct hns_roce_ib_create_cq *ucmd)
{
	if (!(ucmd->create_flags & HNS_ROCE_CREATE_CQ_FLAGS_POE_MODE))
		return 0;

	if (!poe_is_supported(hr_dev))
		return -EOPNOTSUPP;

	if (ucmd->poe_channel >= hr_dev->poe_ctx.poe_num)
		return -EINVAL;

	if (!hr_dev->poe_ctx.poe_ch[ucmd->poe_channel].en)
		return -EFAULT;

	hr_cq->flags |= HNS_ROCE_CQ_FLAG_POE_EN;
	hr_cq->poe_channel = ucmd->poe_channel;
	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)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(hr_cq->ib_cq.device);
	int ret;

	cq_entries = max(cq_entries, hr_dev->caps.min_cqes);
	cq_entries = roundup_pow_of_two(cq_entries);
@@ -325,6 +347,15 @@ static void set_cq_param(struct hns_roce_cq *hr_cq, u32 cq_entries, int vector,
	spin_lock_init(&hr_cq->lock);
	INIT_LIST_HEAD(&hr_cq->sq_list);
	INIT_LIST_HEAD(&hr_cq->rq_list);

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

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

	return 0;
}

static int set_cqe_size(struct hns_roce_cq *hr_cq, struct ib_udata *udata,
@@ -353,6 +384,22 @@ static int set_cqe_size(struct hns_roce_cq *hr_cq, struct ib_udata *udata,
	return 0;
}

static void poe_ch_ref_cnt_inc(struct hns_roce_dev *hr_dev,
			       struct hns_roce_cq *hr_cq)
{
	struct hns_roce_poe_ch *poe_ch =
		&hr_dev->poe_ctx.poe_ch[hr_cq->poe_channel];
	refcount_inc(&poe_ch->ref_cnt);
}

static void poe_ch_ref_cnt_dec(struct hns_roce_dev *hr_dev,
			       struct hns_roce_cq *hr_cq)
{
	struct hns_roce_poe_ch *poe_ch =
		&hr_dev->poe_ctx.poe_ch[hr_cq->poe_channel];
	refcount_dec(&poe_ch->ref_cnt);
}

int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
		       struct ib_udata *udata)
{
@@ -379,7 +426,9 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,

	}

	set_cq_param(hr_cq, attr->cqe, attr->comp_vector, &ucmd);
	ret = set_cq_param(hr_cq, attr->cqe, attr->comp_vector, &ucmd);
	if (ret)
		goto err_out;

	ret = set_cqe_size(hr_cq, udata, &ucmd);
	if (ret)
@@ -412,6 +461,9 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,

	if (udata) {
		resp.cqn = hr_cq->cqn;
		resp.cap_flags = hr_cq->flags;
		if (hr_cq->flags & HNS_ROCE_CQ_FLAG_POE_EN)
			poe_ch_ref_cnt_inc(hr_dev, hr_cq);
		ret = ib_copy_to_udata(udata, &resp,
				       min(udata->outlen, sizeof(resp)));
		if (ret)
@@ -444,6 +496,8 @@ int hns_roce_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
	struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);

	if (hr_cq->flags & HNS_ROCE_CQ_FLAG_POE_EN)
		poe_ch_ref_cnt_dec(hr_dev, hr_cq);
	free_cqc(hr_dev, hr_cq);
	free_cqn(hr_dev, hr_cq->cqn);
	free_cq_db(hr_dev, hr_cq, udata);
+111 −0
Original line number Diff line number Diff line
@@ -74,10 +74,22 @@ struct hns_dca_debugfs {
	struct hns_dca_ctx_debugfs kctx; /* kDCA context */
};

struct hns_poe_ch_debugfs {
	struct dentry *root; /* dev debugfs entry */
	struct hns_debugfs_seqfile en; /* enable stats fir this ch */
	struct hns_debugfs_seqfile addr; /* addr of this ch */
	struct hns_debugfs_seqfile ref_cnt; /* ref_cnt for this ch */
};

struct hns_poe_debugfs {
	struct dentry *root; /* dev debugfs entry */
};

/* Debugfs for device */
struct hns_roce_dev_debugfs {
	struct dentry *root;
	struct hns_dca_debugfs *dca_root;
	struct hns_poe_debugfs *poe_root;
};

struct dca_mem_stats {
@@ -497,6 +509,97 @@ static void destroy_dca_debugfs(struct hns_dca_debugfs *dca_dbgfs)
	kfree(dca_dbgfs);
}

static int poe_debugfs_en_show(struct seq_file *file, void *offset)
{
	struct hns_roce_poe_ch *poe_ch = file->private;

	seq_printf(file, "%-10s\n", poe_ch->en ? "enable" : "disable");
	return 0;
}

static int poe_debugfs_addr_show(struct seq_file *file, void *offset)
{
#define POE_ADDR_OFFSET_MASK GENMASK(31, 0)
	struct hns_roce_poe_ch *poe_ch = file->private;

	seq_printf(file, "0x%llx\n", poe_ch->addr & POE_ADDR_OFFSET_MASK);
	return 0;
}

static int poe_debugfs_ref_cnt_show(struct seq_file *file, void *offset)
{
	struct hns_roce_poe_ch *poe_ch = file->private;

	seq_printf(file, "0x%-10u\n", refcount_read(&poe_ch->ref_cnt));
	return 0;
}

static void init_poe_ch_debugfs(struct hns_roce_dev *hr_dev, uint8_t index,
				struct dentry *parent)
{
#define POE_CH_NAME_LEN 10
	struct hns_roce_poe_ch *poe_ch = &hr_dev->poe_ctx.poe_ch[index];
	struct hns_poe_ch_debugfs *dbgfs;
	char name[POE_CH_NAME_LEN];

	dbgfs = kvzalloc(sizeof(*dbgfs), GFP_KERNEL);
	if (!dbgfs)
		return;

	snprintf(name, sizeof(name), "poe_%u", index);
	dbgfs->root = debugfs_create_dir(name, parent);

	init_debugfs_seqfile(&dbgfs->en, "en", dbgfs->root,
			     poe_debugfs_en_show, poe_ch);
	init_debugfs_seqfile(&dbgfs->addr, "addr", dbgfs->root,
			     poe_debugfs_addr_show, poe_ch);
	init_debugfs_seqfile(&dbgfs->ref_cnt, "ref_cnt", dbgfs->root,
			     poe_debugfs_ref_cnt_show, poe_ch);
	poe_ch->poe_ch_debugfs = dbgfs;
}

static void cleanup_poe_ch_debugfs(struct hns_roce_dev *hr_dev, uint8_t index)
{
	struct hns_roce_poe_ch *poe_ch = &hr_dev->poe_ctx.poe_ch[index];
	struct hns_poe_ch_debugfs *dbgfs = poe_ch->poe_ch_debugfs;

	cleanup_debugfs_seqfile(&dbgfs->en);
	cleanup_debugfs_seqfile(&dbgfs->addr);
	cleanup_debugfs_seqfile(&dbgfs->ref_cnt);
	debugfs_remove_recursive(dbgfs->root);
	kvfree(dbgfs);
}

static struct hns_poe_debugfs *
create_poe_debugfs(struct hns_roce_dev *hr_dev, struct dentry *parent)
{
	struct hns_poe_debugfs *dbgfs;
	int i;

	dbgfs = kvzalloc(sizeof(*dbgfs), GFP_KERNEL);
	if (!dbgfs)
		return NULL;

	dbgfs->root = debugfs_create_dir("poe", parent);

	for (i = 0; i < hr_dev->poe_ctx.poe_num; i++)
		init_poe_ch_debugfs(hr_dev, i, dbgfs->root);

	return dbgfs;
}

static void destroy_poe_debugfs(struct hns_roce_dev *hr_dev,
				struct hns_poe_debugfs *poe_dbgfs)
{
	int i;

	for (i = 0; i < hr_dev->poe_ctx.poe_num; i++)
		cleanup_poe_ch_debugfs(hr_dev, i);

	debugfs_remove_recursive(poe_dbgfs->root);
	kvfree(poe_dbgfs);
}

/* debugfs for ucontext */
void hns_roce_register_uctx_debugfs(struct hns_roce_dev *hr_dev,
				    struct hns_roce_ucontext *uctx)
@@ -553,6 +656,9 @@ void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev)
	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_DCA_MODE)
		dbgfs->dca_root = create_dca_debugfs(hr_dev, dbgfs->root);

	if (poe_is_supported(hr_dev))
		dbgfs->poe_root = create_poe_debugfs(hr_dev, dbgfs->root);

	hr_dev->dbgfs = dbgfs;
}

@@ -572,6 +678,11 @@ void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev)
		dbgfs->dca_root = NULL;
	}

	if (dbgfs->poe_root) {
		destroy_poe_debugfs(hr_dev, dbgfs->poe_root);
		dbgfs->poe_root = NULL;
	}

	debugfs_remove_recursive(dbgfs->root);
	hr_dev->dbgfs = NULL;
	kfree(dbgfs);
+27 −0
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ enum {
	HNS_ROCE_CAP_FLAG_CQE_INLINE		= BIT(19),
	HNS_ROCE_CAP_FLAG_BOND			= BIT(21),
	HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB		= BIT(22),
	HNS_ROCE_CAP_FLAG_POE                   = BIT(27),
};

#define HNS_ROCE_DB_TYPE_COUNT			2
@@ -221,6 +222,18 @@ struct hns_user_mmap_entry {
	u64 address;
};

struct hns_roce_poe_ch {
	uint8_t en;
	refcount_t ref_cnt;
	uint64_t addr;
	void *poe_ch_debugfs;
};

struct hns_roce_poe_ctx {
	uint8_t poe_num;
	struct hns_roce_poe_ch *poe_ch;
};

struct hns_roce_dca_ctx {
	struct list_head pool; /* all DCA mems link to @pool */
	spinlock_t pool_lock; /* protect @pool */
@@ -493,6 +506,7 @@ struct hns_roce_cq {
	struct list_head		rq_list; /* all qps on this recv cq */
	int				is_armed; /* cq is armed */
	struct list_head		node; /* all armed cqs are on a list */
	u8				poe_channel;
};

struct hns_roce_idx_que {
@@ -788,6 +802,8 @@ enum congest_type {
	HNS_ROCE_CONGEST_TYPE_DIP = 1 << HNS_ROCE_SCC_ALGO_DIP,
};

#define HNS_ROCE_POE_CH_NUM 4

struct hns_roce_caps {
	u64		fw_ver;
	u8		num_ports;
@@ -919,6 +935,7 @@ struct hns_roce_caps {
	u16		default_ceq_arm_st;
	u8		congest_type;
	u8		default_congest_type;
	u8              poe_ch_num;
};

enum hns_roce_device_state {
@@ -1034,6 +1051,7 @@ struct hns_roce_hw {
				enum hns_roce_scc_algo algo);
	int (*query_scc_param)(struct hns_roce_dev *hr_dev, u8 port_num,
			       enum hns_roce_scc_algo alog);
	int (*cfg_poe_ch)(struct hns_roce_dev *hr_dev, u32 index, u64 poe_addr);
};

#define HNS_ROCE_SCC_PARAM_SIZE 4
@@ -1133,6 +1151,7 @@ struct hns_roce_dev {
	struct notifier_block bond_nb;
	struct hns_roce_port port_data[HNS_ROCE_MAX_PORTS];
	atomic64_t *dfx_cnt;
	struct hns_roce_poe_ctx poe_ctx; /* poe ch array */
};

static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
@@ -1290,6 +1309,11 @@ static inline u8 get_hr_bus_num(struct hns_roce_dev *hr_dev)
	return hr_dev->pci_dev->bus->number;
}

static inline bool poe_is_supported(struct hns_roce_dev *hr_dev)
{
	return !!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_POE);
}

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);

@@ -1431,4 +1455,7 @@ hns_roce_user_mmap_entry_insert(struct ib_ucontext *ucontext, u64 address,
int hns_roce_create_port_files(struct ib_device *ibdev, u8 port_num,
			       struct kobject *kobj);
void hns_roce_unregister_sysfs(struct hns_roce_dev *hr_dev);
int hns_roce_register_poe_channel(struct hns_roce_dev *hr_dev, u8 channel,
				  u64 poe_addr);
int hns_roce_unregister_poe_channel(struct hns_roce_dev *hr_dev, u8 channel);
#endif /* _HNS_ROCE_DEVICE_H */
+39 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
 * Copyright (c) 2023 Hisilicon Limited.
 */

#include <rdma/ib_verbs.h>
#include "hns_roce_device.h"

static bool is_hns_roce(struct ib_device *ib_dev)
{
	if (ib_dev && ib_dev->ops.driver_id == RDMA_DRIVER_HNS)
		return true;

	return false;
}

int rdma_register_poe_channel(struct ib_device *ib_dev, u8 channel,
			      u64 poe_addr)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);

	if (!is_hns_roce(ib_dev))
		return -EOPNOTSUPP;

	return hns_roce_register_poe_channel(hr_dev, channel, poe_addr);
}
EXPORT_SYMBOL(rdma_register_poe_channel);

int rdma_unregister_poe_channel(struct ib_device *ib_dev, u8 channel)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);

	if (!is_hns_roce(ib_dev))
		return -EOPNOTSUPP;

	return hns_roce_unregister_poe_channel(hr_dev, channel);
}
EXPORT_SYMBOL(rdma_unregister_poe_channel);
Loading