The branch main has been updated by andrew:

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

commit 68e6422c6c91170a615e77028683a157e8e39d05
Author:     Andrew Turner <[email protected]>
AuthorDate: 2025-11-18 18:00:30 +0000
Commit:     Andrew Turner <[email protected]>
CommitDate: 2025-11-18 18:00:30 +0000

    dev/fdt: Add support for non-PCI MSI interrupts
    
    Some non-PCI devices can send interrupts, e.g. the Arm SMMU or GICv5
    Interrupt Wire Bridge. Add support for these by implementing pci_get_id
    and pci_alloc_msi and the MSI/MSI-X parts of the PCIB interface.
    
    Only the MSI parts of the PCI interface are added as that is all I am
    able to test.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D53330
---
 sys/dev/fdt/simplebus.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index a301fb0f247c..3e77f13104ff 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -40,6 +40,9 @@
 
 #include <dev/fdt/simplebus.h>
 
+#include "pci_if.h"
+#include "pcib_if.h"
+
 /*
  * Bus interface.
  */
@@ -62,6 +65,21 @@ static ssize_t               simplebus_get_property(device_t 
bus, device_t child,
 static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus,
     device_t child);
 
+/*
+ * PCI interface for MSI interrupts
+ */
+static pci_get_id_t simplebus_get_id;
+static pci_alloc_msi_t simplebus_alloc_msi;
+
+/*
+ * PCIB interface
+ */
+static pcib_alloc_msi_t simplebus_pcib_alloc_msi;
+static pcib_release_msi_t simplebus_pcib_release_msi;
+static pcib_alloc_msix_t simplebus_pcib_alloc_msix;
+static pcib_release_msix_t simplebus_pcib_release_msix;
+static pcib_map_msi_t simplebus_pcib_map_msi;
+
 /*
  * Driver methods.
  */
@@ -105,6 +123,17 @@ static device_method_t     simplebus_methods[] = {
        DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
        DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
 
+       /* PCI interface for MSI interrupts */
+       DEVMETHOD(pci_get_id,           simplebus_get_id),
+       DEVMETHOD(pci_alloc_msi,        simplebus_alloc_msi),
+
+       /* PCIB interface */
+       DEVMETHOD(pcib_alloc_msi,       simplebus_pcib_alloc_msi),
+       DEVMETHOD(pcib_release_msi,     simplebus_pcib_release_msi),
+       DEVMETHOD(pcib_alloc_msix,      simplebus_pcib_alloc_msix),
+       DEVMETHOD(pcib_release_msix,    simplebus_pcib_release_msix),
+       DEVMETHOD(pcib_map_msi,         simplebus_pcib_map_msi),
+
        DEVMETHOD_END
 };
 
@@ -534,3 +563,108 @@ simplebus_print_child(device_t bus, device_t child)
        rv += bus_print_child_footer(bus, child);
        return (rv);
 }
+
+static int
+simplebus_get_id(device_t dev, device_t child, enum pci_id_type type,
+    uintptr_t *id)
+{
+       phandle_t node, xref;
+       pcell_t *cells;
+       uintptr_t rid;
+       int error, ncells;
+
+       if (type != PCI_ID_MSI)
+               return (EINVAL);
+
+       node = ofw_bus_get_node(child);
+       error = ofw_bus_parse_xref_list_alloc(node, "msi-parent", "#msi-cells",
+           0, &xref, &ncells, &cells);
+       if (error != 0)
+               return (error);
+
+       rid = 0;
+       if (ncells > 0)
+               rid = cells[0];
+
+       *id = rid;
+       return (0);
+}
+
+static int
+simplebus_alloc_msi(device_t bus, device_t child, int *count)
+{
+       struct simplebus_devinfo *ndi;
+       struct resource_list_entry *rle;
+       int error, i, irq_count, *irqs;
+
+       if (*count < 1)
+               return (EINVAL);
+
+       ndi = device_get_ivars(child);
+       if (ndi == NULL)
+               return (ENXIO);
+
+       /* Only MSI or non-MSI for now */
+       rle = resource_list_find(&ndi->rl, SYS_RES_IRQ, 0);
+       if (rle != NULL && rle->res != NULL)
+               return (ENXIO);
+
+       irq_count = *count;
+       irqs = mallocarray(irq_count, sizeof(int), M_DEVBUF, M_WAITOK | M_ZERO);
+
+       error = PCIB_ALLOC_MSI(bus, child, irq_count, irq_count, irqs);
+       if (error != 0)
+               goto out;
+
+       for (i = 0; i < irq_count; i++) {
+               error = bus_generic_rl_set_resource(bus, child, SYS_RES_IRQ,
+                   i + 1, irqs[i], 1);
+               if (error != 0)
+                       break;
+       }
+
+       /* Clean up resources if something failed */
+       if (error != 0) {
+               for (int j = 0; j < i; j++) {
+                       bus_generic_rl_delete_resource(bus, child, SYS_RES_IRQ,
+                           j + 1);
+               }
+       }
+out:
+       free(irqs, M_DEVBUF);
+       return (error);
+}
+
+static int
+simplebus_pcib_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+    int *irqs)
+{
+       return (PCIB_ALLOC_MSI(device_get_parent(dev), child, count, maxcount,
+           irqs));
+}
+
+static int
+simplebus_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
+{
+       return (PCIB_RELEASE_MSI(device_get_parent(dev), child, count, irqs));
+}
+
+static int
+simplebus_pcib_alloc_msix(device_t dev, device_t child, int *irq)
+{
+       return (PCIB_ALLOC_MSIX(device_get_parent(dev), child, irq));
+}
+
+static int
+simplebus_pcib_release_msix(device_t dev, device_t child, int irq)
+{
+       return (PCIB_RELEASE_MSIX(device_get_parent(dev), child, irq));
+}
+
+static int
+simplebus_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
+    uint32_t *data)
+{
+       return (PCIB_MAP_MSI(device_get_parent(dev), child, irq, addr,
+           data));
+}

Reply via email to