The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b15491b4773af99ce2470144ef6bcd9146cc9a98

commit b15491b4773af99ce2470144ef6bcd9146cc9a98
Author:     Bjoern A. Zeeb <b...@freebsd.org>
AuthorDate: 2023-01-27 15:34:42 +0000
Commit:     Bjoern A. Zeeb <b...@freebsd.org>
CommitDate: 2023-02-05 20:49:06 +0000

    LinuxKPI: PCI: implement support for more than 1 MSI vector
    
    Following e9715b1c4474333ff119aba3a9a74bff91f72372 and
    4b56afaf7bf4fa37bae5b26fd93ee1ff5969c1bb, implement support
    for up-to 32 MSI vectors.  This is used by wireless drivers.
    This also switches msi_desc to an array in order to store
    per-vector information.
    
    Sponsored by:   The FreeBSD Foundation
    Discussed with: grehan (in Dec)
    MFC after:      3 days
    Reviewed by:    jhb
    Differential Revision: https://reviews.freebsd.org/D38222
---
 sys/compat/linuxkpi/common/include/linux/pci.h | 40 +++++++++++++++++---------
 sys/compat/linuxkpi/common/src/linux_pci.c     | 32 ++++++++++++++++-----
 2 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h 
b/sys/compat/linuxkpi/common/include/linux/pci.h
index e722b77261c0..596241525904 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -333,11 +333,7 @@ struct pci_dev {
        bool                    msix_enabled;
        phys_addr_t             rom;
        size_t                  romlen;
-       /*
-        * msi_desc should be an array one day? For as long as we only support
-        * 1 MSI vector this is fine.
-        */
-       struct msi_desc         *msi_desc;
+       struct msi_desc         **msi_desc;
 
        TAILQ_HEAD(, pci_mmio_region)   mmio;
 };
@@ -889,28 +885,44 @@ pci_enable_msix_range(struct pci_dev *dev, struct 
msix_entry *entries,
   linux_pci_enable_msi(pdev)
 
 static inline int
-pci_enable_msi(struct pci_dev *pdev)
+_lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec)
 {
        struct resource_list_entry *rle;
        int error;
-       int avail;
+       int nvec;
 
-       avail = pci_msi_count(pdev->dev.bsddev);
-       if (avail < 1)
-               return -EINVAL;
+       if (maxvec < minvec)
+               return (-EINVAL);
 
-       avail = 1;      /* this function only enable one MSI IRQ */
-       if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0)
+       nvec = pci_msi_count(pdev->dev.bsddev);
+       if (nvec < 1 || nvec < minvec)
+               return (-ENOSPC);
+
+       nvec = min(nvec, maxvec);
+       if ((error = -pci_alloc_msi(pdev->dev.bsddev, &nvec)) != 0)
                return error;
 
+       /* Native PCI might only ever ask for 32 vectors. */
+       if (nvec < minvec) {
+               pci_release_msi(pdev->dev.bsddev);
+               return (-ENOSPC);
+       }
+
        rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
        pdev->dev.irq_start = rle->start;
-       pdev->dev.irq_end = rle->start + avail;
+       pdev->dev.irq_end = rle->start + nvec;
        pdev->irq = rle->start;
        pdev->msi_enabled = true;
        return (0);
 }
 
+static inline int
+pci_enable_msi(struct pci_dev *pdev)
+{
+
+       return (_lkpi_pci_enable_msi_range(pdev, 1, 1));
+}
+
 static inline int
 pci_channel_offline(struct pci_dev *pdev)
 {
@@ -1611,7 +1623,7 @@ err:
 /*
  * We cannot simply re-define pci_get_device() as we would normally do
  * and then hide it in linux_pci.c as too many semi-native drivers still
- * inlucde linux/pci.h and run into the conflict with native PCI. Linux drivers
+ * include linux/pci.h and run into the conflict with native PCI. Linux drivers
  * using pci_get_device() need to be changed to call linuxkpi_pci_get_device().
  */
 static inline struct pci_dev *
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c 
b/sys/compat/linuxkpi/common/src/linux_pci.c
index 0d5b3ce52ff5..9db95e1f337d 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -320,6 +320,11 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
        pdev->dev.parent = &linux_root_device;
        pdev->dev.release = lkpi_pci_dev_release;
        INIT_LIST_HEAD(&pdev->dev.irqents);
+
+       if (pci_msi_count(dev) > 0)
+               pdev->msi_desc = malloc(pci_msi_count(dev) *
+                   sizeof(*pdev->msi_desc), M_DEVBUF, M_WAITOK | M_ZERO);
+
        kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
        kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
        kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
@@ -332,6 +337,7 @@ static void
 lkpinew_pci_dev_release(struct device *dev)
 {
        struct pci_dev *pdev;
+       int i;
 
        pdev = to_pci_dev(dev);
        if (pdev->root != NULL)
@@ -339,8 +345,11 @@ lkpinew_pci_dev_release(struct device *dev)
        if (pdev->bus->self != pdev)
                pci_dev_put(pdev->bus->self);
        free(pdev->bus, M_DEVBUF);
-       if (pdev->msi_desc != NULL)
+       if (pdev->msi_desc != NULL) {
+               for (i = pci_msi_count(pdev->dev.bsddev) - 1; i >= 0; i--)
+                       free(pdev->msi_desc[i], M_DEVBUF);
                free(pdev->msi_desc, M_DEVBUF);
+       }
        free(pdev, M_DEVBUF);
 }
 
@@ -952,10 +961,7 @@ out:
        if (flags & PCI_IRQ_MSI) {
                if (pci_msi_count(pdev->dev.bsddev) < minv)
                        return (-ENOSPC);
-               /* We only support 1 vector in pci_enable_msi() */
-               if (minv != 1)
-                       return (-ENOSPC);
-               error = pci_enable_msi(pdev);
+               error = _lkpi_pci_enable_msi_range(pdev, minv, maxv);
                if (error == 0 && pdev->msi_enabled)
                        return (pdev->dev.irq_end - pdev->dev.irq_start);
        }
@@ -975,14 +981,24 @@ lkpi_pci_msi_desc_alloc(int irq)
        struct msi_desc *desc;
        struct pci_devinfo *dinfo;
        struct pcicfg_msi *msi;
+       int vec;
 
        dev = linux_pci_find_irq_dev(irq);
        if (dev == NULL)
                return (NULL);
 
        pdev = to_pci_dev(dev);
-       if (pdev->msi_desc != NULL)
-               return (pdev->msi_desc);
+
+       if (pdev->msi_desc == NULL)
+               return (NULL);
+
+       if (irq < pdev->dev.irq_start || irq >= pdev->dev.irq_end)
+               return (NULL);
+
+       vec = pdev->dev.irq_start - irq;
+
+       if (pdev->msi_desc[vec] != NULL)
+               return (pdev->msi_desc[vec]);
 
        dinfo = device_get_ivars(dev->bsddev);
        msi = &dinfo->cfg.msi;
@@ -993,6 +1009,8 @@ lkpi_pci_msi_desc_alloc(int irq)
           (msi->msi_ctrl & PCIM_MSICTRL_64BIT) ? true : false;
        desc->msg.data = msi->msi_data;
 
+       pdev->msi_desc[vec] = desc;
+
        return (desc);
 }
 

Reply via email to