net: mana: Per-vPort EQ and MSI-X interrupt management
Subsystems (5)
v4 cover net: mana: Per-vPort EQ and MSI-X interrupt management
This series adds per-vPort Event Queue (EQ) allocation and MSI-X interrupt management for the MANA driver. Previously, all vPorts shared a single set of EQs. This change enables dedicated EQs per vPort with support for both dedicated and shared MSI-X vector allocation modes.
Patch 1 moves EQ ownership from mana_context to per-vPort mana_port_context and exports create/destroy functions for the RDMA driver.
Patch 2 adds device capability queries to determine whether MSI-X vectors should be dedicated per-vPort or shared. When the number of available MSI-X vectors is insufficient for dedicated allocation, the driver enables sharing mode with bitmap-based vector assignment.
Patch 3 introduces the GIC (GDMA IRQ Context) abstraction with reference counting, allowing multiple EQs to safely share a single MSI-X vector.
Patch 4 converts the global EQ allocation in probe/resume to use the new GIC functions.
Patch 5 adds per-vPort GIC lifecycle management, calling get/put on each EQ creation and destruction during vPort open/close.
Patch 6 extends the same GIC lifecycle management to the RDMA driver's EQ allocation path.
Changes in v4:
- Rebased on net-next/main 7.0-rc4
- Patch 2: Use MANA_DEF_NUM_QUEUES instead of hardcoded 16 for max_num_queues clamping
- Patch 3: Track dyn_msix in GIC context instead of re-checking pci_msix_can_alloc_dyn() on each call; improved remove_irqs iteration to skip unallocated entries
Changes in v3:
- Rebased on net-next/main
- Patch 1: Added NULL check for mpc->eqs in mana_ib_create_qp_rss() to prevent NULL pointer dereference when RSS QP is created before a raw QP has configured the vport and allocated EQs
Changes in v2:
- Rebased on net-next/main (adapted to kzalloc_objs/kzalloc_obj macros, new GDMA_DRV_CAP_FLAG definitions)
- Patch 2: Fixed misleading comment for max_num_queues vs max_num_queues_vport in gdma.h
- Patch 3: Fixed spelling typo in gdma_main.c ("difference" -> "different")
Long Li (6):
net: mana: Create separate EQs for each vPort
net: mana: Query device capabilities and configure MSI-X sharing for
EQs
net: mana: Introduce GIC context with refcounting for interrupt
management
net: mana: Use GIC functions to allocate global EQs
net: mana: Allocate interrupt context for each EQ when creating vPort RDMA/mana_ib: Allocate interrupt contexts on EQs
drivers/infiniband/hw/mana/main.c | 47 ++- drivers/infiniband/hw/mana/qp.c | 16 +- .../net/ethernet/microsoft/mana/gdma_main.c | 307 +++++++++++++----- drivers/net/ethernet/microsoft/mana/mana_en.c | 162 +++++---- include/net/mana/gdma.h | 32 +- include/net/mana/mana.h | 7 +- 6 files changed, 416 insertions(+), 155 deletions(-)
Signature · 1 line
2.43.0
PATCH v4 1/6 net: mana: Create separate EQs for each vPort
To prepare for assigning vPorts to dedicated MSI-X vectors, remove EQ sharing among the vPorts and create dedicated EQs for each vPort.
Move the EQ definition from struct mana_context to struct mana_port_context and update related support functions. Export mana_create_eq() and mana_destroy_eq() for use by the MANA RDMA driver.
---
Changes in v3:
- Added NULL check for mpc->eqs in mana_ib_create_qp_rss() to prevent kernel crash when RSS QP is created before EQs are allocated
--- drivers/infiniband/hw/mana/main.c | 14 ++- drivers/infiniband/hw/mana/qp.c | 16 ++- drivers/net/ethernet/microsoft/mana/mana_en.c | 109 ++++++++++-------- include/net/mana/mana.h | 7 +- 4 files changed, 94 insertions(+), 52 deletions(-)
drivers/infiniband/hw/mana/main.c +11 -3
@@ -20,8 +20,10 @@ void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd, pd->vport_use_count--;WARN_ON (pd->vport_use_count <0 ); -if (!pd->vport_use_count) +if (!pd->vport_use_count) { +mana_destroy_eq (mpc);mana_uncfg_vport (mpc); + }mutex_unlock (&pd->vport_mutex); }
@@ -55,15 +57,21 @@ int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd,return err; } -mutex_unlock (&pd->vport_mutex); pd->tx_shortform_allowed = mpc->tx_shortform_allowed; pd->tx_vp_offset = mpc->tx_vp_offset; + err =mana_create_eq (mpc); +if (err) { +mana_uncfg_vport (mpc); + pd->vport_use_count--; + } + +mutex_unlock (&pd->vport_mutex);ibdev_dbg (&dev->ib_dev,"vport handle %llx pdid %x doorbell_id %x\n" , mpc->port_handle, pd->pdn, doorbell_id); -return 0 ; +return err; }int mana_ib_alloc_pd (struct ib_pd *ibpd,struct ib_udata *udata)
drivers/infiniband/hw/mana/qp.c +14 -2
@@ -188,7 +188,15 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, cq_spec.gdma_region = cq->queue.gdma_region; cq_spec.queue_size = cq->cqe *COMP_ENTRY_SIZE ; cq_spec.modr_ctx_id =0 ; - eq = &mpc->ac->eqs[cq->comp_vector]; +/* EQs are created when a raw QP configures the vport. +* A raw QP must be created before creating rwq_ind_tbl. +*/ +if (!mpc->eqs) { + ret = -EINVAL ; + i--; + goto fail; + } + eq = &mpc->eqs[cq->comp_vector % mpc->num_queues]; cq_spec.attached_eq = eq->eq->id; ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ,
@@ -340,7 +348,11 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, cq_spec.queue_size = send_cq->cqe *COMP_ENTRY_SIZE ; cq_spec.modr_ctx_id =0 ; eq_vec = send_cq->comp_vector; - eq = &mpc->ac->eqs[eq_vec]; +if (!mpc->eqs) { + err = -EINVAL ; + goto err_destroy_queue; + } + eq = &mpc->eqs[eq_vec % mpc->num_queues]; cq_spec.attached_eq = eq->eq->id; err = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_SQ, &wq_spec,
drivers/net/ethernet/microsoft/mana/mana_en.c +64 -45
262 lines not on this page · raw message
include/net/mana/mana.h +5 -2
@@ -480,8 +480,6 @@ struct mana_context {u8 bm_hostmode;struct mana_ethtool_hc_stats hc_stats; -struct mana_eq *eqs; -struct dentry *mana_eqs_debugfs;struct workqueue_struct *per_port_queue_reset_wq;/* Workqueue for querying hardware stats */ struct delayed_work gf_stats_work;
@@ -501,6 +499,9 @@ struct mana_port_context {u8 mac_addr[ETH_ALEN ]; +struct mana_eq *eqs; +struct dentry *mana_eqs_debugfs; +enum TRI_STATE rss_state;mana_handle_t default_rxobj;
@@ -1033,6 +1034,8 @@ void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type,int mana_cfg_vport (struct mana_port_context *apc,u32 protection_dom_id,u32 doorbell_pg_id);void mana_uncfg_vport (struct mana_port_context *apc); +int mana_create_eq (struct mana_port_context *apc); +void mana_destroy_eq (struct mana_port_context *apc); struct net_device *mana_get_primary_netdev(struct mana_context *ac, u32 port_index,
Signature · 1 line
2.43.0
PATCH v4 2/6 net: mana: Query device capabilities and configure MSI-X sharing for EQs
In reply to Long LiWhen querying the device, adjust the max number of queues to allow dedicated MSI-X vectors for each vPort. The number of queues per vPort is clamped to no less than MANA_DEF_NUM_QUEUES. MSI-X sharing among vPorts is disabled by default and is only enabled when there are not enough MSI-X vectors for dedicated allocation.
Rename mana_query_device_cfg() to mana_gd_query_device_cfg() as it is used at GDMA device probe time for querying device capabilities.
---
Changes in v4:
- Use MANA_DEF_NUM_QUEUES instead of hardcoded 16 for max_num_queues clamping
Changes in v2:
- Fixed misleading comment for max_num_queues vs max_num_queues_vport in gdma.h
--- .../net/ethernet/microsoft/mana/gdma_main.c | 66 ++++++++++++++++--- drivers/net/ethernet/microsoft/mana/mana_en.c | 36 +++++----- include/net/mana/gdma.h | 13 +++- 3 files changed, 91 insertions(+), 24 deletions(-)
drivers/net/ethernet/microsoft/mana/gdma_main.c +58 -8
@@ -124,6 +124,9 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)struct gdma_context *gc =pci_get_drvdata (pdev);struct gdma_query_max_resources_resp resp = {};struct gdma_general_req req = {}; +unsigned int max_num_queues; +u8 bm_hostmode; +u16 num_ports;int err; mana_gd_init_req_hdr(&req.hdr, GDMA_QUERY_MAX_RESOURCES,
@@ -169,6 +172,40 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)if (gc->max_num_queues > gc->num_msix_usable -1 ) gc->max_num_queues = gc->num_msix_usable -1 ; + err =mana_gd_query_device_cfg (gc,MANA_MAJOR_VERSION ,MANA_MINOR_VERSION , +MANA_MICRO_VERSION , &num_ports, &bm_hostmode); +if (err) +return err; + +if (!num_ports) +return -EINVAL ; + +/* +* Adjust gc->max_num_queues returned from the SOC to allow dedicated +* MSIx for each vPort. Clamp to no less than MANA_DEF_NUM_QUEUES. +*/ + max_num_queues = (gc->num_msix_usable -1 ) / num_ports; + max_num_queues =roundup_pow_of_two (max (max_num_queues,1U )); +if (max_num_queues <MANA_DEF_NUM_QUEUES ) + max_num_queues =MANA_DEF_NUM_QUEUES ; + +/* +* Use dedicated MSIx for EQs whenever possible, use MSIx sharing for +* Ethernet EQs when (max_num_queues * num_ports > num_msix_usable - 1) +*/ + max_num_queues =min (gc->max_num_queues, max_num_queues); +if (max_num_queues * num_ports > gc->num_msix_usable -1 ) + gc->msi_sharing = true; + +/* If MSI is shared, use max allowed value */ +if (gc->msi_sharing) + gc->max_num_queues_vport =min (gc->num_msix_usable -1 , gc->max_num_queues); +else + gc->max_num_queues_vport = max_num_queues; + +dev_info (gc->dev,"MSI sharing mode %d max queues %d\n" , + gc->msi_sharing, gc->max_num_queues); +return 0 ; }
@@ -1831,6 +1868,7 @@ static int mana_gd_setup_hwc_irqs(struct pci_dev *pdev)/* Need 1 interrupt for HWC */ max_irqs =min (num_online_cpus (),MANA_MAX_NUM_QUEUES ) +1 ; min_irqs =2 ; + gc->msi_sharing = true; } nvec =pci_alloc_irq_vectors (pdev, min_irqs, max_irqs,PCI_IRQ_MSIX );
@@ -1909,6 +1947,8 @@ static void mana_gd_remove_irqs(struct pci_dev *pdev)pci_free_irq_vectors (pdev); +bitmap_free (gc->msi_bitmap); + gc->msi_bitmap =NULL ; gc->max_num_msix =0 ; gc->num_msix_usable =0 ; }
@@ -1943,20 +1983,30 @@ static int mana_gd_setup(struct pci_dev *pdev)if (err) goto destroy_hwc; - err =mana_gd_query_max_resources (pdev); + err =mana_gd_detect_devices (pdev);if (err) goto destroy_hwc; - err =mana_gd_setup_remaining_irqs (pdev); -if (err) { -dev_err (gc->dev,"Failed to setup remaining IRQs: %d" , err); - goto destroy_hwc; - } - - err =mana_gd_detect_devices (pdev); + err =mana_gd_query_max_resources (pdev);if (err) goto destroy_hwc; +if (!gc->msi_sharing) { + gc->msi_bitmap =bitmap_zalloc (gc->num_msix_usable,GFP_KERNEL ); +if (!gc->msi_bitmap) { + err = -ENOMEM ; + goto destroy_hwc; + } +/* Set bit for HWC */ +set_bit (0 , gc->msi_bitmap); + }else { + err =mana_gd_setup_remaining_irqs (pdev); +if (err) { +dev_err (gc->dev,"Failed to setup remaining IRQs: %d" , err); + goto destroy_hwc; + } + } +dev_dbg (&pdev->dev,"mana gdma setup successful\n" );return 0 ;
drivers/net/ethernet/microsoft/mana/mana_en.c +21 -15
@@ -1000,10 +1000,9 @@ static int mana_init_port_context(struct mana_port_context *apc)return !apc->rxqs ? -ENOMEM :0 ; } -static int mana_send_request (struct mana_context *ac,void *in_buf, -u32 in_len,void *out_buf,u32 out_len) +static int gdma_mana_send_request (struct gdma_context *gc,void *in_buf, +u32 in_len,void *out_buf,u32 out_len) { -struct gdma_context *gc = ac->gdma_dev->gdma_context;struct gdma_resp_hdr *resp = out_buf;struct gdma_req_hdr *req = in_buf;struct device *dev = gc->dev;
@@ -1037,6 +1036,14 @@ static int mana_send_request(struct mana_context *ac, void *in_buf,return 0 ; } +static int mana_send_request (struct mana_context *ac,void *in_buf, +u32 in_len,void *out_buf,u32 out_len) +{ +struct gdma_context *gc = ac->gdma_dev->gdma_context; + +return gdma_mana_send_request (gc, in_buf, in_len, out_buf, out_len); +} +static int mana_verify_resp_hdr (const struct gdma_resp_hdr *resp_hdr,const enum mana_command_code expected_code,const u32 min_size)
@@ -1170,11 +1177,10 @@ static void mana_pf_deregister_filter(struct mana_port_context *apc) err, resp.hdr.status); } -static int mana_query_device_cfg (struct mana_context *ac,u32 proto_major_ver, -u32 proto_minor_ver,u32 proto_micro_ver, -u16 *max_num_vports,u8 *bm_hostmode) +int mana_gd_query_device_cfg (struct gdma_context *gc,u32 proto_major_ver, +u32 proto_minor_ver,u32 proto_micro_ver, +u16 *max_num_vports,u8 *bm_hostmode) { -struct gdma_context *gc = ac->gdma_dev->gdma_context;struct mana_query_device_cfg_resp resp = {};struct mana_query_device_cfg_req req = {};struct device *dev = gc->dev;
@@ -1189,7 +1195,7 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, req.proto_minor_ver = proto_minor_ver; req.proto_micro_ver = proto_micro_ver; - err =mana_send_request (ac, &req,sizeof (req), &resp,sizeof (resp)); + err =gdma_mana_send_request (gc, &req,sizeof (req), &resp,sizeof (resp));if (err) {dev_err (dev,"Failed to query config: %d" , err);return err;
@@ -1217,8 +1223,6 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver,else *bm_hostmode =0 ; -debugfs_create_u16 ("adapter-MTU" ,0400 , gc->mana_pci_debugfs, &gc->adapter_mtu); -return 0 ; }
@@ -3373,7 +3377,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,int err; ndev =alloc_etherdev_mq (sizeof (struct mana_port_context ), - gc->max_num_queues); + gc->max_num_queues_vport);if (!ndev)return -ENOMEM ;
@@ -3382,8 +3386,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, apc =netdev_priv (ndev); apc->ac = ac; apc->ndev = ndev; - apc->max_queues = gc->max_num_queues; - apc->num_queues =min (gc->max_num_queues,MANA_DEF_NUM_QUEUES ); + apc->max_queues = gc->max_num_queues_vport; + apc->num_queues =min (gc->max_num_queues_vport,MANA_DEF_NUM_QUEUES ); apc->tx_queue_size =DEF_TX_BUFFERS_PER_QUEUE ; apc->rx_queue_size =DEF_RX_BUFFERS_PER_QUEUE ; apc->port_handle =INVALID_MANA_HANDLE ;
@@ -3643,13 +3647,15 @@ int mana_probe(struct gdma_dev *gd, bool resuming) gd->driver_data = ac; } - err =mana_query_device_cfg (ac,MANA_MAJOR_VERSION ,MANA_MINOR_VERSION , -MANA_MICRO_VERSION , &num_ports, &bm_hostmode); + err =mana_gd_query_device_cfg (gc,MANA_MAJOR_VERSION ,MANA_MINOR_VERSION , +MANA_MICRO_VERSION , &num_ports, &bm_hostmode);if (err) goto out; ac->bm_hostmode = bm_hostmode; +debugfs_create_u16 ("adapter-MTU" ,0400 , gc->mana_pci_debugfs, &gc->adapter_mtu); +if (!resuming) { ac->num_ports = num_ports;
include/net/mana/gdma.h +12 -1
@@ -399,8 +399,10 @@ struct gdma_context {struct device *dev;struct dentry *mana_pci_debugfs; -/* Per-vPort max number of queues */ +/* Hardware max number of queues */ unsigned int max_num_queues; +/* Per-vPort max number of queues */ +unsigned int max_num_queues_vport;unsigned int max_num_msix;unsigned int num_msix_usable;struct xarray irq_contexts;
@@ -446,6 +448,12 @@ struct gdma_context {struct workqueue_struct *service_wq;unsigned long flags; + +/* Indicate if this device is sharing MSI for EQs on MANA */ +bool msi_sharing; + +/* Bitmap tracks where MSI is allocated when it is not shared for EQs */ +unsigned long *msi_bitmap; };static inline bool mana_gd_is_mana (struct gdma_dev *gd)
@@ -1013,4 +1021,7 @@ int mana_gd_resume(struct pci_dev *pdev);bool mana_need_log (struct gdma_context *gc,int err); +int mana_gd_query_device_cfg (struct gdma_context *gc,u32 proto_major_ver, +u32 proto_minor_ver,u32 proto_micro_ver, +u16 *max_num_vports,u8 *bm_hostmode);#endif /* _GDMA_H */
Signature · 1 line
2.43.0
PATCH v4 3/6 net: mana: Introduce GIC context with refcounting for interrupt management
In reply to Long LiTo allow Ethernet EQs to use dedicated or shared MSI-X vectors and RDMA EQs to share the same MSI-X, introduce a GIC (GDMA IRQ Context) with reference counting. This allows the driver to create an interrupt context on an assigned or unassigned MSI-X vector and share it across multiple EQ consumers.
---
Changes in v4:
- Track dyn_msix in GIC context instead of re-checking pci_msix_can_alloc_dyn() on each call
- Improved remove_irqs iteration to skip unallocated entries
Changes in v2:
- Fixed spelling typo in gdma_main.c ("difference" -> "different")
--- .../net/ethernet/microsoft/mana/gdma_main.c | 159 ++++++++++++++++++ include/net/mana/gdma.h | 11 ++ 2 files changed, 170 insertions(+)
drivers/net/ethernet/microsoft/mana/gdma_main.c +159 -0
@@ -1587,6 +1587,164 @@ static irqreturn_t mana_gd_intr(int irq, void *arg)return IRQ_HANDLED ; } +void mana_gd_put_gic (struct gdma_context *gc,bool use_msi_bitmap,int msi) +{ +struct pci_dev *dev =to_pci_dev (gc->dev); +struct msi_map irq_map; +struct gdma_irq_context *gic; +int irq; + +mutex_lock (&gc->gic_mutex); + + gic =xa_load (&gc->irq_contexts, msi); +if (WARN_ON (!gic)) { +mutex_unlock (&gc->gic_mutex); +return ; + } + +if (use_msi_bitmap) + gic->bitmap_refs--; + +if (use_msi_bitmap && gic->bitmap_refs ==0 ) +clear_bit (msi, gc->msi_bitmap); + +if (!refcount_dec_and_test (&gic->refcount)) + goto out; + + irq =pci_irq_vector (dev, msi); + +irq_update_affinity_hint (irq,NULL ); +free_irq (irq, gic); + +if (gic->dyn_msix) { + irq_map.virq = irq; + irq_map.index = msi; +pci_msix_free_irq (dev, irq_map); + } + +xa_erase (&gc->irq_contexts, msi); +kfree (gic); + +out: +mutex_unlock (&gc->gic_mutex); +} +EXPORT_SYMBOL_NS (mana_gd_put_gic,"NET_MANA" ); + +/* +* Get a GIC (GDMA IRQ Context) on a MSI vector +* a MSI can be shared between different EQs, this function supports setting +* up separate MSIs using a bitmap, or directly using the MSI index +* +* @use_msi_bitmap: +* True if MSI is assigned by this function on available slots from bitmap. +* False if MSI is passed from *msi_requested +*/ +struct gdma_irq_context *mana_gd_get_gic (struct gdma_context *gc, +bool use_msi_bitmap, +int *msi_requested) +{ +struct gdma_irq_context *gic; +struct pci_dev *dev =to_pci_dev (gc->dev); +struct msi_map irq_map = { }; +int irq; +int msi; +int err; + +mutex_lock (&gc->gic_mutex); + +if (use_msi_bitmap) { + msi =find_first_zero_bit (gc->msi_bitmap, gc->num_msix_usable); +if (msi >= gc->num_msix_usable) { +dev_err (gc->dev,"No free MSI vectors available\n" ); + gic =NULL ; + goto out; + } + *msi_requested = msi; + }else { + msi = *msi_requested; + } + + gic =xa_load (&gc->irq_contexts, msi); +if (gic) { +refcount_inc (&gic->refcount); +if (use_msi_bitmap) { + gic->bitmap_refs++; +set_bit (msi, gc->msi_bitmap); + } + goto out; + } + + irq =pci_irq_vector (dev, msi); +if (irq == -EINVAL ) { + irq_map =pci_msix_alloc_irq_at (dev, msi,NULL ); +if (!irq_map.virq) { + err = irq_map.index; +dev_err (gc->dev, +"Failed to alloc irq_map msi %d err %d\n" , + msi, err); + gic =NULL ; + goto out; + } + irq = irq_map.virq; + msi = irq_map.index; + } + + gic =kzalloc (sizeof (*gic),GFP_KERNEL ); +if (!gic) { +if (irq_map.virq) +pci_msix_free_irq (dev, irq_map); + goto out; + } + + gic->handler = mana_gd_process_eq_events; + gic->msi = msi; + gic->irq = irq; +INIT_LIST_HEAD (&gic->eq_list); +spin_lock_init (&gic->lock); + +if (!gic->msi) +snprintf (gic->name,MANA_IRQ_NAME_SZ ,"mana_hwc@pci:%s" , +pci_name (dev)); +else +snprintf (gic->name,MANA_IRQ_NAME_SZ ,"mana_msi%d@pci:%s" , + gic->msi,pci_name (dev)); + + err =request_irq (irq, mana_gd_intr,0 , gic->name, gic); +if (err) { +dev_err (gc->dev,"Failed to request irq %d %s\n" , + irq, gic->name); +kfree (gic); + gic =NULL ; +if (irq_map.virq) +pci_msix_free_irq (dev, irq_map); + goto out; + } + + gic->dyn_msix = !!irq_map.virq; +refcount_set (&gic->refcount,1 ); + gic->bitmap_refs = use_msi_bitmap ?1 :0 ; + + err =xa_err (xa_store (&gc->irq_contexts, msi, gic,GFP_KERNEL )); +if (err) { +dev_err (gc->dev,"Failed to store irq context for msi %d: %d\n" , + msi, err); +free_irq (irq, gic); +kfree (gic); + gic =NULL ; +if (irq_map.virq) +pci_msix_free_irq (dev, irq_map); + goto out; + } + +if (use_msi_bitmap) +set_bit (msi, gc->msi_bitmap); + +out: +mutex_unlock (&gc->gic_mutex); +return gic; +} +EXPORT_SYMBOL_NS (mana_gd_get_gic,"NET_MANA" ); +int mana_gd_alloc_res_map (u32 res_avail,struct gdma_resource *r) { r->map =bitmap_zalloc (res_avail,GFP_KERNEL );
@@ -2076,6 +2234,7 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto release_region;mutex_init (&gc->eq_test_event_mutex); +mutex_init (&gc->gic_mutex);pci_set_drvdata (pdev, gc); gc->bar0_pa =pci_resource_start (pdev,0 ); gc->bar0_size =pci_resource_len (pdev,0 );
include/net/mana/gdma.h +11 -0
@@ -388,6 +388,11 @@ struct gdma_irq_context {spinlock_t lock;struct list_head eq_list;char name[MANA_IRQ_NAME_SZ ]; +unsigned int msi; +unsigned int irq; +refcount_t refcount; +unsigned int bitmap_refs; +bool dyn_msix; };enum gdma_context_flags {
@@ -449,6 +454,9 @@ struct gdma_context {unsigned long flags; +/* Protect access to GIC context */ +struct mutex gic_mutex; +/* Indicate if this device is sharing MSI for EQs on MANA */ bool msi_sharing;
@@ -1021,6 +1029,9 @@ int mana_gd_resume(struct pci_dev *pdev);bool mana_need_log (struct gdma_context *gc,int err); +struct gdma_irq_context *mana_gd_get_gic (struct gdma_context *gc,bool use_msi_bitmap, +int *msi_requested); +void mana_gd_put_gic (struct gdma_context *gc,bool use_msi_bitmap,int msi);int mana_gd_query_device_cfg (struct gdma_context *gc,u32 proto_major_ver,u32 proto_minor_ver,u32 proto_micro_ver,u16 *max_num_vports,u8 *bm_hostmode);
Signature · 1 line
2.43.0
PATCH v4 4/6 net: mana: Use GIC functions to allocate global EQs
In reply to Long LiReplace the GDMA global interrupt setup code with the new GIC allocation and release functions for managing interrupt contexts.
--- .../net/ethernet/microsoft/mana/gdma_main.c | 80 +++---------------- 1 file changed, 10 insertions(+), 70 deletions(-)
drivers/net/ethernet/microsoft/mana/gdma_main.c +10 -70
@@ -1860,30 +1860,13 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec)* further used in irq_setup() */ for (i =1 ; i <= nvec; i++) { - gic =kzalloc_obj (*gic); + gic =mana_gd_get_gic (gc, false, &i);if (!gic) { err = -ENOMEM ; goto free_irq; } - gic->handler = mana_gd_process_eq_events; -INIT_LIST_HEAD (&gic->eq_list); -spin_lock_init (&gic->lock); - -snprintf (gic->name,MANA_IRQ_NAME_SZ ,"mana_q%d@pci:%s" , - i -1 ,pci_name (pdev)); - -/* one pci vector is already allocated for HWC */ - irqs[i -1 ] =pci_irq_vector (pdev, i); -if (irqs[i -1 ] <0 ) { - err = irqs[i -1 ]; - goto free_current_gic; - } - - err =request_irq (irqs[i -1 ], mana_gd_intr,0 , gic->name, gic); -if (err) - goto free_current_gic; -xa_store (&gc->irq_contexts, i, gic,GFP_KERNEL ); + irqs[i -1 ] = gic->irq; }/*
@@ -1905,19 +1888,11 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec)kfree (irqs);return 0 ; -free_current_gic: -kfree (gic); free_irq:for (i -=1 ; i >0 ; i--) { irq =pci_irq_vector (pdev, i); - gic =xa_load (&gc->irq_contexts, i); -if (WARN_ON (!gic)) -continue ; -irq_update_affinity_hint (irq,NULL ); -free_irq (irq, gic); -xa_erase (&gc->irq_contexts, i); -kfree (gic); +mana_gd_put_gic (gc, false, i); }kfree (irqs);return err;
@@ -1938,34 +1913,13 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev, int nvec) start_irqs = irqs;for (i =0 ; i < nvec; i++) { - gic =kzalloc_obj (*gic); + gic =mana_gd_get_gic (gc, false, &i);if (!gic) { err = -ENOMEM ; goto free_irq; } - gic->handler = mana_gd_process_eq_events; -INIT_LIST_HEAD (&gic->eq_list); -spin_lock_init (&gic->lock); - -if (!i) -snprintf (gic->name,MANA_IRQ_NAME_SZ ,"mana_hwc@pci:%s" , -pci_name (pdev)); -else -snprintf (gic->name,MANA_IRQ_NAME_SZ ,"mana_q%d@pci:%s" , - i -1 ,pci_name (pdev)); - - irqs[i] =pci_irq_vector (pdev, i); -if (irqs[i] <0 ) { - err = irqs[i]; - goto free_current_gic; - } - - err =request_irq (irqs[i], mana_gd_intr,0 , gic->name, gic); -if (err) - goto free_current_gic; - -xa_store (&gc->irq_contexts, i, gic,GFP_KERNEL ); + irqs[i] = gic->irq; }/* If number of IRQ is one extra than number of online CPUs,
@@ -1994,19 +1948,11 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev, int nvec)kfree (start_irqs);return 0 ; -free_current_gic: -kfree (gic); free_irq:for (i -=1 ; i >=0 ; i--) { irq =pci_irq_vector (pdev, i); - gic =xa_load (&gc->irq_contexts, i); -if (WARN_ON (!gic)) -continue ; -irq_update_affinity_hint (irq,NULL ); -free_irq (irq, gic); -xa_erase (&gc->irq_contexts, i); -kfree (gic); +mana_gd_put_gic (gc, false, i); }kfree (start_irqs);
@@ -2081,26 +2027,20 @@ static int mana_gd_setup_remaining_irqs(struct pci_dev *pdev)static void mana_gd_remove_irqs (struct pci_dev *pdev) {struct gdma_context *gc =pci_get_drvdata (pdev); -struct gdma_irq_context *gic;int irq, i;if (gc->max_num_msix <1 )return ;for (i =0 ; i < gc->max_num_msix; i++) { - irq =pci_irq_vector (pdev, i); -if (irq <0 ) -continue ; - - gic =xa_load (&gc->irq_contexts, i); -if (WARN_ON (!gic)) +if (!xa_load (&gc->irq_contexts, i))continue ;/* Need to clear the hint before free_irq */ + irq =pci_irq_vector (pdev, i);irq_update_affinity_hint (irq,NULL ); -free_irq (irq, gic); -xa_erase (&gc->irq_contexts, i); -kfree (gic); + +mana_gd_put_gic (gc, false, i); }pci_free_irq_vectors (pdev);
Signature · 1 line
2.43.0
PATCH v4 5/6 net: mana: Allocate interrupt context for each EQ when creating vPort
In reply to Long LiUse GIC functions to create a dedicated interrupt context or acquire a shared interrupt context for each EQ when setting up a vPort.
--- drivers/net/ethernet/microsoft/mana/gdma_main.c | 2 +- drivers/net/ethernet/microsoft/mana/mana_en.c | 17 ++++++++++++++++- include/net/mana/gdma.h | 1 + 3 files changed, 18 insertions(+), 2 deletions(-)
drivers/net/ethernet/microsoft/mana/gdma_main.c +1 -1
@@ -826,7 +826,6 @@ static void mana_gd_deregister_irq(struct gdma_queue *queue) }spin_unlock_irqrestore (&gic->lock, flags); - queue->eq.msix_index =INVALID_PCI_MSIX_INDEX ;synchronize_rcu (); }
@@ -941,6 +940,7 @@ static int mana_gd_create_eq(struct gdma_dev *gd, out:dev_err (dev,"Failed to create EQ: %d\n" , err);mana_gd_destroy_eq (gc, false, queue); + queue->eq.msix_index =INVALID_PCI_MSIX_INDEX ;return err; }
drivers/net/ethernet/microsoft/mana/mana_en.c +16 -1
@@ -1606,6 +1606,7 @@ void mana_destroy_eq(struct mana_port_context *apc)struct gdma_context *gc = ac->gdma_dev->gdma_context;struct gdma_queue *eq;int i; +unsigned int msi;if (!apc->eqs)return ;
@@ -1618,7 +1619,9 @@ void mana_destroy_eq(struct mana_port_context *apc)if (!eq)continue ; + msi = eq->eq.msix_index;mana_gd_destroy_queue (gc, eq); +mana_gd_put_gic (gc, !gc->msi_sharing, msi); }kfree (apc->eqs);
@@ -1635,6 +1638,7 @@ static void mana_create_eq_debugfs(struct mana_port_context *apc, int i) eq.mana_eq_debugfs =debugfs_create_dir (eqnum, apc->mana_eqs_debugfs);debugfs_create_u32 ("head" ,0400 , eq.mana_eq_debugfs, &eq.eq->head);debugfs_create_u32 ("tail" ,0400 , eq.mana_eq_debugfs, &eq.eq->tail); +debugfs_create_u32 ("irq" ,0400 , eq.mana_eq_debugfs, &eq.eq->eq.irq);debugfs_create_file ("eq_dump" ,0400 , eq.mana_eq_debugfs, eq.eq, &mana_dbg_q_fops); }
@@ -1645,6 +1649,7 @@ int mana_create_eq(struct mana_port_context *apc)struct gdma_queue_spec spec = {};int err;int i; +struct gdma_irq_context *gic;WARN_ON (apc->eqs); apc->eqs = kzalloc_objs(struct mana_eq, apc->num_queues);
@@ -1661,12 +1666,22 @@ int mana_create_eq(struct mana_port_context *apc) apc->mana_eqs_debugfs =debugfs_create_dir ("EQs" , apc->mana_port_debugfs);for (i =0 ; i < apc->num_queues; i++) { - spec.eq.msix_index = (i +1 ) % gc->num_msix_usable; +if (gc->msi_sharing) + spec.eq.msix_index = (i +1 ) % gc->num_msix_usable; + + gic =mana_gd_get_gic (gc, !gc->msi_sharing, &spec.eq.msix_index); +if (!gic) { + err = -ENOMEM ; + goto out; + } + err =mana_gd_create_mana_eq (gd, &spec, &apc->eqs[i].eq);if (err) {dev_err (gc->dev,"Failed to create EQ %d : %d\n" , i, err); +mana_gd_put_gic (gc, !gc->msi_sharing, spec.eq.msix_index); goto out; } + apc->eqs[i].eq->eq.irq = gic->irq;mana_create_eq_debugfs (apc, i); }
include/net/mana/gdma.h +1 -0
@@ -342,6 +342,7 @@ struct gdma_queue {void *context;unsigned int msix_index; +unsigned int irq;u32 log2_throttle_limit; } eq;
Signature · 1 line
2.43.0
PATCH v4 6/6 RDMA/mana_ib: Allocate interrupt contexts on EQs
In reply to Long LiUse the GIC functions to allocate interrupt contexts for RDMA EQs. These interrupt contexts may be shared with Ethernet EQs when MSI-X vectors are limited.
The driver now supports allocating dedicated MSI-X for each EQ. Indicate this capability through driver capability bits.
--- drivers/infiniband/hw/mana/main.c | 33 ++++++++++++++++++++++++++----- include/net/mana/gdma.h | 7 +++++-- 2 files changed, 33 insertions(+), 7 deletions(-)
drivers/infiniband/hw/mana/main.c +28 -5
@@ -787,6 +787,7 @@ int mana_ib_create_eqs(struct mana_ib_dev *mdev) {struct gdma_context *gc =mdev_to_gc (mdev);struct gdma_queue_spec spec = {}; +struct gdma_irq_context *gic;int err, i; spec.type =GDMA_EQ ;
@@ -797,9 +798,15 @@ int mana_ib_create_eqs(struct mana_ib_dev *mdev) spec.eq.log2_throttle_limit =LOG2_EQ_THROTTLE ; spec.eq.msix_index =0 ; + gic =mana_gd_get_gic (gc, false, &spec.eq.msix_index); +if (!gic) +return -ENOMEM ; + err =mana_gd_create_mana_eq (mdev->gdma_dev, &spec, &mdev->fatal_err_eq); -if (err) +if (err) { +mana_gd_put_gic (gc, false,0 );return err; + } mdev->eqs = kzalloc_objs(struct gdma_queue *, mdev->ib_dev.num_comp_vectors);
@@ -810,31 +817,47 @@ int mana_ib_create_eqs(struct mana_ib_dev *mdev) spec.eq.callback =NULL ;for (i =0 ; i < mdev->ib_dev.num_comp_vectors; i++) { spec.eq.msix_index = (i +1 ) % gc->num_msix_usable; + + gic =mana_gd_get_gic (gc, false, &spec.eq.msix_index); +if (!gic) { + err = -ENOMEM ; + goto destroy_eqs; + } + err =mana_gd_create_mana_eq (mdev->gdma_dev, &spec, &mdev->eqs[i]); -if (err) +if (err) { +mana_gd_put_gic (gc, false, spec.eq.msix_index); goto destroy_eqs; + } }return 0 ; destroy_eqs: -while (i-- >0 ) +while (i-- >0 ) {mana_gd_destroy_queue (gc, mdev->eqs[i]); +mana_gd_put_gic (gc, false, (i +1 ) % gc->num_msix_usable); + }kfree (mdev->eqs); destroy_fatal_eq:mana_gd_destroy_queue (gc, mdev->fatal_err_eq); +mana_gd_put_gic (gc, false,0 );return err; }void mana_ib_destroy_eqs (struct mana_ib_dev *mdev) {struct gdma_context *gc =mdev_to_gc (mdev); -int i; +int i, msi;mana_gd_destroy_queue (gc, mdev->fatal_err_eq); +mana_gd_put_gic (gc, false,0 ); -for (i =0 ; i < mdev->ib_dev.num_comp_vectors; i++) +for (i =0 ; i < mdev->ib_dev.num_comp_vectors; i++) {mana_gd_destroy_queue (gc, mdev->eqs[i]); + msi = (i +1 ) % gc->num_msix_usable; +mana_gd_put_gic (gc, false, msi); + }kfree (mdev->eqs); }
include/net/mana/gdma.h +5 -2
@@ -615,6 +615,7 @@ enum {#define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG BIT(3)#define GDMA_DRV_CAP_FLAG_1_GDMA_PAGES_4MB_1GB_2GB BIT(4)#define GDMA_DRV_CAP_FLAG_1_VARIABLE_INDIRECTION_TABLE_SUPPORT BIT(5) +#define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)/* Driver can handle holes (zeros) in the device list */ #define GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP BIT(11)
@@ -631,7 +632,8 @@ enum {/* Driver detects stalled send queues and recovers them */ #define GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY BIT(18) -#define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6) +/* Driver supports separate EQ/MSIs for each vPort */ +#define GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT BIT(19)/* Driver supports linearizing the skb when num_sge exceeds hardware limit */ #define GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE BIT(20)
@@ -659,7 +661,8 @@ enum {GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \ - GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY) +GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \ + GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT) #define GDMA_DRV_CAP_FLAGS2 0
Signature · 1 line
2.43.0
Simon Horman
reviewerQuoted 4 lines · Long Li
This series adds per-vPort Event Queue (EQ) allocation and MSI-X interrupt management for the MANA driver. Previously, all vPorts shared a single set of EQs. This change enables dedicated EQs per vPort with support for both dedicated and shared MSI-X vector allocation modes.
...
Hi Long Li,
Unfortunately this series did not apply to net-next cleanly. Which breaks our CI.
Please rebase and repost.
Thanks!
Signature · 1 line
pw-bot: changes-requested
Quoted 26 lines
-----Original Message-----
From: Simon Horman <[email protected]>
Sent: Monday, March 23, 2026 6:44 AM
To: Long Li <[email protected]>
Cc: Konstantin Taranov <[email protected]>; Jakub Kicinski <[email protected]>; David S . Miller <[email protected]>; Paolo Abeni <[email protected]>; Eric Dumazet <[email protected]>; Andrew Lunn <[email protected]>; Jason Gunthorpe <[email protected]>; Leon Romanovsky <[email protected]>; Haiyang Zhang <[email protected]>; KY Srinivasan <[email protected]>; Wei Liu <[email protected]>; Dexuan Cui <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]
Subject: [EXTERNAL] Re: [PATCH net-next v4 0/6] net: mana: Per-vPort EQ and MSI-X interrupt managementQuoted 4 lines · Long Li
This series adds per-vPort Event Queue (EQ) allocation and MSI-X interrupt management for the MANA driver. Previously, all vPorts shared a single set of EQs. This change enables dedicated EQs per vPort with support for both dedicated and shared MSI-X vector allocation
modes.
...
Quoted 8 lines
Hi Long Li,
Unfortunately this series did not apply to net-next cleanly. Which breaks our CI.
Please rebase and repost.
Thanks!
I have sent v5 of the patch set.
Please apply the patch set after this patch "net: mana: Set default number of queues to 16"
Thank you,
Long