When 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 16. 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.

Signed-off-by: Long Li <[email protected]>
---
 .../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(-)

diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c 
b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 0055c231acf6..62e3a2eb68e0 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -107,6 +107,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,
@@ -152,6 +155,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. Reduce max_num_queues to no less than 16 if necessary
+        */
+       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 < 16)
+               max_num_queues = 16;
+
+       /*
+        * 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;
 }
 
@@ -1802,6 +1839,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);
@@ -1880,6 +1918,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;
 }
@@ -1911,20 +1951,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;
 
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c 
b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 566e45a66adf..1e65670feb17 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1002,10 +1002,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;
@@ -1039,6 +1038,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)
@@ -1172,11 +1179,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;
@@ -1191,7 +1197,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;
@@ -1219,8 +1225,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;
 }
 
@@ -3334,7 +3338,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;
 
@@ -3343,8 +3347,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 = gc->max_num_queues;
+       apc->max_queues = gc->max_num_queues_vport;
+       apc->num_queues = gc->max_num_queues_vport;
        apc->tx_queue_size = DEF_TX_BUFFERS_PER_QUEUE;
        apc->rx_queue_size = DEF_RX_BUFFERS_PER_QUEUE;
        apc->port_handle = INVALID_MANA_HANDLE;
@@ -3596,13 +3600,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;
 
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 766f4fb25e26..477b751f124e 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -392,8 +392,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;
@@ -438,6 +440,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)
@@ -999,4 +1007,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 */
-- 
2.43.0


Reply via email to