git: 68e6422c6c91 - main - dev/fdt: Add support for non-PCI MSI interrupts
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 18 Nov 2025 18:02:34 UTC
The branch main has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=68e6422c6c91170a615e77028683a157e8e39d05
commit 68e6422c6c91170a615e77028683a157e8e39d05
Author: Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-11-18 18:00:30 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
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));
+}