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:
Linus Torvalds
2025-10-03 18:35:22 -07:00
128 changed files with 16181 additions and 1481 deletions
@@ -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
+9
View File
@@ -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
+1
View File
@@ -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"
+40 -45
View File
@@ -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);
+1 -2
View File
@@ -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;
}
+2 -2
View File
@@ -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)
+134 -2
View File
@@ -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);
+3 -1
View File
@@ -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 {
+1 -1
View File
@@ -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.
+270 -13
View File
@@ -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;
+119 -1
View File
@@ -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,
+1
View File
@@ -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/
+15 -4
View File
@@ -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
+37
View File
@@ -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++) {
+34 -75
View File
@@ -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:
+3 -23
View File
@@ -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
};
+149 -7
View File
@@ -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;
+10
View File
@@ -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