mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
Pull rdma updates from Jason Gunthorpe:
"A new Pensando ionic driver, a new Gen 3 HW support for Intel irdma,
and lots of small bnxt_re improvements.
- Small bug fixes and improves to hfi1, efa, mlx5, erdma, rdmarvt,
siw
- Allow userspace access to IB service records through the rdmacm
- Optimize dma mapping for erdma
- Fix shutdown of the GSI QP in mana
- Support relaxed ordering MR and fix a corruption bug with mlx5 DMA
Data Direct
- Many improvement to bnxt_re:
- Debugging features and counters
- Improve performance of some commands
- Change flow_label reporting in completions
- Mirror vnic
- RDMA flow support
- New RDMA driver for Pensando Ethernet devices: ionic
- Gen 3 hardware support for the Intel irdma driver
- Fix rdma routing resolution with VRFs"
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma: (85 commits)
RDMA/ionic: Fix memory leak of admin q_wr
RDMA/siw: Always report immediate post SQ errors
RDMA/bnxt_re: improve clarity in ALLOC_PAGE handler
RDMA/irdma: Remove unused struct irdma_cq fields
RDMA/irdma: Fix positive vs negative error codes in irdma_post_send()
RDMA/bnxt_re: Remove non-statistics counters from hw_counters
RDMA/bnxt_re: Add debugfs info entry for device and resource information
RDMA/bnxt_re: Fix incorrect errno used in function comments
RDMA: Use %pe format specifier for error pointers
RDMA/ionic: Use ether_addr_copy instead of memcpy
RDMA/ionic: Fix build failure on SPARC due to xchg() operand size
RDMA/rxe: Fix race in do_task() when draining
IB/sa: Fix sa_local_svc_timeout_ms read race
IB/ipoib: Ignore L3 master device
RDMA/core: Use route entry flag to decide on loopback traffic
RDMA/core: Resolve MAC of next-hop device without ARP support
RDMA/core: Squash a single user static function
RDMA/irdma: Update Kconfig
RDMA/irdma: Extend CQE Error and Flush Handling for GEN3 Devices
RDMA/irdma: Add Atomic Operations support
...
This commit is contained in:
@@ -50,6 +50,7 @@ Contents:
|
||||
neterion/s2io
|
||||
netronome/nfp
|
||||
pensando/ionic
|
||||
pensando/ionic_rdma
|
||||
qualcomm/ppe/ppe
|
||||
smsc/smc9
|
||||
stmicro/stmmac
|
||||
|
||||
@@ -13,6 +13,7 @@ Contents
|
||||
- Identifying the Adapter
|
||||
- Enabling the driver
|
||||
- Configuring the driver
|
||||
- RDMA Support via Auxiliary Device
|
||||
- Statistics
|
||||
- Support
|
||||
|
||||
@@ -105,6 +106,15 @@ XDP
|
||||
Support for XDP includes the basics, plus Jumbo frames, Redirect and
|
||||
ndo_xmit. There is no current support for zero-copy sockets or HW offload.
|
||||
|
||||
RDMA Support via Auxiliary Device
|
||||
=================================
|
||||
|
||||
The ionic driver supports RDMA (Remote Direct Memory Access) functionality
|
||||
through the Linux auxiliary device framework when advertised by the firmware.
|
||||
RDMA capability is detected during device initialization, and if supported,
|
||||
the ethernet driver will create an auxiliary device that allows the RDMA
|
||||
driver to bind and provide InfiniBand/RoCE functionality.
|
||||
|
||||
Statistics
|
||||
==========
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
===========================================================
|
||||
RDMA Driver for the AMD Pensando(R) Ethernet adapter family
|
||||
===========================================================
|
||||
|
||||
AMD Pensando RDMA driver.
|
||||
Copyright (C) 2018-2025, Advanced Micro Devices, Inc.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The ionic_rdma driver provides Remote Direct Memory Access functionality
|
||||
for AMD Pensando DSC (Distributed Services Card) devices. This driver
|
||||
implements RDMA capabilities as an auxiliary driver that operates in
|
||||
conjunction with the ionic ethernet driver.
|
||||
|
||||
The ionic ethernet driver detects RDMA capability during device
|
||||
initialization and creates auxiliary devices that the ionic_rdma driver
|
||||
binds to, establishing the RDMA data path and control interfaces.
|
||||
|
||||
Identifying the Adapter
|
||||
=======================
|
||||
|
||||
See Documentation/networking/device_drivers/ethernet/pensando/ionic.rst
|
||||
for more information on identifying the adapter.
|
||||
|
||||
Enabling the driver
|
||||
===================
|
||||
|
||||
The ionic_rdma driver depends on the ionic ethernet driver.
|
||||
See Documentation/networking/device_drivers/ethernet/pensando/ionic.rst
|
||||
for detailed information on enabling and configuring the ionic driver.
|
||||
|
||||
The ionic_rdma driver is enabled via the standard kernel configuration system,
|
||||
using the make command::
|
||||
|
||||
make oldconfig/menuconfig/etc.
|
||||
|
||||
The driver is located in the menu structure at:
|
||||
|
||||
-> Device Drivers
|
||||
-> InfiniBand support
|
||||
-> AMD Pensando DSC RDMA/RoCE Support
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
For general Linux RDMA support, please use the RDMA mailing
|
||||
list, which is monitored by AMD Pensando personnel::
|
||||
|
||||
linux-rdma@vger.kernel.org
|
||||
@@ -1177,6 +1177,15 @@ F: Documentation/networking/device_drivers/ethernet/amd/pds_core.rst
|
||||
F: drivers/net/ethernet/amd/pds_core/
|
||||
F: include/linux/pds/
|
||||
|
||||
AMD PENSANDO RDMA DRIVER
|
||||
M: Abhijit Gangurde <abhijit.gangurde@amd.com>
|
||||
M: Allen Hubbe <allen.hubbe@amd.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/networking/device_drivers/ethernet/pensando/ionic_rdma.rst
|
||||
F: drivers/infiniband/hw/ionic/
|
||||
F: include/uapi/rdma/ionic-abi.h
|
||||
|
||||
AMD PMC DRIVER
|
||||
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
||||
@@ -85,6 +85,7 @@ source "drivers/infiniband/hw/efa/Kconfig"
|
||||
source "drivers/infiniband/hw/erdma/Kconfig"
|
||||
source "drivers/infiniband/hw/hfi1/Kconfig"
|
||||
source "drivers/infiniband/hw/hns/Kconfig"
|
||||
source "drivers/infiniband/hw/ionic/Kconfig"
|
||||
source "drivers/infiniband/hw/irdma/Kconfig"
|
||||
source "drivers/infiniband/hw/mana/Kconfig"
|
||||
source "drivers/infiniband/hw/mlx4/Kconfig"
|
||||
|
||||
@@ -446,36 +446,56 @@ static int addr6_resolve(struct sockaddr *src_sock,
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool is_dst_local(const struct dst_entry *dst)
|
||||
{
|
||||
if (dst->ops->family == AF_INET)
|
||||
return !!(dst_rtable(dst)->rt_type & RTN_LOCAL);
|
||||
else if (dst->ops->family == AF_INET6)
|
||||
return !!(dst_rt6_info(dst)->rt6i_flags & RTF_LOCAL);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int addr_resolve_neigh(const struct dst_entry *dst,
|
||||
const struct sockaddr *dst_in,
|
||||
struct rdma_dev_addr *addr,
|
||||
unsigned int ndev_flags,
|
||||
u32 seq)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ndev_flags & IFF_LOOPBACK) {
|
||||
if (is_dst_local(dst)) {
|
||||
/* When the destination is local entry, source and destination
|
||||
* are same. Skip the neighbour lookup.
|
||||
*/
|
||||
memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
|
||||
} else {
|
||||
if (!(ndev_flags & IFF_NOARP)) {
|
||||
/* If the device doesn't do ARP internally */
|
||||
ret = fetch_ha(dst, addr, dst_in, seq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
|
||||
return fetch_ha(dst, addr, dst_in, seq);
|
||||
}
|
||||
|
||||
static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
|
||||
const struct sockaddr *dst_in,
|
||||
const struct dst_entry *dst,
|
||||
const struct net_device *ndev)
|
||||
static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr,
|
||||
const struct sockaddr *dst_in,
|
||||
const struct dst_entry *dst)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device *ndev = READ_ONCE(dst->dev);
|
||||
|
||||
if (dst->dev->flags & IFF_LOOPBACK)
|
||||
/* A physical device must be the RDMA device to use */
|
||||
if (is_dst_local(dst)) {
|
||||
int ret;
|
||||
/*
|
||||
* RDMA (IB/RoCE, iWarp) doesn't run on lo interface or
|
||||
* loopback IP address. So if route is resolved to loopback
|
||||
* interface, translate that to a real ndev based on non
|
||||
* loopback IP address.
|
||||
*/
|
||||
ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in);
|
||||
if (IS_ERR(ndev))
|
||||
return -ENODEV;
|
||||
ret = rdma_translate_ip(dst_in, dev_addr);
|
||||
else
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
rdma_copy_src_l2_addr(dev_addr, dst->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's a gateway and type of device not ARPHRD_INFINIBAND,
|
||||
@@ -490,31 +510,7 @@ static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
|
||||
else
|
||||
dev_addr->network = RDMA_NETWORK_IB;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr,
|
||||
unsigned int *ndev_flags,
|
||||
const struct sockaddr *dst_in,
|
||||
const struct dst_entry *dst)
|
||||
{
|
||||
struct net_device *ndev = READ_ONCE(dst->dev);
|
||||
|
||||
*ndev_flags = ndev->flags;
|
||||
/* A physical device must be the RDMA device to use */
|
||||
if (ndev->flags & IFF_LOOPBACK) {
|
||||
/*
|
||||
* RDMA (IB/RoCE, iWarp) doesn't run on lo interface or
|
||||
* loopback IP address. So if route is resolved to loopback
|
||||
* interface, translate that to a real ndev based on non
|
||||
* loopback IP address.
|
||||
*/
|
||||
ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in);
|
||||
if (IS_ERR(ndev))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return copy_src_l2_addr(dev_addr, dst_in, dst, ndev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_addr_netns_by_gid_rcu(struct rdma_dev_addr *addr)
|
||||
@@ -551,7 +547,6 @@ static int addr_resolve(struct sockaddr *src_in,
|
||||
u32 seq)
|
||||
{
|
||||
struct dst_entry *dst = NULL;
|
||||
unsigned int ndev_flags = 0;
|
||||
struct rtable *rt = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -588,7 +583,7 @@ static int addr_resolve(struct sockaddr *src_in,
|
||||
rcu_read_unlock();
|
||||
goto done;
|
||||
}
|
||||
ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, dst);
|
||||
ret = rdma_set_src_addr_rcu(addr, dst_in, dst);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
@@ -596,7 +591,7 @@ static int addr_resolve(struct sockaddr *src_in,
|
||||
* only if src addr translation didn't fail.
|
||||
*/
|
||||
if (!ret && resolve_neigh)
|
||||
ret = addr_resolve_neigh(dst, dst_in, addr, ndev_flags, seq);
|
||||
ret = addr_resolve_neigh(dst, dst_in, addr, seq);
|
||||
|
||||
if (src_in->sa_family == AF_INET)
|
||||
ip_rt_put(rt);
|
||||
|
||||
@@ -110,8 +110,7 @@ void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *
|
||||
agent = port_priv->agent[qpn];
|
||||
ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
|
||||
if (IS_ERR(ah)) {
|
||||
dev_err(&device->dev, "ib_create_ah_from_wc error %ld\n",
|
||||
PTR_ERR(ah));
|
||||
dev_err(&device->dev, "ib_create_ah_from_wc error %pe\n", ah);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1049,8 +1049,8 @@ static noinline void cm_destroy_id_wait_timeout(struct ib_cm_id *cm_id,
|
||||
struct cm_id_private *cm_id_priv;
|
||||
|
||||
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
|
||||
pr_err("%s: cm_id=%p timed out. state %d -> %d, refcnt=%d\n", __func__,
|
||||
cm_id, old_state, cm_id->state, refcount_read(&cm_id_priv->refcount));
|
||||
pr_err_ratelimited("%s: cm_id=%p timed out. state %d -> %d, refcnt=%d\n", __func__,
|
||||
cm_id, old_state, cm_id->state, refcount_read(&cm_id_priv->refcount));
|
||||
}
|
||||
|
||||
static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
|
||||
|
||||
@@ -2076,6 +2076,7 @@ static void _destroy_id(struct rdma_id_private *id_priv,
|
||||
kfree(id_priv->id.route.path_rec);
|
||||
kfree(id_priv->id.route.path_rec_inbound);
|
||||
kfree(id_priv->id.route.path_rec_outbound);
|
||||
kfree(id_priv->id.route.service_recs);
|
||||
|
||||
put_net(id_priv->id.route.addr.dev_addr.net);
|
||||
kfree(id_priv);
|
||||
@@ -3382,13 +3383,18 @@ err1:
|
||||
int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms)
|
||||
{
|
||||
struct rdma_id_private *id_priv;
|
||||
enum rdma_cm_state state;
|
||||
int ret;
|
||||
|
||||
if (!timeout_ms)
|
||||
return -EINVAL;
|
||||
|
||||
id_priv = container_of(id, struct rdma_id_private, id);
|
||||
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
|
||||
state = id_priv->state;
|
||||
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
|
||||
RDMA_CM_ROUTE_QUERY) &&
|
||||
!cma_comp_exch(id_priv, RDMA_CM_ADDRINFO_RESOLVED,
|
||||
RDMA_CM_ROUTE_QUERY))
|
||||
return -EINVAL;
|
||||
|
||||
cma_id_get(id_priv);
|
||||
@@ -3409,7 +3415,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms)
|
||||
|
||||
return 0;
|
||||
err:
|
||||
cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
|
||||
cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, state);
|
||||
cma_id_put(id_priv);
|
||||
return ret;
|
||||
}
|
||||
@@ -5506,3 +5512,129 @@ static void __exit cma_cleanup(void)
|
||||
|
||||
module_init(cma_init);
|
||||
module_exit(cma_cleanup);
|
||||
|
||||
static void cma_query_ib_service_handler(int status,
|
||||
struct sa_service_rec *recs,
|
||||
unsigned int num_recs, void *context)
|
||||
{
|
||||
struct cma_work *work = context;
|
||||
struct rdma_id_private *id_priv = work->id;
|
||||
struct sockaddr_ib *addr;
|
||||
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
if (!num_recs) {
|
||||
status = -ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (id_priv->id.route.service_recs) {
|
||||
status = -EALREADY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
id_priv->id.route.service_recs =
|
||||
kmalloc_array(num_recs, sizeof(*recs), GFP_KERNEL);
|
||||
if (!id_priv->id.route.service_recs) {
|
||||
status = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
id_priv->id.route.num_service_recs = num_recs;
|
||||
memcpy(id_priv->id.route.service_recs, recs, sizeof(*recs) * num_recs);
|
||||
|
||||
addr = (struct sockaddr_ib *)&id_priv->id.route.addr.dst_addr;
|
||||
addr->sib_family = AF_IB;
|
||||
addr->sib_addr = *(struct ib_addr *)&recs->gid;
|
||||
addr->sib_pkey = recs->pkey;
|
||||
addr->sib_sid = recs->id;
|
||||
rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
|
||||
(union ib_gid *)&addr->sib_addr);
|
||||
ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr,
|
||||
ntohs(addr->sib_pkey));
|
||||
|
||||
queue_work(cma_wq, &work->work);
|
||||
return;
|
||||
|
||||
fail:
|
||||
work->old_state = RDMA_CM_ADDRINFO_QUERY;
|
||||
work->new_state = RDMA_CM_ADDR_BOUND;
|
||||
work->event.event = RDMA_CM_EVENT_ADDRINFO_ERROR;
|
||||
work->event.status = status;
|
||||
pr_debug_ratelimited(
|
||||
"RDMA CM: SERVICE_ERROR: failed to query service record. status %d\n",
|
||||
status);
|
||||
queue_work(cma_wq, &work->work);
|
||||
}
|
||||
|
||||
static int cma_resolve_ib_service(struct rdma_id_private *id_priv,
|
||||
struct rdma_ucm_ib_service *ibs)
|
||||
{
|
||||
struct sa_service_rec sr = {};
|
||||
ib_sa_comp_mask mask = 0;
|
||||
struct cma_work *work;
|
||||
|
||||
work = kzalloc(sizeof(*work), GFP_KERNEL);
|
||||
if (!work)
|
||||
return -ENOMEM;
|
||||
|
||||
cma_id_get(id_priv);
|
||||
|
||||
work->id = id_priv;
|
||||
INIT_WORK(&work->work, cma_work_handler);
|
||||
work->old_state = RDMA_CM_ADDRINFO_QUERY;
|
||||
work->new_state = RDMA_CM_ADDRINFO_RESOLVED;
|
||||
work->event.event = RDMA_CM_EVENT_ADDRINFO_RESOLVED;
|
||||
|
||||
if (ibs->flags & RDMA_USER_CM_IB_SERVICE_FLAG_ID) {
|
||||
sr.id = cpu_to_be64(ibs->service_id);
|
||||
mask |= IB_SA_SERVICE_REC_SERVICE_ID;
|
||||
}
|
||||
if (ibs->flags & RDMA_USER_CM_IB_SERVICE_FLAG_NAME) {
|
||||
strscpy(sr.name, ibs->service_name, sizeof(sr.name));
|
||||
mask |= IB_SA_SERVICE_REC_SERVICE_NAME;
|
||||
}
|
||||
|
||||
id_priv->query_id = ib_sa_service_rec_get(&sa_client,
|
||||
id_priv->id.device,
|
||||
id_priv->id.port_num,
|
||||
&sr, mask,
|
||||
2000, GFP_KERNEL,
|
||||
cma_query_ib_service_handler,
|
||||
work, &id_priv->query);
|
||||
|
||||
if (id_priv->query_id < 0) {
|
||||
cma_id_put(id_priv);
|
||||
kfree(work);
|
||||
return id_priv->query_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rdma_resolve_ib_service(struct rdma_cm_id *id,
|
||||
struct rdma_ucm_ib_service *ibs)
|
||||
{
|
||||
struct rdma_id_private *id_priv;
|
||||
int ret;
|
||||
|
||||
id_priv = container_of(id, struct rdma_id_private, id);
|
||||
if (!id_priv->cma_dev ||
|
||||
!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDRINFO_QUERY))
|
||||
return -EINVAL;
|
||||
|
||||
if (rdma_cap_ib_sa(id->device, id->port_num))
|
||||
ret = cma_resolve_ib_service(id_priv, ibs);
|
||||
else
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
cma_comp_exch(id_priv, RDMA_CM_ADDRINFO_QUERY, RDMA_CM_ADDR_BOUND);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rdma_resolve_ib_service);
|
||||
|
||||
@@ -47,7 +47,9 @@ enum rdma_cm_state {
|
||||
RDMA_CM_ADDR_BOUND,
|
||||
RDMA_CM_LISTEN,
|
||||
RDMA_CM_DEVICE_REMOVAL,
|
||||
RDMA_CM_DESTROYING
|
||||
RDMA_CM_DESTROYING,
|
||||
RDMA_CM_ADDRINFO_QUERY,
|
||||
RDMA_CM_ADDRINFO_RESOLVED
|
||||
};
|
||||
|
||||
struct rdma_id_private {
|
||||
|
||||
@@ -1543,7 +1543,7 @@ static void __ib_unregister_device(struct ib_device *ib_dev)
|
||||
|
||||
/*
|
||||
* We have a registration lock so that all the calls to unregister are
|
||||
* fully fenced, once any unregister returns the device is truely
|
||||
* fully fenced, once any unregister returns the device is truly
|
||||
* unregistered even if multiple callers are unregistering it at the
|
||||
* same time. This also interacts with the registration flow and
|
||||
* provides sane semantics if register and unregister are racing.
|
||||
|
||||
@@ -107,6 +107,8 @@ struct ib_sa_device {
|
||||
struct ib_sa_query {
|
||||
void (*callback)(struct ib_sa_query *sa_query, int status,
|
||||
struct ib_sa_mad *mad);
|
||||
void (*rmpp_callback)(struct ib_sa_query *sa_query, int status,
|
||||
struct ib_mad_recv_wc *mad);
|
||||
void (*release)(struct ib_sa_query *);
|
||||
struct ib_sa_client *client;
|
||||
struct ib_sa_port *port;
|
||||
@@ -150,6 +152,13 @@ struct ib_sa_mcmember_query {
|
||||
struct ib_sa_query sa_query;
|
||||
};
|
||||
|
||||
struct ib_sa_service_query {
|
||||
void (*callback)(int status, struct sa_service_rec *rec,
|
||||
unsigned int num_services, void *context);
|
||||
void *context;
|
||||
struct ib_sa_query sa_query;
|
||||
};
|
||||
|
||||
static LIST_HEAD(ib_nl_request_list);
|
||||
static DEFINE_SPINLOCK(ib_nl_request_lock);
|
||||
static atomic_t ib_nl_sa_request_seq;
|
||||
@@ -684,6 +693,58 @@ static const struct ib_field guidinfo_rec_table[] = {
|
||||
.size_bits = 512 },
|
||||
};
|
||||
|
||||
#define SERVICE_REC_FIELD(field) \
|
||||
.struct_offset_bytes = offsetof(struct sa_service_rec, field), \
|
||||
.struct_size_bytes = sizeof_field(struct sa_service_rec, field), \
|
||||
.field_name = "sa_service_rec:" #field
|
||||
|
||||
static const struct ib_field service_rec_table[] = {
|
||||
{ SERVICE_REC_FIELD(id),
|
||||
.offset_words = 0,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 64 },
|
||||
{ SERVICE_REC_FIELD(gid),
|
||||
.offset_words = 2,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
{ SERVICE_REC_FIELD(pkey),
|
||||
.offset_words = 6,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 16 },
|
||||
{ RESERVED,
|
||||
.offset_words = 6,
|
||||
.offset_bits = 16,
|
||||
.size_bits = 16 },
|
||||
{ SERVICE_REC_FIELD(lease),
|
||||
.offset_words = 7,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 32 },
|
||||
{ SERVICE_REC_FIELD(key),
|
||||
.offset_words = 8,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
{ SERVICE_REC_FIELD(name),
|
||||
.offset_words = 12,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 512 },
|
||||
{ SERVICE_REC_FIELD(data_8),
|
||||
.offset_words = 28,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
{ SERVICE_REC_FIELD(data_16),
|
||||
.offset_words = 32,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
{ SERVICE_REC_FIELD(data_32),
|
||||
.offset_words = 36,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
{ SERVICE_REC_FIELD(data_64),
|
||||
.offset_words = 40,
|
||||
.offset_bits = 0,
|
||||
.size_bits = 128 },
|
||||
};
|
||||
|
||||
#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3
|
||||
|
||||
static inline void ib_sa_disable_local_svc(struct ib_sa_query *query)
|
||||
@@ -1013,6 +1074,8 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
|
||||
if (timeout > IB_SA_LOCAL_SVC_TIMEOUT_MAX)
|
||||
timeout = IB_SA_LOCAL_SVC_TIMEOUT_MAX;
|
||||
|
||||
spin_lock_irqsave(&ib_nl_request_lock, flags);
|
||||
|
||||
delta = timeout - sa_local_svc_timeout_ms;
|
||||
if (delta < 0)
|
||||
abs_delta = -delta;
|
||||
@@ -1020,7 +1083,6 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
|
||||
abs_delta = delta;
|
||||
|
||||
if (delta != 0) {
|
||||
spin_lock_irqsave(&ib_nl_request_lock, flags);
|
||||
sa_local_svc_timeout_ms = timeout;
|
||||
list_for_each_entry(query, &ib_nl_request_list, list) {
|
||||
if (delta < 0 && abs_delta > query->timeout)
|
||||
@@ -1038,9 +1100,10 @@ int ib_nl_handle_set_timeout(struct sk_buff *skb,
|
||||
if (delay)
|
||||
mod_delayed_work(ib_nl_wq, &ib_nl_timed_work,
|
||||
(unsigned long)delay);
|
||||
spin_unlock_irqrestore(&ib_nl_request_lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ib_nl_request_lock, flags);
|
||||
|
||||
settimeout_out:
|
||||
return 0;
|
||||
}
|
||||
@@ -1390,6 +1453,20 @@ void ib_sa_pack_path(struct sa_path_rec *rec, void *attribute)
|
||||
}
|
||||
EXPORT_SYMBOL(ib_sa_pack_path);
|
||||
|
||||
void ib_sa_pack_service(struct sa_service_rec *rec, void *attribute)
|
||||
{
|
||||
ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), rec,
|
||||
attribute);
|
||||
}
|
||||
EXPORT_SYMBOL(ib_sa_pack_service);
|
||||
|
||||
void ib_sa_unpack_service(void *attribute, struct sa_service_rec *rec)
|
||||
{
|
||||
ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table), attribute,
|
||||
rec);
|
||||
}
|
||||
EXPORT_SYMBOL(ib_sa_unpack_service);
|
||||
|
||||
static bool ib_sa_opa_pathrecord_support(struct ib_sa_client *client,
|
||||
struct ib_sa_device *sa_dev,
|
||||
u32 port_num)
|
||||
@@ -1479,6 +1556,68 @@ static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
|
||||
}
|
||||
}
|
||||
|
||||
#define IB_SA_DATA_OFFS 56
|
||||
#define IB_SERVICE_REC_SZ 176
|
||||
|
||||
static void ib_unpack_service_rmpp(struct sa_service_rec *rec,
|
||||
struct ib_mad_recv_wc *mad_wc,
|
||||
int num_services)
|
||||
{
|
||||
unsigned int cp_sz, data_i, data_size, rec_i = 0, buf_i = 0;
|
||||
struct ib_mad_recv_buf *mad_buf;
|
||||
u8 buf[IB_SERVICE_REC_SZ];
|
||||
u8 *data;
|
||||
|
||||
data_size = sizeof(((struct ib_sa_mad *) mad_buf->mad)->data);
|
||||
|
||||
list_for_each_entry(mad_buf, &mad_wc->rmpp_list, list) {
|
||||
data = ((struct ib_sa_mad *) mad_buf->mad)->data;
|
||||
data_i = 0;
|
||||
while (data_i < data_size && rec_i < num_services) {
|
||||
cp_sz = min(IB_SERVICE_REC_SZ - buf_i,
|
||||
data_size - data_i);
|
||||
memcpy(buf + buf_i, data + data_i, cp_sz);
|
||||
data_i += cp_sz;
|
||||
buf_i += cp_sz;
|
||||
if (buf_i == IB_SERVICE_REC_SZ) {
|
||||
ib_sa_unpack_service(buf, rec + rec_i);
|
||||
buf_i = 0;
|
||||
rec_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, int status,
|
||||
struct ib_mad_recv_wc *mad_wc)
|
||||
{
|
||||
struct ib_sa_service_query *query =
|
||||
container_of(sa_query, struct ib_sa_service_query, sa_query);
|
||||
struct sa_service_rec *rec;
|
||||
int num_services;
|
||||
|
||||
if (!mad_wc || !mad_wc->recv_buf.mad) {
|
||||
query->callback(status, NULL, 0, query->context);
|
||||
return;
|
||||
}
|
||||
|
||||
num_services = (mad_wc->mad_len - IB_SA_DATA_OFFS) / IB_SERVICE_REC_SZ;
|
||||
if (!num_services) {
|
||||
query->callback(-ENODATA, NULL, 0, query->context);
|
||||
return;
|
||||
}
|
||||
|
||||
rec = kmalloc_array(num_services, sizeof(*rec), GFP_KERNEL);
|
||||
if (!rec) {
|
||||
query->callback(-ENOMEM, NULL, 0, query->context);
|
||||
return;
|
||||
}
|
||||
|
||||
ib_unpack_service_rmpp(rec, mad_wc, num_services);
|
||||
query->callback(status, rec, num_services, query->context);
|
||||
kfree(rec);
|
||||
}
|
||||
|
||||
static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
|
||||
{
|
||||
struct ib_sa_path_query *query =
|
||||
@@ -1488,6 +1627,14 @@ static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
|
||||
kfree(query);
|
||||
}
|
||||
|
||||
static void ib_sa_service_rec_release(struct ib_sa_query *sa_query)
|
||||
{
|
||||
struct ib_sa_service_query *query =
|
||||
container_of(sa_query, struct ib_sa_service_query, sa_query);
|
||||
|
||||
kfree(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* ib_sa_path_rec_get - Start a Path get query
|
||||
* @client:SA client
|
||||
@@ -1618,6 +1765,101 @@ err1:
|
||||
}
|
||||
EXPORT_SYMBOL(ib_sa_path_rec_get);
|
||||
|
||||
/**
|
||||
* ib_sa_service_rec_get - Start a Service get query
|
||||
* @client: SA client
|
||||
* @device: device to send query on
|
||||
* @port_num: port number to send query on
|
||||
* @rec: Service Record to send in query
|
||||
* @comp_mask: component mask to send in query
|
||||
* @timeout_ms: time to wait for response
|
||||
* @gfp_mask: GFP mask to use for internal allocations
|
||||
* @callback: function called when query completes, times out or is
|
||||
* canceled
|
||||
* @context: opaque user context passed to callback
|
||||
* @sa_query: query context, used to cancel query
|
||||
*
|
||||
* Send a Service Record Get query to the SA to look up a path. The
|
||||
* callback function will be called when the query completes (or
|
||||
* fails); status is 0 for a successful response, -EINTR if the query
|
||||
* is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error
|
||||
* occurred sending the query. The resp parameter of the callback is
|
||||
* only valid if status is 0.
|
||||
*
|
||||
* If the return value of ib_sa_service_rec_get() is negative, it is an
|
||||
* error code. Otherwise it is a query ID that can be used to cancel
|
||||
* the query.
|
||||
*/
|
||||
int ib_sa_service_rec_get(struct ib_sa_client *client,
|
||||
struct ib_device *device, u32 port_num,
|
||||
struct sa_service_rec *rec,
|
||||
ib_sa_comp_mask comp_mask,
|
||||
unsigned long timeout_ms, gfp_t gfp_mask,
|
||||
void (*callback)(int status,
|
||||
struct sa_service_rec *resp,
|
||||
unsigned int num_services,
|
||||
void *context),
|
||||
void *context, struct ib_sa_query **sa_query)
|
||||
{
|
||||
struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
|
||||
struct ib_sa_service_query *query;
|
||||
struct ib_mad_agent *agent;
|
||||
struct ib_sa_port *port;
|
||||
struct ib_sa_mad *mad;
|
||||
int ret;
|
||||
|
||||
if (!sa_dev)
|
||||
return -ENODEV;
|
||||
|
||||
port = &sa_dev->port[port_num - sa_dev->start_port];
|
||||
agent = port->agent;
|
||||
|
||||
query = kzalloc(sizeof(*query), gfp_mask);
|
||||
if (!query)
|
||||
return -ENOMEM;
|
||||
|
||||
query->sa_query.port = port;
|
||||
|
||||
ret = alloc_mad(&query->sa_query, gfp_mask);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
ib_sa_client_get(client);
|
||||
query->sa_query.client = client;
|
||||
query->callback = callback;
|
||||
query->context = context;
|
||||
|
||||
mad = query->sa_query.mad_buf->mad;
|
||||
init_mad(&query->sa_query, agent);
|
||||
|
||||
query->sa_query.rmpp_callback = callback ? ib_sa_service_rec_callback :
|
||||
NULL;
|
||||
query->sa_query.release = ib_sa_service_rec_release;
|
||||
mad->mad_hdr.method = IB_MGMT_METHOD_GET_TABLE;
|
||||
mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC);
|
||||
mad->sa_hdr.comp_mask = comp_mask;
|
||||
|
||||
ib_sa_pack_service(rec, mad->data);
|
||||
|
||||
*sa_query = &query->sa_query;
|
||||
query->sa_query.mad_buf->context[1] = rec;
|
||||
|
||||
ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
|
||||
return ret;
|
||||
|
||||
err2:
|
||||
*sa_query = NULL;
|
||||
ib_sa_client_put(query->sa_query.client);
|
||||
free_mad(&query->sa_query);
|
||||
err1:
|
||||
kfree(query);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ib_sa_service_rec_get);
|
||||
|
||||
static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,
|
||||
int status, struct ib_sa_mad *mad)
|
||||
{
|
||||
@@ -1987,23 +2229,29 @@ static void send_handler(struct ib_mad_agent *agent,
|
||||
{
|
||||
struct ib_sa_query *query = mad_send_wc->send_buf->context[0];
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
|
||||
if (query->callback)
|
||||
if (query->callback || query->rmpp_callback) {
|
||||
switch (mad_send_wc->status) {
|
||||
case IB_WC_SUCCESS:
|
||||
/* No callback -- already got recv */
|
||||
break;
|
||||
case IB_WC_RESP_TIMEOUT_ERR:
|
||||
query->callback(query, -ETIMEDOUT, NULL);
|
||||
status = -ETIMEDOUT;
|
||||
break;
|
||||
case IB_WC_WR_FLUSH_ERR:
|
||||
query->callback(query, -EINTR, NULL);
|
||||
status = -EINTR;
|
||||
break;
|
||||
default:
|
||||
query->callback(query, -EIO, NULL);
|
||||
status = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
query->callback ? query->callback(query, status, NULL) :
|
||||
query->rmpp_callback(query, status, NULL);
|
||||
}
|
||||
|
||||
xa_lock_irqsave(&queries, flags);
|
||||
__xa_erase(&queries, query->id);
|
||||
xa_unlock_irqrestore(&queries, flags);
|
||||
@@ -2019,17 +2267,25 @@ static void recv_handler(struct ib_mad_agent *mad_agent,
|
||||
struct ib_mad_recv_wc *mad_recv_wc)
|
||||
{
|
||||
struct ib_sa_query *query;
|
||||
struct ib_mad *mad;
|
||||
|
||||
|
||||
if (!send_buf)
|
||||
return;
|
||||
|
||||
query = send_buf->context[0];
|
||||
if (query->callback) {
|
||||
mad = mad_recv_wc->recv_buf.mad;
|
||||
|
||||
if (query->rmpp_callback) {
|
||||
if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
|
||||
query->callback(query,
|
||||
mad_recv_wc->recv_buf.mad->mad_hdr.status ?
|
||||
-EINVAL : 0,
|
||||
(struct ib_sa_mad *) mad_recv_wc->recv_buf.mad);
|
||||
query->rmpp_callback(query, mad->mad_hdr.status ?
|
||||
-EINVAL : 0, mad_recv_wc);
|
||||
else
|
||||
query->rmpp_callback(query, -EIO, NULL);
|
||||
} else if (query->callback) {
|
||||
if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
|
||||
query->callback(query, mad->mad_hdr.status ?
|
||||
-EINVAL : 0, (struct ib_sa_mad *)mad);
|
||||
else
|
||||
query->callback(query, -EIO, NULL);
|
||||
}
|
||||
@@ -2181,8 +2437,9 @@ static int ib_sa_add_one(struct ib_device *device)
|
||||
|
||||
sa_dev->port[i].agent =
|
||||
ib_register_mad_agent(device, i + s, IB_QPT_GSI,
|
||||
NULL, 0, send_handler,
|
||||
recv_handler, sa_dev, 0);
|
||||
NULL, IB_MGMT_RMPP_VERSION,
|
||||
send_handler, recv_handler,
|
||||
sa_dev, 0);
|
||||
if (IS_ERR(sa_dev->port[i].agent)) {
|
||||
ret = PTR_ERR(sa_dev->port[i].agent);
|
||||
goto err;
|
||||
|
||||
@@ -282,6 +282,10 @@ static struct ucma_event *ucma_create_uevent(struct ucma_context *ctx,
|
||||
}
|
||||
uevent->resp.event = event->event;
|
||||
uevent->resp.status = event->status;
|
||||
|
||||
if (event->event == RDMA_CM_EVENT_ADDRINFO_RESOLVED)
|
||||
goto out;
|
||||
|
||||
if (ctx->cm_id->qp_type == IB_QPT_UD)
|
||||
ucma_copy_ud_event(ctx->cm_id->device, &uevent->resp.param.ud,
|
||||
&event->param.ud);
|
||||
@@ -289,6 +293,7 @@ static struct ucma_event *ucma_create_uevent(struct ucma_context *ctx,
|
||||
ucma_copy_conn_event(&uevent->resp.param.conn,
|
||||
&event->param.conn);
|
||||
|
||||
out:
|
||||
uevent->resp.ece.vendor_id = event->ece.vendor_id;
|
||||
uevent->resp.ece.attr_mod = event->ece.attr_mod;
|
||||
return uevent;
|
||||
@@ -728,6 +733,28 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ucma_resolve_ib_service(struct ucma_file *file,
|
||||
const char __user *inbuf, int in_len,
|
||||
int out_len)
|
||||
{
|
||||
struct rdma_ucm_resolve_ib_service cmd;
|
||||
struct ucma_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
mutex_lock(&ctx->mutex);
|
||||
ret = rdma_resolve_ib_service(ctx->cm_id, &cmd.ibs);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
ucma_put_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ucma_resolve_route(struct ucma_file *file,
|
||||
const char __user *inbuf,
|
||||
int in_len, int out_len)
|
||||
@@ -994,6 +1021,43 @@ static ssize_t ucma_query_gid(struct ucma_context *ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ucma_query_ib_service(struct ucma_context *ctx,
|
||||
void __user *response, int out_len)
|
||||
{
|
||||
struct rdma_ucm_query_ib_service_resp *resp;
|
||||
int n, ret = 0;
|
||||
|
||||
if (out_len < sizeof(struct rdma_ucm_query_ib_service_resp))
|
||||
return -ENOSPC;
|
||||
|
||||
if (!ctx->cm_id->route.service_recs)
|
||||
return -ENODATA;
|
||||
|
||||
resp = kzalloc(out_len, GFP_KERNEL);
|
||||
if (!resp)
|
||||
return -ENOMEM;
|
||||
|
||||
resp->num_service_recs = ctx->cm_id->route.num_service_recs;
|
||||
|
||||
n = (out_len - sizeof(struct rdma_ucm_query_ib_service_resp)) /
|
||||
sizeof(struct ib_user_service_rec);
|
||||
|
||||
if (!n)
|
||||
goto out;
|
||||
|
||||
if (n > ctx->cm_id->route.num_service_recs)
|
||||
n = ctx->cm_id->route.num_service_recs;
|
||||
|
||||
memcpy(resp->recs, ctx->cm_id->route.service_recs,
|
||||
sizeof(*resp->recs) * n);
|
||||
if (copy_to_user(response, resp, struct_size(resp, recs, n)))
|
||||
ret = -EFAULT;
|
||||
|
||||
out:
|
||||
kfree(resp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ucma_query(struct ucma_file *file,
|
||||
const char __user *inbuf,
|
||||
int in_len, int out_len)
|
||||
@@ -1022,6 +1086,9 @@ static ssize_t ucma_query(struct ucma_file *file,
|
||||
case RDMA_USER_CM_QUERY_GID:
|
||||
ret = ucma_query_gid(ctx, response, out_len);
|
||||
break;
|
||||
case RDMA_USER_CM_QUERY_IB_SERVICE:
|
||||
ret = ucma_query_ib_service(ctx, response, out_len);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
@@ -1678,6 +1745,55 @@ err_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ucma_write_cm_event(struct ucma_file *file,
|
||||
const char __user *inbuf, int in_len,
|
||||
int out_len)
|
||||
{
|
||||
struct rdma_ucm_write_cm_event cmd;
|
||||
struct rdma_cm_event event = {};
|
||||
struct ucma_event *uevent;
|
||||
struct ucma_context *ctx;
|
||||
int ret = 0;
|
||||
|
||||
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((cmd.event != RDMA_CM_EVENT_USER) &&
|
||||
(cmd.event != RDMA_CM_EVENT_INTERNAL))
|
||||
return -EINVAL;
|
||||
|
||||
ctx = ucma_get_ctx(file, cmd.id);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
event.event = cmd.event;
|
||||
event.status = cmd.status;
|
||||
event.param.arg = cmd.param.arg;
|
||||
|
||||
uevent = kzalloc(sizeof(*uevent), GFP_KERNEL);
|
||||
if (!uevent) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uevent->ctx = ctx;
|
||||
uevent->resp.uid = ctx->uid;
|
||||
uevent->resp.id = ctx->id;
|
||||
uevent->resp.event = event.event;
|
||||
uevent->resp.status = event.status;
|
||||
memcpy(uevent->resp.param.arg32, &event.param.arg,
|
||||
sizeof(event.param.arg));
|
||||
|
||||
mutex_lock(&ctx->file->mut);
|
||||
list_add_tail(&uevent->list, &ctx->file->event_list);
|
||||
mutex_unlock(&ctx->file->mut);
|
||||
wake_up_interruptible(&ctx->file->poll_wait);
|
||||
|
||||
out:
|
||||
ucma_put_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
|
||||
const char __user *inbuf,
|
||||
int in_len, int out_len) = {
|
||||
@@ -1703,7 +1819,9 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
|
||||
[RDMA_USER_CM_CMD_QUERY] = ucma_query,
|
||||
[RDMA_USER_CM_CMD_BIND] = ucma_bind,
|
||||
[RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
|
||||
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast
|
||||
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
|
||||
[RDMA_USER_CM_CMD_RESOLVE_IB_SERVICE] = ucma_resolve_ib_service,
|
||||
[RDMA_USER_CM_CMD_WRITE_CM_EVENT] = ucma_write_cm_event,
|
||||
};
|
||||
|
||||
static ssize_t ucma_write(struct file *filp, const char __user *buf,
|
||||
|
||||
@@ -14,3 +14,4 @@ obj-$(CONFIG_INFINIBAND_HNS_HIP08) += hns/
|
||||
obj-$(CONFIG_INFINIBAND_QEDR) += qedr/
|
||||
obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re/
|
||||
obj-$(CONFIG_INFINIBAND_ERDMA) += erdma/
|
||||
obj-$(CONFIG_INFINIBAND_IONIC) += ionic/
|
||||
|
||||
@@ -172,9 +172,9 @@ struct bnxt_re_dev {
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
#define BNXT_RE_FLAG_NETDEV_REGISTERED 0
|
||||
#define BNXT_RE_FLAG_STATS_CTX3_ALLOC 1
|
||||
#define BNXT_RE_FLAG_HAVE_L2_REF 3
|
||||
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4
|
||||
#define BNXT_RE_FLAG_QOS_WORK_REG 5
|
||||
#define BNXT_RE_FLAG_RESOURCES_ALLOCATED 7
|
||||
#define BNXT_RE_FLAG_RESOURCES_INITIALIZED 8
|
||||
#define BNXT_RE_FLAG_ERR_DEVICE_DETACHED 17
|
||||
@@ -187,9 +187,6 @@ struct bnxt_re_dev {
|
||||
|
||||
int id;
|
||||
|
||||
struct delayed_work worker;
|
||||
u8 cur_prio_map;
|
||||
|
||||
/* RCFW Channel */
|
||||
struct bnxt_qplib_rcfw rcfw;
|
||||
|
||||
@@ -227,6 +224,13 @@ struct bnxt_re_dev {
|
||||
struct workqueue_struct *dcb_wq;
|
||||
struct dentry *cc_config;
|
||||
struct bnxt_re_dbg_cc_config_params *cc_config_params;
|
||||
#define BNXT_VPD_FLD_LEN 32
|
||||
char board_partno[BNXT_VPD_FLD_LEN];
|
||||
/* RoCE mirror */
|
||||
u16 mirror_vnic_id;
|
||||
union ib_gid ugid;
|
||||
u32 ugid_index;
|
||||
u8 sniffer_flow_created : 1;
|
||||
};
|
||||
|
||||
#define to_bnxt_re_dev(ptr, member) \
|
||||
@@ -243,6 +247,10 @@ int bnxt_re_assign_pma_port_counters(struct bnxt_re_dev *rdev, struct ib_mad *ou
|
||||
int bnxt_re_assign_pma_port_ext_counters(struct bnxt_re_dev *rdev,
|
||||
struct ib_mad *out_mad);
|
||||
|
||||
void bnxt_re_hwrm_free_vnic(struct bnxt_re_dev *rdev);
|
||||
int bnxt_re_hwrm_alloc_vnic(struct bnxt_re_dev *rdev);
|
||||
int bnxt_re_hwrm_cfg_vnic(struct bnxt_re_dev *rdev, u32 qp_id);
|
||||
|
||||
static inline struct device *rdev_to_dev(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
if (rdev)
|
||||
@@ -276,4 +284,7 @@ static inline int bnxt_re_read_context_allowed(struct bnxt_re_dev *rdev)
|
||||
#define BNXT_RE_CONTEXT_TYPE_MRW_SIZE_P7 192
|
||||
#define BNXT_RE_CONTEXT_TYPE_SRQ_SIZE_P7 192
|
||||
|
||||
#define BNXT_RE_HWRM_CMD_TIMEOUT(rdev) \
|
||||
((rdev)->chip_ctx->hwrm_cmd_max_timeout * 1000)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <rdma/ib_addr.h>
|
||||
|
||||
#include "bnxt_ulp.h"
|
||||
@@ -314,6 +315,40 @@ static const struct file_operations bnxt_re_cc_config_ops = {
|
||||
.write = bnxt_re_cc_config_set,
|
||||
};
|
||||
|
||||
static int info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct bnxt_re_dev *rdev = m->private;
|
||||
struct bnxt_re_res_cntrs *res_s = &rdev->stats.res;
|
||||
|
||||
seq_puts(m, "Info:\n");
|
||||
seq_printf(m, "Device Name\t\t: %s\n", dev_name(&rdev->ibdev.dev));
|
||||
seq_printf(m, "PD Watermark\t\t: %llu\n", res_s->pd_watermark);
|
||||
seq_printf(m, "AH Watermark\t\t: %llu\n", res_s->ah_watermark);
|
||||
seq_printf(m, "QP Watermark\t\t: %llu\n", res_s->qp_watermark);
|
||||
seq_printf(m, "RC QP Watermark\t\t: %llu\n", res_s->rc_qp_watermark);
|
||||
seq_printf(m, "UD QP Watermark\t\t: %llu\n", res_s->ud_qp_watermark);
|
||||
seq_printf(m, "SRQ Watermark\t\t: %llu\n", res_s->srq_watermark);
|
||||
seq_printf(m, "CQ Watermark\t\t: %llu\n", res_s->cq_watermark);
|
||||
seq_printf(m, "MR Watermark\t\t: %llu\n", res_s->mr_watermark);
|
||||
seq_printf(m, "MW Watermark\t\t: %llu\n", res_s->mw_watermark);
|
||||
seq_printf(m, "CQ Resize Count\t\t: %d\n", atomic_read(&res_s->resize_count));
|
||||
if (rdev->pacing.dbr_pacing) {
|
||||
seq_printf(m, "DB Pacing Reschedule\t: %llu\n", rdev->stats.pacing.resched);
|
||||
seq_printf(m, "DB Pacing Complete\t: %llu\n", rdev->stats.pacing.complete);
|
||||
seq_printf(m, "DB Pacing Alerts\t: %llu\n", rdev->stats.pacing.alerts);
|
||||
seq_printf(m, "DB FIFO Register\t: 0x%x\n",
|
||||
readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(info);
|
||||
|
||||
static void bnxt_re_debugfs_add_info(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
debugfs_create_file("info", 0400, rdev->dbg_root, rdev, &info_fops);
|
||||
}
|
||||
|
||||
void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
struct pci_dev *pdev = rdev->en_dev->pdev;
|
||||
@@ -325,6 +360,8 @@ void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev)
|
||||
rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root);
|
||||
rdev->cc_config = debugfs_create_dir("cc_config", rdev->dbg_root);
|
||||
|
||||
bnxt_re_debugfs_add_info(rdev);
|
||||
|
||||
rdev->cc_config_params = kzalloc(sizeof(*cc_params), GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < BNXT_RE_CC_PARAM_GEN0; i++) {
|
||||
|
||||
@@ -51,25 +51,6 @@
|
||||
#include "hw_counters.h"
|
||||
|
||||
static const struct rdma_stat_desc bnxt_re_stat_descs[] = {
|
||||
[BNXT_RE_ACTIVE_PD].name = "active_pds",
|
||||
[BNXT_RE_ACTIVE_AH].name = "active_ahs",
|
||||
[BNXT_RE_ACTIVE_QP].name = "active_qps",
|
||||
[BNXT_RE_ACTIVE_RC_QP].name = "active_rc_qps",
|
||||
[BNXT_RE_ACTIVE_UD_QP].name = "active_ud_qps",
|
||||
[BNXT_RE_ACTIVE_SRQ].name = "active_srqs",
|
||||
[BNXT_RE_ACTIVE_CQ].name = "active_cqs",
|
||||
[BNXT_RE_ACTIVE_MR].name = "active_mrs",
|
||||
[BNXT_RE_ACTIVE_MW].name = "active_mws",
|
||||
[BNXT_RE_WATERMARK_PD].name = "watermark_pds",
|
||||
[BNXT_RE_WATERMARK_AH].name = "watermark_ahs",
|
||||
[BNXT_RE_WATERMARK_QP].name = "watermark_qps",
|
||||
[BNXT_RE_WATERMARK_RC_QP].name = "watermark_rc_qps",
|
||||
[BNXT_RE_WATERMARK_UD_QP].name = "watermark_ud_qps",
|
||||
[BNXT_RE_WATERMARK_SRQ].name = "watermark_srqs",
|
||||
[BNXT_RE_WATERMARK_CQ].name = "watermark_cqs",
|
||||
[BNXT_RE_WATERMARK_MR].name = "watermark_mrs",
|
||||
[BNXT_RE_WATERMARK_MW].name = "watermark_mws",
|
||||
[BNXT_RE_RESIZE_CQ_CNT].name = "resize_cq_cnt",
|
||||
[BNXT_RE_RX_PKTS].name = "rx_pkts",
|
||||
[BNXT_RE_RX_BYTES].name = "rx_bytes",
|
||||
[BNXT_RE_TX_PKTS].name = "tx_pkts",
|
||||
@@ -79,22 +60,22 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = {
|
||||
[BNXT_RE_TX_DISCARDS].name = "tx_roce_discards",
|
||||
[BNXT_RE_RX_ERRORS].name = "rx_roce_errors",
|
||||
[BNXT_RE_RX_DISCARDS].name = "rx_roce_discards",
|
||||
[BNXT_RE_TO_RETRANSMITS].name = "to_retransmits",
|
||||
[BNXT_RE_SEQ_ERR_NAKS_RCVD].name = "seq_err_naks_rcvd",
|
||||
[BNXT_RE_MAX_RETRY_EXCEEDED].name = "max_retry_exceeded",
|
||||
[BNXT_RE_RNR_NAKS_RCVD].name = "rnr_naks_rcvd",
|
||||
[BNXT_RE_MISSING_RESP].name = "missing_resp",
|
||||
[BNXT_RE_TO_RETRANSMITS].name = "local_ack_timeout_err",
|
||||
[BNXT_RE_SEQ_ERR_NAKS_RCVD].name = "packet_seq_err",
|
||||
[BNXT_RE_MAX_RETRY_EXCEEDED].name = "max_retry_exceeded",
|
||||
[BNXT_RE_RNR_NAKS_RCVD].name = "rnr_nak_retry_err",
|
||||
[BNXT_RE_MISSING_RESP].name = "implied_nak_seq_err",
|
||||
[BNXT_RE_UNRECOVERABLE_ERR].name = "unrecoverable_err",
|
||||
[BNXT_RE_BAD_RESP_ERR].name = "bad_resp_err",
|
||||
[BNXT_RE_LOCAL_QP_OP_ERR].name = "local_qp_op_err",
|
||||
[BNXT_RE_LOCAL_PROTECTION_ERR].name = "local_protection_err",
|
||||
[BNXT_RE_MEM_MGMT_OP_ERR].name = "mem_mgmt_op_err",
|
||||
[BNXT_RE_REMOTE_INVALID_REQ_ERR].name = "remote_invalid_req_err",
|
||||
[BNXT_RE_REMOTE_ACCESS_ERR].name = "remote_access_err",
|
||||
[BNXT_RE_REMOTE_INVALID_REQ_ERR].name = "req_remote_invalid_request",
|
||||
[BNXT_RE_REMOTE_ACCESS_ERR].name = "req_remote_access_errors",
|
||||
[BNXT_RE_REMOTE_OP_ERR].name = "remote_op_err",
|
||||
[BNXT_RE_DUP_REQ].name = "dup_req",
|
||||
[BNXT_RE_DUP_REQ].name = "duplicate_request",
|
||||
[BNXT_RE_RES_EXCEED_MAX].name = "res_exceed_max",
|
||||
[BNXT_RE_RES_LENGTH_MISMATCH].name = "res_length_mismatch",
|
||||
[BNXT_RE_RES_LENGTH_MISMATCH].name = "resp_local_length_error",
|
||||
[BNXT_RE_RES_EXCEEDS_WQE].name = "res_exceeds_wqe",
|
||||
[BNXT_RE_RES_OPCODE_ERR].name = "res_opcode_err",
|
||||
[BNXT_RE_RES_RX_INVALID_RKEY].name = "res_rx_invalid_rkey",
|
||||
@@ -118,7 +99,7 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = {
|
||||
[BNXT_RE_RES_SRQ_LOAD_ERR].name = "res_srq_load_err",
|
||||
[BNXT_RE_RES_TX_PCI_ERR].name = "res_tx_pci_err",
|
||||
[BNXT_RE_RES_RX_PCI_ERR].name = "res_rx_pci_err",
|
||||
[BNXT_RE_OUT_OF_SEQ_ERR].name = "oos_drop_count",
|
||||
[BNXT_RE_OUT_OF_SEQ_ERR].name = "out_of_sequence",
|
||||
[BNXT_RE_TX_ATOMIC_REQ].name = "tx_atomic_req",
|
||||
[BNXT_RE_TX_READ_REQ].name = "tx_read_req",
|
||||
[BNXT_RE_TX_READ_RES].name = "tx_read_resp",
|
||||
@@ -126,23 +107,22 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = {
|
||||
[BNXT_RE_TX_SEND_REQ].name = "tx_send_req",
|
||||
[BNXT_RE_TX_ROCE_PKTS].name = "tx_roce_only_pkts",
|
||||
[BNXT_RE_TX_ROCE_BYTES].name = "tx_roce_only_bytes",
|
||||
[BNXT_RE_RX_ATOMIC_REQ].name = "rx_atomic_req",
|
||||
[BNXT_RE_RX_READ_REQ].name = "rx_read_req",
|
||||
[BNXT_RE_RX_ATOMIC_REQ].name = "rx_atomic_requests",
|
||||
[BNXT_RE_RX_READ_REQ].name = "rx_read_requests",
|
||||
[BNXT_RE_RX_READ_RESP].name = "rx_read_resp",
|
||||
[BNXT_RE_RX_WRITE_REQ].name = "rx_write_req",
|
||||
[BNXT_RE_RX_WRITE_REQ].name = "rx_write_requests",
|
||||
[BNXT_RE_RX_SEND_REQ].name = "rx_send_req",
|
||||
[BNXT_RE_RX_ROCE_PKTS].name = "rx_roce_only_pkts",
|
||||
[BNXT_RE_RX_ROCE_BYTES].name = "rx_roce_only_bytes",
|
||||
[BNXT_RE_RX_ROCE_GOOD_PKTS].name = "rx_roce_good_pkts",
|
||||
[BNXT_RE_RX_ROCE_GOOD_BYTES].name = "rx_roce_good_bytes",
|
||||
[BNXT_RE_OOB].name = "rx_out_of_buffer",
|
||||
[BNXT_RE_TX_CNP].name = "tx_cnp_pkts",
|
||||
[BNXT_RE_RX_CNP].name = "rx_cnp_pkts",
|
||||
[BNXT_RE_RX_ECN].name = "rx_ecn_marked_pkts",
|
||||
[BNXT_RE_PACING_RESCHED].name = "pacing_reschedule",
|
||||
[BNXT_RE_PACING_CMPL].name = "pacing_complete",
|
||||
[BNXT_RE_PACING_ALERT].name = "pacing_alerts",
|
||||
[BNXT_RE_DB_FIFO_REG].name = "db_fifo_register",
|
||||
[BNXT_RE_OOB].name = "out_of_buffer",
|
||||
[BNXT_RE_TX_CNP].name = "np_cnp_pkts",
|
||||
[BNXT_RE_RX_CNP].name = "rp_cnp_handled",
|
||||
[BNXT_RE_RX_ECN].name = "np_ecn_marked_roce_packets",
|
||||
[BNXT_RE_REQ_CQE_ERROR].name = "req_cqe_error",
|
||||
[BNXT_RE_RESP_CQE_ERROR].name = "resp_cqe_error",
|
||||
[BNXT_RE_RESP_REMOTE_ACCESS_ERRS].name = "resp_remote_access_errors",
|
||||
};
|
||||
|
||||
static void bnxt_re_copy_ext_stats(struct bnxt_re_dev *rdev,
|
||||
@@ -273,18 +253,20 @@ static void bnxt_re_copy_err_stats(struct bnxt_re_dev *rdev,
|
||||
err_s->res_rx_pci_err;
|
||||
stats->value[BNXT_RE_OUT_OF_SEQ_ERR] =
|
||||
err_s->res_oos_drop_count;
|
||||
}
|
||||
|
||||
static void bnxt_re_copy_db_pacing_stats(struct bnxt_re_dev *rdev,
|
||||
struct rdma_hw_stats *stats)
|
||||
{
|
||||
struct bnxt_re_db_pacing_stats *pacing_s = &rdev->stats.pacing;
|
||||
|
||||
stats->value[BNXT_RE_PACING_RESCHED] = pacing_s->resched;
|
||||
stats->value[BNXT_RE_PACING_CMPL] = pacing_s->complete;
|
||||
stats->value[BNXT_RE_PACING_ALERT] = pacing_s->alerts;
|
||||
stats->value[BNXT_RE_DB_FIFO_REG] =
|
||||
readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off);
|
||||
stats->value[BNXT_RE_REQ_CQE_ERROR] =
|
||||
err_s->bad_resp_err +
|
||||
err_s->local_qp_op_err +
|
||||
err_s->local_protection_err +
|
||||
err_s->mem_mgmt_op_err +
|
||||
err_s->remote_invalid_req_err +
|
||||
err_s->remote_access_err +
|
||||
err_s->remote_op_err;
|
||||
stats->value[BNXT_RE_RESP_CQE_ERROR] =
|
||||
err_s->res_cmp_err +
|
||||
err_s->res_cq_load_err;
|
||||
stats->value[BNXT_RE_RESP_REMOTE_ACCESS_ERRS] =
|
||||
err_s->res_rx_no_perm +
|
||||
err_s->res_tx_no_perm;
|
||||
}
|
||||
|
||||
int bnxt_re_assign_pma_port_ext_counters(struct bnxt_re_dev *rdev, struct ib_mad *out_mad)
|
||||
@@ -382,7 +364,6 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
|
||||
u32 port, int index)
|
||||
{
|
||||
struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
|
||||
struct bnxt_re_res_cntrs *res_s = &rdev->stats.res;
|
||||
struct bnxt_qplib_roce_stats *err_s = NULL;
|
||||
struct ctx_hw_stats *hw_stats = NULL;
|
||||
int rc = 0;
|
||||
@@ -391,26 +372,6 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
|
||||
if (!port || !stats)
|
||||
return -EINVAL;
|
||||
|
||||
stats->value[BNXT_RE_ACTIVE_QP] = atomic_read(&res_s->qp_count);
|
||||
stats->value[BNXT_RE_ACTIVE_RC_QP] = atomic_read(&res_s->rc_qp_count);
|
||||
stats->value[BNXT_RE_ACTIVE_UD_QP] = atomic_read(&res_s->ud_qp_count);
|
||||
stats->value[BNXT_RE_ACTIVE_SRQ] = atomic_read(&res_s->srq_count);
|
||||
stats->value[BNXT_RE_ACTIVE_CQ] = atomic_read(&res_s->cq_count);
|
||||
stats->value[BNXT_RE_ACTIVE_MR] = atomic_read(&res_s->mr_count);
|
||||
stats->value[BNXT_RE_ACTIVE_MW] = atomic_read(&res_s->mw_count);
|
||||
stats->value[BNXT_RE_ACTIVE_PD] = atomic_read(&res_s->pd_count);
|
||||
stats->value[BNXT_RE_ACTIVE_AH] = atomic_read(&res_s->ah_count);
|
||||
stats->value[BNXT_RE_WATERMARK_QP] = res_s->qp_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_RC_QP] = res_s->rc_qp_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_UD_QP] = res_s->ud_qp_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_SRQ] = res_s->srq_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_CQ] = res_s->cq_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_MR] = res_s->mr_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_MW] = res_s->mw_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_PD] = res_s->pd_watermark;
|
||||
stats->value[BNXT_RE_WATERMARK_AH] = res_s->ah_watermark;
|
||||
stats->value[BNXT_RE_RESIZE_CQ_CNT] = atomic_read(&res_s->resize_count);
|
||||
|
||||
if (hw_stats) {
|
||||
stats->value[BNXT_RE_RECOVERABLE_ERRORS] =
|
||||
le64_to_cpu(hw_stats->tx_bcast_pkts);
|
||||
@@ -449,8 +410,6 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (rdev->pacing.dbr_pacing && bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
|
||||
bnxt_re_copy_db_pacing_stats(rdev, stats);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -41,25 +41,6 @@
|
||||
#define __BNXT_RE_HW_STATS_H__
|
||||
|
||||
enum bnxt_re_hw_stats {
|
||||
BNXT_RE_ACTIVE_PD,
|
||||
BNXT_RE_ACTIVE_AH,
|
||||
BNXT_RE_ACTIVE_QP,
|
||||
BNXT_RE_ACTIVE_RC_QP,
|
||||
BNXT_RE_ACTIVE_UD_QP,
|
||||
BNXT_RE_ACTIVE_SRQ,
|
||||
BNXT_RE_ACTIVE_CQ,
|
||||
BNXT_RE_ACTIVE_MR,
|
||||
BNXT_RE_ACTIVE_MW,
|
||||
BNXT_RE_WATERMARK_PD,
|
||||
BNXT_RE_WATERMARK_AH,
|
||||
BNXT_RE_WATERMARK_QP,
|
||||
BNXT_RE_WATERMARK_RC_QP,
|
||||
BNXT_RE_WATERMARK_UD_QP,
|
||||
BNXT_RE_WATERMARK_SRQ,
|
||||
BNXT_RE_WATERMARK_CQ,
|
||||
BNXT_RE_WATERMARK_MR,
|
||||
BNXT_RE_WATERMARK_MW,
|
||||
BNXT_RE_RESIZE_CQ_CNT,
|
||||
BNXT_RE_RX_PKTS,
|
||||
BNXT_RE_RX_BYTES,
|
||||
BNXT_RE_TX_PKTS,
|
||||
@@ -129,10 +110,9 @@ enum bnxt_re_hw_stats {
|
||||
BNXT_RE_TX_CNP,
|
||||
BNXT_RE_RX_CNP,
|
||||
BNXT_RE_RX_ECN,
|
||||
BNXT_RE_PACING_RESCHED,
|
||||
BNXT_RE_PACING_CMPL,
|
||||
BNXT_RE_PACING_ALERT,
|
||||
BNXT_RE_DB_FIFO_REG,
|
||||
BNXT_RE_REQ_CQE_ERROR,
|
||||
BNXT_RE_RESP_CQE_ERROR,
|
||||
BNXT_RE_RESP_REMOTE_ACCESS_ERRS,
|
||||
BNXT_RE_NUM_EXT_COUNTERS
|
||||
};
|
||||
|
||||
|
||||
@@ -288,7 +288,9 @@ int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num,
|
||||
}
|
||||
port_attr->max_mtu = IB_MTU_4096;
|
||||
port_attr->active_mtu = iboe_get_mtu(rdev->netdev->mtu);
|
||||
port_attr->gid_tbl_len = dev_attr->max_sgid;
|
||||
/* One GID is reserved for RawEth QP. Report one less */
|
||||
port_attr->gid_tbl_len = (rdev->rcfw.roce_mirror ? (dev_attr->max_sgid - 1) :
|
||||
dev_attr->max_sgid);
|
||||
port_attr->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
|
||||
IB_PORT_DEVICE_MGMT_SUP |
|
||||
IB_PORT_VENDOR_CLASS_SUP;
|
||||
@@ -375,7 +377,7 @@ int bnxt_re_del_gid(const struct ib_gid_attr *attr, void **context)
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
if (sgid_tbl && sgid_tbl->active) {
|
||||
if (sgid_tbl->active) {
|
||||
if (ctx->idx >= sgid_tbl->max)
|
||||
return -EINVAL;
|
||||
gid_to_del = &sgid_tbl->tbl[ctx->idx].gid;
|
||||
@@ -429,7 +431,7 @@ int bnxt_re_add_gid(const struct ib_gid_attr *attr, void **context)
|
||||
|
||||
rc = bnxt_qplib_add_sgid(sgid_tbl, (struct bnxt_qplib_gid *)&attr->gid,
|
||||
rdev->qplib_res.netdev->dev_addr,
|
||||
vlan_id, true, &tbl_idx);
|
||||
vlan_id, true, &tbl_idx, false, 0);
|
||||
if (rc == -EALREADY) {
|
||||
ctx_tbl = sgid_tbl->ctx;
|
||||
ctx_tbl[tbl_idx]->refcnt++;
|
||||
@@ -955,6 +957,20 @@ fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void bnxt_re_del_unique_gid(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!rdev->rcfw.roce_mirror)
|
||||
return;
|
||||
|
||||
rc = bnxt_qplib_del_sgid(&rdev->qplib_res.sgid_tbl,
|
||||
(struct bnxt_qplib_gid *)&rdev->ugid,
|
||||
0xFFFF, true);
|
||||
if (rc)
|
||||
dev_err(rdev_to_dev(rdev), "Failed to delete unique GID, rc: %d\n", rc);
|
||||
}
|
||||
|
||||
/* Queue Pairs */
|
||||
int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
|
||||
{
|
||||
@@ -994,6 +1010,9 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
|
||||
else if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_UD)
|
||||
atomic_dec(&rdev->stats.res.ud_qp_count);
|
||||
|
||||
if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE)
|
||||
bnxt_re_del_unique_gid(rdev);
|
||||
|
||||
ib_umem_release(qp->rumem);
|
||||
ib_umem_release(qp->sumem);
|
||||
|
||||
@@ -1018,6 +1037,8 @@ static u8 __from_ib_qp_type(enum ib_qp_type type)
|
||||
return CMDQ_CREATE_QP_TYPE_RC;
|
||||
case IB_QPT_UD:
|
||||
return CMDQ_CREATE_QP_TYPE_UD;
|
||||
case IB_QPT_RAW_PACKET:
|
||||
return CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE;
|
||||
default:
|
||||
return IB_QPT_MAX;
|
||||
}
|
||||
@@ -1595,6 +1616,29 @@ static bool bnxt_re_test_qp_limits(struct bnxt_re_dev *rdev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bnxt_re_add_unique_gid(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
struct bnxt_qplib_ctx *hctx = &rdev->qplib_ctx;
|
||||
struct bnxt_qplib_res *res = &rdev->qplib_res;
|
||||
int rc;
|
||||
|
||||
if (!rdev->rcfw.roce_mirror)
|
||||
return 0;
|
||||
|
||||
rdev->ugid.global.subnet_prefix = cpu_to_be64(0xfe8000000000abcdLL);
|
||||
addrconf_ifid_eui48(&rdev->ugid.raw[8], rdev->netdev);
|
||||
|
||||
rc = bnxt_qplib_add_sgid(&res->sgid_tbl,
|
||||
(struct bnxt_qplib_gid *)&rdev->ugid,
|
||||
rdev->qplib_res.netdev->dev_addr,
|
||||
0xFFFF, true, &rdev->ugid_index, true,
|
||||
hctx->stats3.fw_id);
|
||||
if (rc)
|
||||
dev_err(rdev_to_dev(rdev), "Failed to add unique GID. rc = %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr,
|
||||
struct ib_udata *udata)
|
||||
{
|
||||
@@ -1656,6 +1700,17 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr,
|
||||
}
|
||||
}
|
||||
|
||||
/* Support for RawEth QP is added to capture TCP pkt dump.
|
||||
* So unique SGID is used to avoid incorrect statistics on per
|
||||
* function stats_ctx
|
||||
*/
|
||||
if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE) {
|
||||
rc = bnxt_re_add_unique_gid(rdev);
|
||||
if (rc)
|
||||
goto qp_destroy;
|
||||
qp->qplib_qp.ugid_index = rdev->ugid_index;
|
||||
}
|
||||
|
||||
qp->ib_qp.qp_num = qp->qplib_qp.id;
|
||||
if (qp_init_attr->qp_type == IB_QPT_GSI)
|
||||
rdev->gsi_ctx.gsi_qp = qp;
|
||||
@@ -2301,7 +2356,7 @@ int bnxt_re_query_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
|
||||
qp_attr->pkey_index = qplib_qp->pkey_index;
|
||||
qp_attr->qkey = qplib_qp->qkey;
|
||||
qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE;
|
||||
rdma_ah_set_grh(&qp_attr->ah_attr, NULL, qplib_qp->ah.flow_label,
|
||||
rdma_ah_set_grh(&qp_attr->ah_attr, NULL, qplib_qp->udp_sport,
|
||||
qplib_qp->ah.host_sgid_index,
|
||||
qplib_qp->ah.hop_limit,
|
||||
qplib_qp->ah.traffic_class);
|
||||
@@ -3248,9 +3303,9 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
|
||||
IB_ACCESS_LOCAL_WRITE);
|
||||
if (IS_ERR(cq->resize_umem)) {
|
||||
rc = PTR_ERR(cq->resize_umem);
|
||||
ibdev_err(&rdev->ibdev, "%s: ib_umem_get failed! rc = %pe\n",
|
||||
__func__, cq->resize_umem);
|
||||
cq->resize_umem = NULL;
|
||||
ibdev_err(&rdev->ibdev, "%s: ib_umem_get failed! rc = %d\n",
|
||||
__func__, rc);
|
||||
goto fail;
|
||||
}
|
||||
cq->resize_cqe = entries;
|
||||
@@ -4392,6 +4447,93 @@ void bnxt_re_dealloc_ucontext(struct ib_ucontext *ib_uctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int bnxt_re_setup_vnic(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = bnxt_re_hwrm_alloc_vnic(rdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = bnxt_re_hwrm_cfg_vnic(rdev, qp->qplib_qp.id);
|
||||
if (rc)
|
||||
goto out_free_vnic;
|
||||
|
||||
return 0;
|
||||
out_free_vnic:
|
||||
bnxt_re_hwrm_free_vnic(rdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct ib_flow *bnxt_re_create_flow(struct ib_qp *ib_qp,
|
||||
struct ib_flow_attr *attr,
|
||||
struct ib_udata *udata)
|
||||
{
|
||||
struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
|
||||
struct bnxt_re_dev *rdev = qp->rdev;
|
||||
struct bnxt_re_flow *flow;
|
||||
int rc;
|
||||
|
||||
if (attr->type != IB_FLOW_ATTR_SNIFFER ||
|
||||
!rdev->rcfw.roce_mirror)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
mutex_lock(&rdev->qp_lock);
|
||||
if (rdev->sniffer_flow_created) {
|
||||
ibdev_err(&rdev->ibdev, "RoCE Mirroring is already Configured\n");
|
||||
mutex_unlock(&rdev->qp_lock);
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
|
||||
if (!flow) {
|
||||
mutex_unlock(&rdev->qp_lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
flow->rdev = rdev;
|
||||
|
||||
rc = bnxt_re_setup_vnic(rdev, qp);
|
||||
if (rc)
|
||||
goto out_free_flow;
|
||||
|
||||
rc = bnxt_qplib_create_flow(&rdev->qplib_res);
|
||||
if (rc)
|
||||
goto out_free_vnic;
|
||||
|
||||
rdev->sniffer_flow_created = 1;
|
||||
mutex_unlock(&rdev->qp_lock);
|
||||
|
||||
return &flow->ib_flow;
|
||||
|
||||
out_free_vnic:
|
||||
bnxt_re_hwrm_free_vnic(rdev);
|
||||
out_free_flow:
|
||||
mutex_unlock(&rdev->qp_lock);
|
||||
kfree(flow);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
int bnxt_re_destroy_flow(struct ib_flow *flow_id)
|
||||
{
|
||||
struct bnxt_re_flow *flow =
|
||||
container_of(flow_id, struct bnxt_re_flow, ib_flow);
|
||||
struct bnxt_re_dev *rdev = flow->rdev;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&rdev->qp_lock);
|
||||
rc = bnxt_qplib_destroy_flow(&rdev->qplib_res);
|
||||
if (rc)
|
||||
ibdev_dbg(&rdev->ibdev, "failed to destroy_flow rc = %d\n", rc);
|
||||
rdev->sniffer_flow_created = 0;
|
||||
|
||||
bnxt_re_hwrm_free_vnic(rdev);
|
||||
mutex_unlock(&rdev->qp_lock);
|
||||
kfree(flow);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct bnxt_re_cq *bnxt_re_search_for_cq(struct bnxt_re_dev *rdev, u32 cq_id)
|
||||
{
|
||||
struct bnxt_re_cq *cq = NULL, *tmp_cq;
|
||||
@@ -4604,7 +4746,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *
|
||||
return err;
|
||||
|
||||
err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_DPI,
|
||||
&dpi, sizeof(length));
|
||||
&dpi, sizeof(dpi));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -164,6 +164,11 @@ struct bnxt_re_user_mmap_entry {
|
||||
u8 mmap_flag;
|
||||
};
|
||||
|
||||
struct bnxt_re_flow {
|
||||
struct ib_flow ib_flow;
|
||||
struct bnxt_re_dev *rdev;
|
||||
};
|
||||
|
||||
static inline u16 bnxt_re_get_swqe_size(int nsge)
|
||||
{
|
||||
return sizeof(struct sq_send_hdr) + nsge * sizeof(struct sq_sge);
|
||||
@@ -267,6 +272,11 @@ struct ib_mr *bnxt_re_reg_user_mr_dmabuf(struct ib_pd *ib_pd, u64 start,
|
||||
struct uverbs_attr_bundle *attrs);
|
||||
int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata);
|
||||
void bnxt_re_dealloc_ucontext(struct ib_ucontext *context);
|
||||
struct ib_flow *bnxt_re_create_flow(struct ib_qp *ib_qp,
|
||||
struct ib_flow_attr *attr,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_destroy_flow(struct ib_flow *flow_id);
|
||||
|
||||
int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
|
||||
void bnxt_re_mmap_free(struct rdma_user_mmap_entry *rdma_entry);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user