Commit b37ad2e2 authored by Junxian Huang's avatar Junxian Huang Committed by Leon Romanovsky
Browse files

RDMA/hns: Initialize bonding resources



Allocate bond_grp resources for each card when the first device in
this card is registered. Block the initialization of VF when its PF
is a bonded slave, as VF is not supported in this case due to HW
constraints.

Signed-off-by: default avatarJunxian Huang <huangjunxian6@hisilicon.com>
Link: https://patch.msgid.link/20251112093510.3696363-3-huangjunxian6@hisilicon.com


Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
parent cdb3a6f1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -4,11 +4,13 @@
#

ccflags-y :=  -I $(srctree)/drivers/net/ethernet/hisilicon/hns3
ccflags-y +=  -I $(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3pf
ccflags-y +=  -I $(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3_common
ccflags-y +=  -I $(src)

hns-roce-hw-v2-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_debugfs.o hns_roce_hw_v2.o
	hns_roce_debugfs.o hns_roce_hw_v2.o hns_roce_bond.o

obj-$(CONFIG_INFINIBAND_HNS_HIP08) += hns-roce-hw-v2.o
+192 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (c) 2025 Hisilicon Limited.
 */

#include "hns_roce_device.h"
#include "hns_roce_hw_v2.h"
#include "hns_roce_bond.h"

static DEFINE_XARRAY(roce_bond_xa);

static struct net_device *get_upper_dev_from_ndev(struct net_device *net_dev)
{
	struct net_device *upper_dev;

	rcu_read_lock();
	upper_dev = netdev_master_upper_dev_get_rcu(net_dev);
	dev_hold(upper_dev);
	rcu_read_unlock();

	return upper_dev;
}

static int get_netdev_bond_slave_id(struct net_device *net_dev,
				    struct hns_roce_bond_group *bond_grp)
{
	int i;

	for (i = 0; i < ROCE_BOND_FUNC_MAX; i++)
		if (net_dev == bond_grp->bond_func_info[i].net_dev)
			return i;

	return -ENOENT;
}

struct hns_roce_bond_group *hns_roce_get_bond_grp(struct net_device *net_dev,
						  u8 bus_num)
{
	struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num);
	struct hns_roce_bond_group *bond_grp;
	struct net_device *upper_dev = NULL;
	int i;

	if (!die_info)
		return NULL;

	for (i = 0; i < ROCE_BOND_NUM_MAX; i++) {
		bond_grp = die_info->bgrps[i];
		if (!bond_grp)
			continue;
		if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0)
			return bond_grp;
		if (bond_grp->upper_dev) {
			upper_dev = get_upper_dev_from_ndev(net_dev);
			if (bond_grp->upper_dev == upper_dev) {
				dev_put(upper_dev);
				return bond_grp;
			}
			dev_put(upper_dev);
		}
	}

	return NULL;
}

static struct hns_roce_die_info *alloc_die_info(int bus_num)
{
	struct hns_roce_die_info *die_info;
	int ret;

	die_info = kzalloc(sizeof(*die_info), GFP_KERNEL);
	if (!die_info)
		return NULL;

	ret = xa_err(xa_store(&roce_bond_xa, bus_num, die_info, GFP_KERNEL));
	if (ret) {
		kfree(die_info);
		return NULL;
	}

	return die_info;
}

static void dealloc_die_info(struct hns_roce_die_info *die_info, u8 bus_num)
{
	xa_erase(&roce_bond_xa, bus_num);
	kfree(die_info);
}

static int alloc_bond_id(struct hns_roce_bond_group *bond_grp)
{
	u8 bus_num = bond_grp->bus_num;
	struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num);
	int i;

	if (!die_info) {
		die_info = alloc_die_info(bus_num);
		if (!die_info)
			return -ENOMEM;
	}

	for (i = 0; i < ROCE_BOND_NUM_MAX; i++) {
		if (die_info->bond_id_mask & BOND_ID(i))
			continue;

		die_info->bond_id_mask |= BOND_ID(i);
		die_info->bgrps[i] = bond_grp;
		bond_grp->bond_id = i;

		return 0;
	}

	return -ENOSPC;
}

static int remove_bond_id(int bus_num, u8 bond_id)
{
	struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num);

	if (bond_id >= ROCE_BOND_NUM_MAX)
		return -EINVAL;

	if (!die_info)
		return -ENODEV;

	die_info->bond_id_mask &= ~BOND_ID(bond_id);
	die_info->bgrps[bond_id] = NULL;
	if (!die_info->bond_id_mask)
		dealloc_die_info(die_info, bus_num);

	return 0;
}

int hns_roce_alloc_bond_grp(struct hns_roce_dev *hr_dev)
{
	struct hns_roce_bond_group *bgrps[ROCE_BOND_NUM_MAX];
	struct hns_roce_bond_group *bond_grp;
	u8 bus_num = get_hr_bus_num(hr_dev);
	int ret;
	int i;

	if (xa_load(&roce_bond_xa, bus_num))
		return 0;

	for (i = 0; i < ROCE_BOND_NUM_MAX; i++) {
		bond_grp = kvzalloc(sizeof(*bond_grp), GFP_KERNEL);
		if (!bond_grp) {
			ret = -ENOMEM;
			goto mem_err;
		}

		bond_grp->bus_num = bus_num;

		ret = alloc_bond_id(bond_grp);
		if (ret) {
			dev_err(hr_dev->dev,
				"failed to alloc bond ID, ret = %d.\n", ret);
			goto alloc_id_err;
		}

		bgrps[i] = bond_grp;
	}

	return 0;

alloc_id_err:
	kvfree(bond_grp);
mem_err:
	for (i--; i >= 0; i--) {
		remove_bond_id(bgrps[i]->bus_num, bgrps[i]->bond_id);
		kvfree(bgrps[i]);
	}
	return ret;
}

void hns_roce_dealloc_bond_grp(void)
{
	struct hns_roce_bond_group *bond_grp;
	struct hns_roce_die_info *die_info;
	unsigned long id;
	int i;

	xa_for_each(&roce_bond_xa, id, die_info) {
		for (i = 0; i < ROCE_BOND_NUM_MAX; i++) {
			bond_grp = die_info->bgrps[i];
			if (!bond_grp)
				continue;
			remove_bond_id(bond_grp->bus_num, bond_grp->bond_id);
			kvfree(bond_grp);
		}
	}
}
+38 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2025 Hisilicon Limited.
 */

#ifndef _HNS_ROCE_BOND_H
#define _HNS_ROCE_BOND_H

#include <linux/netdevice.h>
#include <net/bonding.h>

#define ROCE_BOND_FUNC_MAX 4
#define ROCE_BOND_NUM_MAX 2

#define BOND_ID(id) BIT(id)

struct hns_roce_func_info {
	struct net_device *net_dev;
};

struct hns_roce_bond_group {
	struct net_device *upper_dev;
	u8 bond_id;
	u8 bus_num;
	struct hns_roce_func_info bond_func_info[ROCE_BOND_FUNC_MAX];
};

struct hns_roce_die_info {
	u8 bond_id_mask;
	struct hns_roce_bond_group *bgrps[ROCE_BOND_NUM_MAX];
};

struct hns_roce_bond_group *hns_roce_get_bond_grp(struct net_device *net_dev,
						  u8 bus_num);
int hns_roce_alloc_bond_grp(struct hns_roce_dev *hr_dev);
void hns_roce_dealloc_bond_grp(void);

#endif
+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ enum {
	HNS_ROCE_CAP_FLAG_SDI_MODE		= BIT(14),
	HNS_ROCE_CAP_FLAG_STASH			= BIT(17),
	HNS_ROCE_CAP_FLAG_CQE_INLINE		= BIT(19),
	HNS_ROCE_CAP_FLAG_BOND                  = BIT(21),
	HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB         = BIT(22),
};

+6 −0
Original line number Diff line number Diff line
@@ -43,11 +43,13 @@
#include <rdma/ib_umem.h>
#include <rdma/uverbs_ioctl.h>

#include "hclge_main.h"
#include "hns_roce_common.h"
#include "hns_roce_device.h"
#include "hns_roce_cmd.h"
#include "hns_roce_hem.h"
#include "hns_roce_hw_v2.h"
#include "hns_roce_bond.h"

#define CREATE_TRACE_POINTS
#include "hns_roce_trace.h"
@@ -2270,6 +2272,9 @@ static int hns_roce_query_caps(struct hns_roce_dev *hr_dev)
	caps->flags |= le16_to_cpu(resp_d->cap_flags_ex) <<
		       HNS_ROCE_CAP_FLAGS_EX_SHIFT;

	if (hr_dev->is_vf)
		caps->flags &= ~HNS_ROCE_CAP_FLAG_BOND;

	caps->num_cqs = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_CQS);
	caps->gid_table_len[0] = hr_reg_read(resp_c, PF_CAPS_C_MAX_GID);
	caps->max_cqes = 1 << hr_reg_read(resp_c, PF_CAPS_C_CQ_DEPTH);
@@ -7260,6 +7265,7 @@ static int __init hns_roce_hw_v2_init(void)

static void __exit hns_roce_hw_v2_exit(void)
{
	hns_roce_dealloc_bond_grp();
	hnae3_unregister_client(&hns_roce_hw_v2_client);
	hns_roce_cleanup_debugfs();
}
Loading