| raw e-mail | index | archive | help
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)); +}
