1*eb3d9e2dSkettenis /* $OpenBSD: acpipci.c,v 1.43 2025/01/23 11:24:34 kettenis Exp $ */ 281657d7aSkettenis /* 381657d7aSkettenis * Copyright (c) 2018 Mark Kettenis 481657d7aSkettenis * 581657d7aSkettenis * Permission to use, copy, modify, and distribute this software for any 681657d7aSkettenis * purpose with or without fee is hereby granted, provided that the above 781657d7aSkettenis * copyright notice and this permission notice appear in all copies. 881657d7aSkettenis * 981657d7aSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1081657d7aSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1181657d7aSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1281657d7aSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1381657d7aSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1481657d7aSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1581657d7aSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1681657d7aSkettenis */ 1781657d7aSkettenis 1881657d7aSkettenis #include <sys/param.h> 1981657d7aSkettenis #include <sys/device.h> 2081657d7aSkettenis #include <sys/extent.h> 2181657d7aSkettenis #include <sys/malloc.h> 2281657d7aSkettenis #include <sys/systm.h> 2381657d7aSkettenis 2481657d7aSkettenis #include <machine/bus.h> 2581657d7aSkettenis 2681657d7aSkettenis #include <dev/acpi/acpireg.h> 2781657d7aSkettenis #include <dev/acpi/acpivar.h> 2881657d7aSkettenis #include <dev/acpi/acpidev.h> 2981657d7aSkettenis #include <dev/acpi/amltypes.h> 3081657d7aSkettenis #include <dev/acpi/dsdt.h> 3181657d7aSkettenis 3281657d7aSkettenis #include <dev/pci/pcidevs.h> 3381657d7aSkettenis #include <dev/pci/pcireg.h> 3481657d7aSkettenis #include <dev/pci/pcivar.h> 3581657d7aSkettenis #include <dev/pci/ppbreg.h> 3681657d7aSkettenis 37b85db7edSpatrick #include <arm64/dev/acpiiort.h> 38b85db7edSpatrick 39d6a1c66eSkettenis struct acpipci_mcfg { 40d6a1c66eSkettenis SLIST_ENTRY(acpipci_mcfg) am_list; 41d6a1c66eSkettenis 42d6a1c66eSkettenis uint16_t am_segment; 43d6a1c66eSkettenis uint8_t am_min_bus; 44d6a1c66eSkettenis uint8_t am_max_bus; 45d6a1c66eSkettenis 46d6a1c66eSkettenis bus_space_tag_t am_iot; 47d6a1c66eSkettenis bus_space_handle_t am_ioh; 48d6a1c66eSkettenis 492b0be198Skettenis struct machine_pci_chipset am_pc; 50d6a1c66eSkettenis }; 5181657d7aSkettenis 5281657d7aSkettenis struct acpipci_trans { 5381657d7aSkettenis struct acpipci_trans *at_next; 5481657d7aSkettenis bus_space_tag_t at_iot; 5581657d7aSkettenis bus_addr_t at_base; 5681657d7aSkettenis bus_size_t at_size; 5781657d7aSkettenis bus_size_t at_offset; 5881657d7aSkettenis }; 5981657d7aSkettenis 6081657d7aSkettenis struct acpipci_softc { 6181657d7aSkettenis struct device sc_dev; 6281657d7aSkettenis struct acpi_softc *sc_acpi; 6381657d7aSkettenis struct aml_node *sc_node; 6481657d7aSkettenis bus_space_tag_t sc_iot; 65d6a1c66eSkettenis pci_chipset_tag_t sc_pc; 6681657d7aSkettenis 6781657d7aSkettenis struct bus_space sc_bus_iot; 6881657d7aSkettenis struct bus_space sc_bus_memt; 6981657d7aSkettenis struct acpipci_trans *sc_io_trans; 7081657d7aSkettenis struct acpipci_trans *sc_mem_trans; 7181657d7aSkettenis 7281657d7aSkettenis struct extent *sc_busex; 7381657d7aSkettenis struct extent *sc_memex; 7481657d7aSkettenis struct extent *sc_ioex; 7581657d7aSkettenis char sc_busex_name[32]; 7681657d7aSkettenis char sc_ioex_name[32]; 7781657d7aSkettenis char sc_memex_name[32]; 7881657d7aSkettenis int sc_bus; 791d265412Skettenis uint32_t sc_seg; 80f52d4db4Skettenis 81f52d4db4Skettenis struct interrupt_controller *sc_msi_ic; 8281657d7aSkettenis }; 8381657d7aSkettenis 84cc0ede06Spatrick struct acpipci_intr_handle { 852b0be198Skettenis struct machine_intr_handle aih_ih; 86cc0ede06Spatrick bus_dma_tag_t aih_dmat; 87cc0ede06Spatrick bus_dmamap_t aih_map; 88cc0ede06Spatrick }; 89cc0ede06Spatrick 9081657d7aSkettenis int acpipci_match(struct device *, void *, void *); 9181657d7aSkettenis void acpipci_attach(struct device *, struct device *, void *); 9281657d7aSkettenis 939fdf0c62Smpi const struct cfattach acpipci_ca = { 9481657d7aSkettenis sizeof(struct acpipci_softc), acpipci_match, acpipci_attach 9581657d7aSkettenis }; 9681657d7aSkettenis 9781657d7aSkettenis struct cfdriver acpipci_cd = { 9881657d7aSkettenis NULL, "acpipci", DV_DULL 9981657d7aSkettenis }; 10081657d7aSkettenis 10181657d7aSkettenis const char *acpipci_hids[] = { 10281657d7aSkettenis "PNP0A08", 10381657d7aSkettenis NULL 10481657d7aSkettenis }; 10581657d7aSkettenis 10681657d7aSkettenis int acpipci_parse_resources(int, union acpi_resource *, void *); 10781657d7aSkettenis int acpipci_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 10881657d7aSkettenis bus_space_handle_t *); 10982666eb1Skettenis paddr_t acpipci_bs_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); 11081657d7aSkettenis 11181657d7aSkettenis void acpipci_attach_hook(struct device *, struct device *, 11281657d7aSkettenis struct pcibus_attach_args *); 11381657d7aSkettenis int acpipci_bus_maxdevs(void *, int); 11481657d7aSkettenis pcitag_t acpipci_make_tag(void *, int, int, int); 11581657d7aSkettenis void acpipci_decompose_tag(void *, pcitag_t, int *, int *, int *); 11681657d7aSkettenis int acpipci_conf_size(void *, pcitag_t); 11781657d7aSkettenis pcireg_t acpipci_conf_read(void *, pcitag_t, int); 11881657d7aSkettenis void acpipci_conf_write(void *, pcitag_t, int, pcireg_t); 119619b146dSpatrick int acpipci_probe_device_hook(void *, struct pci_attach_args *); 12081657d7aSkettenis 12181657d7aSkettenis int acpipci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 12281657d7aSkettenis const char *acpipci_intr_string(void *, pci_intr_handle_t); 12381657d7aSkettenis void *acpipci_intr_establish(void *, pci_intr_handle_t, int, 124d67371fdSpatrick struct cpu_info *, int (*)(void *), void *, char *); 12581657d7aSkettenis void acpipci_intr_disestablish(void *, void *); 12681657d7aSkettenis 127aa5ad52dSjmatthew uint32_t acpipci_iort_map_msi(pci_chipset_tag_t, pcitag_t, 128aa5ad52dSjmatthew struct interrupt_controller **); 129aa5ad52dSjmatthew 130aa5ad52dSjmatthew extern LIST_HEAD(, interrupt_controller) interrupt_controllers; 1311d265412Skettenis 13281657d7aSkettenis int 13381657d7aSkettenis acpipci_match(struct device *parent, void *match, void *aux) 13481657d7aSkettenis { 13581657d7aSkettenis struct acpi_attach_args *aaa = aux; 13681657d7aSkettenis struct cfdata *cf = match; 13781657d7aSkettenis 13881657d7aSkettenis return acpi_matchhids(aaa, acpipci_hids, cf->cf_driver->cd_name); 13981657d7aSkettenis } 14081657d7aSkettenis 14181657d7aSkettenis void 14281657d7aSkettenis acpipci_attach(struct device *parent, struct device *self, void *aux) 14381657d7aSkettenis { 14481657d7aSkettenis struct acpi_attach_args *aaa = aux; 14581657d7aSkettenis struct acpipci_softc *sc = (struct acpipci_softc *)self; 146f52d4db4Skettenis struct interrupt_controller *ic; 14781657d7aSkettenis struct pcibus_attach_args pba; 14881657d7aSkettenis struct aml_value res; 14981657d7aSkettenis uint64_t bbn = 0; 1501d265412Skettenis uint64_t seg = 0; 15181657d7aSkettenis 15281657d7aSkettenis sc->sc_acpi = (struct acpi_softc *)parent; 15381657d7aSkettenis sc->sc_node = aaa->aaa_node; 15481657d7aSkettenis printf(" %s", sc->sc_node->name); 15581657d7aSkettenis 15681657d7aSkettenis if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 15781657d7aSkettenis printf(": can't find resources\n"); 15881657d7aSkettenis return; 15981657d7aSkettenis } 16081657d7aSkettenis 16181657d7aSkettenis aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL, &bbn); 16281657d7aSkettenis sc->sc_bus = bbn; 16381657d7aSkettenis 1641d265412Skettenis aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg); 1651d265412Skettenis sc->sc_seg = seg; 1661d265412Skettenis 167d6a1c66eSkettenis sc->sc_iot = aaa->aaa_memt; 16881657d7aSkettenis 16981657d7aSkettenis printf("\n"); 17081657d7aSkettenis 17181657d7aSkettenis /* Create extents for our address spaces. */ 17281657d7aSkettenis snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name), 17381657d7aSkettenis "%s pcibus", sc->sc_dev.dv_xname); 17481657d7aSkettenis snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), 17581657d7aSkettenis "%s pciio", sc->sc_dev.dv_xname); 17681657d7aSkettenis snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), 17781657d7aSkettenis "%s pcimem", sc->sc_dev.dv_xname); 17881657d7aSkettenis sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255, 17981657d7aSkettenis M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 18081657d7aSkettenis sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff, 18181657d7aSkettenis M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 18281657d7aSkettenis sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1, 18381657d7aSkettenis M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); 18481657d7aSkettenis 18581657d7aSkettenis aml_parse_resource(&res, acpipci_parse_resources, sc); 18681657d7aSkettenis 18781657d7aSkettenis memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); 18881657d7aSkettenis sc->sc_bus_iot.bus_private = sc->sc_io_trans; 18981657d7aSkettenis sc->sc_bus_iot._space_map = acpipci_bs_map; 19082666eb1Skettenis sc->sc_bus_iot._space_mmap = acpipci_bs_mmap; 19181657d7aSkettenis memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); 19281657d7aSkettenis sc->sc_bus_memt.bus_private = sc->sc_mem_trans; 19381657d7aSkettenis sc->sc_bus_memt._space_map = acpipci_bs_map; 19482666eb1Skettenis sc->sc_bus_memt._space_mmap = acpipci_bs_mmap; 19581657d7aSkettenis 196f52d4db4Skettenis LIST_FOREACH(ic, &interrupt_controllers, ic_list) { 197f52d4db4Skettenis if (ic->ic_establish_msi) 198f52d4db4Skettenis break; 199f52d4db4Skettenis } 200f52d4db4Skettenis sc->sc_msi_ic = ic; 201f52d4db4Skettenis 202*eb3d9e2dSkettenis sc->sc_pc = pci_lookup_segment(sc->sc_seg, sc->sc_bus); 203d6a1c66eSkettenis KASSERT(sc->sc_pc->pc_intr_v == NULL); 20481657d7aSkettenis 205619b146dSpatrick sc->sc_pc->pc_probe_device_hook = acpipci_probe_device_hook; 206619b146dSpatrick 207d6a1c66eSkettenis sc->sc_pc->pc_intr_v = sc; 208d6a1c66eSkettenis sc->sc_pc->pc_intr_map = acpipci_intr_map; 209809fc743Skettenis sc->sc_pc->pc_intr_map_msi = _pci_intr_map_msi; 21056d02c00Skettenis sc->sc_pc->pc_intr_map_msivec = _pci_intr_map_msivec; 211809fc743Skettenis sc->sc_pc->pc_intr_map_msix = _pci_intr_map_msix; 212d6a1c66eSkettenis sc->sc_pc->pc_intr_string = acpipci_intr_string; 213d6a1c66eSkettenis sc->sc_pc->pc_intr_establish = acpipci_intr_establish; 214d6a1c66eSkettenis sc->sc_pc->pc_intr_disestablish = acpipci_intr_disestablish; 21581657d7aSkettenis 21681657d7aSkettenis memset(&pba, 0, sizeof(pba)); 21781657d7aSkettenis pba.pba_busname = "pci"; 21881657d7aSkettenis pba.pba_iot = &sc->sc_bus_iot; 21981657d7aSkettenis pba.pba_memt = &sc->sc_bus_memt; 22081657d7aSkettenis pba.pba_dmat = aaa->aaa_dmat; 221d6a1c66eSkettenis pba.pba_pc = sc->sc_pc; 22281657d7aSkettenis pba.pba_busex = sc->sc_busex; 22381657d7aSkettenis pba.pba_ioex = sc->sc_ioex; 22481657d7aSkettenis pba.pba_memex = sc->sc_memex; 225e34c4bb6Skettenis pba.pba_pmemex = sc->sc_memex; 22681657d7aSkettenis pba.pba_domain = pci_ndomains++; 22781657d7aSkettenis pba.pba_bus = sc->sc_bus; 228f52d4db4Skettenis if (sc->sc_msi_ic) 2290045467fSkettenis pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; 23081657d7aSkettenis 23181657d7aSkettenis config_found(self, &pba, NULL); 23281657d7aSkettenis } 23381657d7aSkettenis 23481657d7aSkettenis int 23581657d7aSkettenis acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg) 23681657d7aSkettenis { 23781657d7aSkettenis struct acpipci_softc *sc = arg; 23881657d7aSkettenis struct acpipci_trans *at; 23981657d7aSkettenis int type = AML_CRSTYPE(crs); 24081657d7aSkettenis int restype, tflags; 24181657d7aSkettenis u_long min, len = 0, tra; 24281657d7aSkettenis 24381657d7aSkettenis switch (type) { 24481657d7aSkettenis case LR_WORD: 24581657d7aSkettenis restype = crs->lr_word.type; 24681657d7aSkettenis tflags = crs->lr_word.tflags; 24781657d7aSkettenis min = crs->lr_word._min; 24881657d7aSkettenis len = crs->lr_word._len; 24981657d7aSkettenis tra = crs->lr_word._tra; 25081657d7aSkettenis break; 25181657d7aSkettenis case LR_DWORD: 25281657d7aSkettenis restype = crs->lr_dword.type; 25381657d7aSkettenis tflags = crs->lr_dword.tflags; 25481657d7aSkettenis min = crs->lr_dword._min; 25581657d7aSkettenis len = crs->lr_dword._len; 25681657d7aSkettenis tra = crs->lr_dword._tra; 25781657d7aSkettenis break; 25881657d7aSkettenis case LR_QWORD: 25981657d7aSkettenis restype = crs->lr_qword.type; 26081657d7aSkettenis tflags = crs->lr_qword.tflags; 26181657d7aSkettenis min = crs->lr_qword._min; 26281657d7aSkettenis len = crs->lr_qword._len; 26381657d7aSkettenis tra = crs->lr_qword._tra; 26481657d7aSkettenis break; 26546b0d19aSkettenis case LR_MEM32FIXED: 26646b0d19aSkettenis restype = LR_TYPE_MEMORY; 26746b0d19aSkettenis tflags = 0; 26846b0d19aSkettenis min = crs->lr_m32fixed._bas; 26946b0d19aSkettenis len = crs->lr_m32fixed._len; 27046b0d19aSkettenis tra = 0; 27146b0d19aSkettenis break; 27281657d7aSkettenis } 27381657d7aSkettenis 27481657d7aSkettenis if (len == 0) 27581657d7aSkettenis return 0; 27681657d7aSkettenis 27781657d7aSkettenis switch (restype) { 27881657d7aSkettenis case LR_TYPE_MEMORY: 27981657d7aSkettenis if (tflags & LR_MEMORY_TTP) 28081657d7aSkettenis return 0; 28181657d7aSkettenis extent_free(sc->sc_memex, min, len, EX_WAITOK); 28281657d7aSkettenis at = malloc(sizeof(struct acpipci_trans), M_DEVBUF, M_WAITOK); 28381657d7aSkettenis at->at_iot = sc->sc_iot; 28481657d7aSkettenis at->at_base = min; 28581657d7aSkettenis at->at_size = len; 28681657d7aSkettenis at->at_offset = tra; 28781657d7aSkettenis at->at_next = sc->sc_mem_trans; 28881657d7aSkettenis sc->sc_mem_trans = at; 28981657d7aSkettenis break; 29081657d7aSkettenis case LR_TYPE_IO: 2913bd15d39Skettenis /* 2923bd15d39Skettenis * Don't check _TTP as various firmwares don't set it, 2933bd15d39Skettenis * even though they should!! 2943bd15d39Skettenis */ 29581657d7aSkettenis extent_free(sc->sc_ioex, min, len, EX_WAITOK); 29681657d7aSkettenis at = malloc(sizeof(struct acpipci_trans), M_DEVBUF, M_WAITOK); 29781657d7aSkettenis at->at_iot = sc->sc_iot; 29881657d7aSkettenis at->at_base = min; 29981657d7aSkettenis at->at_size = len; 30081657d7aSkettenis at->at_offset = tra; 30181657d7aSkettenis at->at_next = sc->sc_io_trans; 30281657d7aSkettenis sc->sc_io_trans = at; 30381657d7aSkettenis break; 30481657d7aSkettenis case LR_TYPE_BUS: 30581657d7aSkettenis extent_free(sc->sc_busex, min, len, EX_WAITOK); 306c95edaacSkettenis /* 307c95edaacSkettenis * Let _CRS minimum bus number override _BBN. 308c95edaacSkettenis */ 309c95edaacSkettenis sc->sc_bus = min; 31081657d7aSkettenis break; 31181657d7aSkettenis } 31281657d7aSkettenis 31381657d7aSkettenis return 0; 31481657d7aSkettenis } 31581657d7aSkettenis 31681657d7aSkettenis void 31781657d7aSkettenis acpipci_attach_hook(struct device *parent, struct device *self, 31881657d7aSkettenis struct pcibus_attach_args *pba) 31981657d7aSkettenis { 32081657d7aSkettenis } 32181657d7aSkettenis 32281657d7aSkettenis int 32381657d7aSkettenis acpipci_bus_maxdevs(void *v, int bus) 32481657d7aSkettenis { 32581657d7aSkettenis return 32; 32681657d7aSkettenis } 32781657d7aSkettenis 32881657d7aSkettenis pcitag_t 32981657d7aSkettenis acpipci_make_tag(void *v, int bus, int device, int function) 33081657d7aSkettenis { 33181657d7aSkettenis return ((bus << 20) | (device << 15) | (function << 12)); 33281657d7aSkettenis } 33381657d7aSkettenis 33481657d7aSkettenis void 33581657d7aSkettenis acpipci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 33681657d7aSkettenis { 33781657d7aSkettenis if (bp != NULL) 33881657d7aSkettenis *bp = (tag >> 20) & 0xff; 33981657d7aSkettenis if (dp != NULL) 34081657d7aSkettenis *dp = (tag >> 15) & 0x1f; 34181657d7aSkettenis if (fp != NULL) 34281657d7aSkettenis *fp = (tag >> 12) & 0x7; 34381657d7aSkettenis } 34481657d7aSkettenis 34581657d7aSkettenis int 34681657d7aSkettenis acpipci_conf_size(void *v, pcitag_t tag) 34781657d7aSkettenis { 34881657d7aSkettenis return PCIE_CONFIG_SPACE_SIZE; 34981657d7aSkettenis } 35081657d7aSkettenis 35181657d7aSkettenis pcireg_t 35281657d7aSkettenis acpipci_conf_read(void *v, pcitag_t tag, int reg) 35381657d7aSkettenis { 354d6a1c66eSkettenis struct acpipci_mcfg *am = v; 35581657d7aSkettenis 356d6a1c66eSkettenis if (tag < (am->am_min_bus << 20) || 357d6a1c66eSkettenis tag >= ((am->am_max_bus + 1) << 20)) 358d6a1c66eSkettenis return 0xffffffff; 359d6a1c66eSkettenis 360d6a1c66eSkettenis return bus_space_read_4(am->am_iot, am->am_ioh, tag | reg); 36181657d7aSkettenis } 36281657d7aSkettenis 36381657d7aSkettenis void 36481657d7aSkettenis acpipci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 36581657d7aSkettenis { 366d6a1c66eSkettenis struct acpipci_mcfg *am = v; 36781657d7aSkettenis 368d6a1c66eSkettenis if (tag < (am->am_min_bus << 20) || 369d6a1c66eSkettenis tag >= ((am->am_max_bus + 1) << 20)) 370d6a1c66eSkettenis return; 371d6a1c66eSkettenis 372d6a1c66eSkettenis bus_space_write_4(am->am_iot, am->am_ioh, tag | reg, data); 37381657d7aSkettenis } 37481657d7aSkettenis 37581657d7aSkettenis int 376619b146dSpatrick acpipci_probe_device_hook(void *v, struct pci_attach_args *pa) 377619b146dSpatrick { 378b85db7edSpatrick struct acpipci_mcfg *am = v; 379415019ceSpatrick struct acpipci_trans *at; 380b85db7edSpatrick struct acpi_table_header *hdr; 381b85db7edSpatrick struct acpi_iort *iort = NULL; 382b85db7edSpatrick struct acpi_iort_node *node; 383b85db7edSpatrick struct acpi_iort_mapping *map; 384b85db7edSpatrick struct acpi_iort_rc_node *rc; 385b85db7edSpatrick struct acpi_q *entry; 386b85db7edSpatrick uint32_t rid, offset; 387b85db7edSpatrick int i; 388b85db7edSpatrick 389b85db7edSpatrick rid = pci_requester_id(pa->pa_pc, pa->pa_tag); 390b85db7edSpatrick 391b85db7edSpatrick /* Look for IORT table. */ 392b85db7edSpatrick SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) { 393b85db7edSpatrick hdr = entry->q_table; 394b85db7edSpatrick if (strncmp(hdr->signature, IORT_SIG, 395b85db7edSpatrick sizeof(hdr->signature)) == 0) { 396b85db7edSpatrick iort = entry->q_table; 397b85db7edSpatrick break; 398b85db7edSpatrick } 399b85db7edSpatrick } 400b85db7edSpatrick if (iort == NULL) 401b85db7edSpatrick return 0; 402b85db7edSpatrick 403b85db7edSpatrick /* Find our root complex. */ 404b85db7edSpatrick offset = iort->offset; 405b85db7edSpatrick for (i = 0; i < iort->number_of_nodes; i++) { 406b85db7edSpatrick node = (struct acpi_iort_node *)((char *)iort + offset); 407b85db7edSpatrick if (node->type == ACPI_IORT_ROOT_COMPLEX) { 408b85db7edSpatrick rc = (struct acpi_iort_rc_node *)&node[1]; 409b85db7edSpatrick if (rc->segment == am->am_segment) 410b85db7edSpatrick break; 411b85db7edSpatrick } 412b85db7edSpatrick offset += node->length; 413b85db7edSpatrick } 414b85db7edSpatrick 415b85db7edSpatrick /* No RC found? Weird. */ 416b85db7edSpatrick if (i >= iort->number_of_nodes) 417b85db7edSpatrick return 0; 418b85db7edSpatrick 419b85db7edSpatrick /* Find our output base towards SMMU. */ 420b85db7edSpatrick map = (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); 421b85db7edSpatrick for (i = 0; i < node->number_of_mappings; i++) { 422b85db7edSpatrick offset = map[i].output_reference; 423b85db7edSpatrick 424b85db7edSpatrick if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { 425b85db7edSpatrick rid = map[i].output_base; 426b85db7edSpatrick break; 427b85db7edSpatrick } 428b85db7edSpatrick 429b85db7edSpatrick /* Mapping encodes number of IDs in the range minus one. */ 430b85db7edSpatrick if (map[i].input_base <= rid && 431b85db7edSpatrick rid <= map[i].input_base + map[i].number_of_ids) { 432b85db7edSpatrick rid = map[i].output_base + (rid - map[i].input_base); 433b85db7edSpatrick break; 434b85db7edSpatrick } 435b85db7edSpatrick } 436b85db7edSpatrick 437b85db7edSpatrick /* No mapping found? Even weirder. */ 438b85db7edSpatrick if (i >= node->number_of_mappings) 439b85db7edSpatrick return 0; 440b85db7edSpatrick 441b85db7edSpatrick node = (struct acpi_iort_node *)((char *)iort + offset); 442227a6d54Spatrick if (node->type == ACPI_IORT_SMMU || node->type == ACPI_IORT_SMMU_V3) { 44388933a1fSpatrick pa->pa_dmat = acpiiort_smmu_map(node, rid, pa->pa_dmat); 444415019ceSpatrick for (at = pa->pa_iot->bus_private; at; at = at->at_next) { 445415019ceSpatrick acpiiort_smmu_reserve_region(node, rid, 446415019ceSpatrick at->at_base, at->at_size); 447415019ceSpatrick } 448415019ceSpatrick for (at = pa->pa_memt->bus_private; at; at = at->at_next) { 449415019ceSpatrick acpiiort_smmu_reserve_region(node, rid, 450415019ceSpatrick at->at_base, at->at_size); 451415019ceSpatrick } 452415019ceSpatrick } 453b85db7edSpatrick 454619b146dSpatrick return 0; 455619b146dSpatrick } 456619b146dSpatrick 457619b146dSpatrick int 45809c29451Skettenis acpipci_intr_swizzle(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 45909c29451Skettenis { 46009c29451Skettenis int dev, swizpin; 4611a4b96f2Skettenis pcireg_t id; 46209c29451Skettenis 463809fc743Skettenis if (pa->pa_bridgeih == NULL) 46409c29451Skettenis return -1; 46509c29451Skettenis 46609c29451Skettenis pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL); 46709c29451Skettenis swizpin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); 4681a4b96f2Skettenis 4691a4b96f2Skettenis /* 4701a4b96f2Skettenis * Qualcomm SC8280XP Root Complex violates PCI bridge 4711a4b96f2Skettenis * interrupt swizzling rules. 4721a4b96f2Skettenis */ 4731a4b96f2Skettenis if (pa->pa_bridgetag) { 4741a4b96f2Skettenis id = pci_conf_read(pa->pa_pc, *pa->pa_bridgetag, PCI_ID_REG); 4751a4b96f2Skettenis if (PCI_VENDOR(id) == PCI_VENDOR_QUALCOMM && 4761a4b96f2Skettenis PCI_PRODUCT(id) == PCI_PRODUCT_QUALCOMM_SC8280XP_PCIE) { 4771a4b96f2Skettenis swizpin = (((swizpin - 1) + 3) % 4) + 1; 4781a4b96f2Skettenis } 4791a4b96f2Skettenis } 4801a4b96f2Skettenis 481809fc743Skettenis if (pa->pa_bridgeih[swizpin - 1].ih_type == PCI_NONE) 48209c29451Skettenis return -1; 48309c29451Skettenis 484809fc743Skettenis *ihp = pa->pa_bridgeih[swizpin - 1]; 48509c29451Skettenis return 0; 48609c29451Skettenis } 48709c29451Skettenis 48809c29451Skettenis int 489063d2976Skettenis acpipci_getirq(int crsidx, union acpi_resource *crs, void *arg) 490063d2976Skettenis { 491063d2976Skettenis int *irq = arg; 492063d2976Skettenis 493063d2976Skettenis switch (AML_CRSTYPE(crs)) { 494063d2976Skettenis case SR_IRQ: 495063d2976Skettenis *irq = ffs(letoh16(crs->sr_irq.irq_mask)) - 1; 496063d2976Skettenis break; 497063d2976Skettenis case LR_EXTIRQ: 498063d2976Skettenis *irq = letoh32(crs->lr_extirq.irq[0]); 499063d2976Skettenis break; 500063d2976Skettenis default: 501063d2976Skettenis break; 502063d2976Skettenis } 503063d2976Skettenis 504063d2976Skettenis return 0; 505063d2976Skettenis } 506063d2976Skettenis 507063d2976Skettenis int 508751e2f11Skettenis acpipci_intr_link(struct acpipci_softc *sc, struct aml_node *node, 509751e2f11Skettenis struct aml_value *val) 510063d2976Skettenis { 511063d2976Skettenis struct aml_value res; 512063d2976Skettenis int64_t sta; 513063d2976Skettenis int irq = -1; 514063d2976Skettenis 515751e2f11Skettenis if (val->type == AML_OBJTYPE_NAMEREF) { 516751e2f11Skettenis node = aml_searchrel(node, aml_getname(val->v_nameref)); 517751e2f11Skettenis if (node) 518751e2f11Skettenis val = node->value; 519751e2f11Skettenis } 520063d2976Skettenis if (val->type == AML_OBJTYPE_OBJREF) 521063d2976Skettenis val = val->v_objref.ref; 522063d2976Skettenis if (val->type != AML_OBJTYPE_DEVICE) 523063d2976Skettenis return -1; 524063d2976Skettenis 525063d2976Skettenis sta = acpi_getsta(sc->sc_acpi, val->node); 526063d2976Skettenis if ((sta & STA_PRESENT) == 0) 527063d2976Skettenis return -1; 528063d2976Skettenis 529063d2976Skettenis if (aml_evalname(sc->sc_acpi, val->node, "_CRS", 0, NULL, &res)) 530063d2976Skettenis return -1; 531063d2976Skettenis aml_parse_resource(&res, acpipci_getirq, &irq); 532063d2976Skettenis aml_freevalue(&res); 533063d2976Skettenis 534063d2976Skettenis return irq; 535063d2976Skettenis } 536063d2976Skettenis 537063d2976Skettenis int 53881657d7aSkettenis acpipci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 53981657d7aSkettenis { 5406550c394Skettenis struct acpipci_softc *sc = pa->pa_pc->pc_intr_v; 54109c29451Skettenis struct aml_node *node = sc->sc_node; 5426550c394Skettenis struct aml_value res; 5436550c394Skettenis uint64_t addr, pin, source, index; 5446550c394Skettenis int i; 5456550c394Skettenis 54609c29451Skettenis /* 54709c29451Skettenis * If we're behind a bridge, we need to look for a _PRT for 54809c29451Skettenis * it. If we don't find a _PRT, we need to swizzle. If we're 54909c29451Skettenis * not behind a bridge we need to look for a _PRT on the host 55009c29451Skettenis * bridge node itself. 55109c29451Skettenis */ 55209c29451Skettenis if (pa->pa_bridgetag) { 5536550c394Skettenis node = acpi_find_pci(pa->pa_pc, *pa->pa_bridgetag); 5546550c394Skettenis if (node == NULL) 55509c29451Skettenis return acpipci_intr_swizzle(pa, ihp); 55609c29451Skettenis } 5576550c394Skettenis 5586550c394Skettenis if (aml_evalname(sc->sc_acpi, node, "_PRT", 0, NULL, &res)) 55909c29451Skettenis return acpipci_intr_swizzle(pa, ihp); 5606550c394Skettenis 5616550c394Skettenis if (res.type != AML_OBJTYPE_PACKAGE) 5626550c394Skettenis return -1; 5636550c394Skettenis 5646550c394Skettenis for (i = 0; i < res.length; i++) { 5656550c394Skettenis struct aml_value *val = res.v_package[i]; 5666550c394Skettenis 5676550c394Skettenis if (val->type != AML_OBJTYPE_PACKAGE) 5686550c394Skettenis continue; 5696550c394Skettenis if (val->length != 4) 5706550c394Skettenis continue; 5716550c394Skettenis if (val->v_package[0]->type != AML_OBJTYPE_INTEGER || 5726550c394Skettenis val->v_package[1]->type != AML_OBJTYPE_INTEGER || 5736550c394Skettenis val->v_package[3]->type != AML_OBJTYPE_INTEGER) 5746550c394Skettenis continue; 5756550c394Skettenis 5766550c394Skettenis addr = val->v_package[0]->v_integer; 5776550c394Skettenis pin = val->v_package[1]->v_integer; 5786550c394Skettenis if (ACPI_ADR_PCIDEV(addr) != pa->pa_device || 5796550c394Skettenis ACPI_ADR_PCIFUN(addr) != 0xffff || 580063d2976Skettenis pin != pa->pa_intrpin - 1) 581063d2976Skettenis continue; 582063d2976Skettenis 583063d2976Skettenis if (val->v_package[2]->type == AML_OBJTYPE_INTEGER) { 584063d2976Skettenis source = val->v_package[2]->v_integer; 585063d2976Skettenis index = val->v_package[3]->v_integer; 586063d2976Skettenis } else { 587063d2976Skettenis source = 0; 588751e2f11Skettenis index = acpipci_intr_link(sc, node, val->v_package[2]); 589063d2976Skettenis } 590063d2976Skettenis if (source != 0 || index == -1) 5916550c394Skettenis continue; 5926550c394Skettenis 593809fc743Skettenis ihp->ih_pc = pa->pa_pc; 594809fc743Skettenis ihp->ih_tag = pa->pa_tag; 595809fc743Skettenis ihp->ih_intrpin = index; 596809fc743Skettenis ihp->ih_type = PCI_INTX; 5976550c394Skettenis 5986550c394Skettenis return 0; 5996550c394Skettenis } 6006550c394Skettenis 60181657d7aSkettenis return -1; 60281657d7aSkettenis } 60381657d7aSkettenis 60481657d7aSkettenis const char * 605809fc743Skettenis acpipci_intr_string(void *v, pci_intr_handle_t ih) 60681657d7aSkettenis { 6076550c394Skettenis static char irqstr[32]; 60881657d7aSkettenis 609809fc743Skettenis switch (ih.ih_type) { 610a569ea7cSkettenis case PCI_MSI: 61181657d7aSkettenis return "msi"; 612a569ea7cSkettenis case PCI_MSIX: 613a569ea7cSkettenis return "msix"; 614a569ea7cSkettenis } 61581657d7aSkettenis 616809fc743Skettenis snprintf(irqstr, sizeof(irqstr), "irq %d", ih.ih_intrpin); 6176550c394Skettenis return irqstr; 61881657d7aSkettenis } 61981657d7aSkettenis 62081657d7aSkettenis void * 621809fc743Skettenis acpipci_intr_establish(void *v, pci_intr_handle_t ih, int level, 622d67371fdSpatrick struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 62381657d7aSkettenis { 624a569ea7cSkettenis struct acpipci_softc *sc = v; 625cc0ede06Spatrick struct acpipci_intr_handle *aih; 62681657d7aSkettenis void *cookie; 62781657d7aSkettenis 628f2ee0c12Skettenis KASSERT(ih.ih_type != PCI_NONE); 629f2ee0c12Skettenis 630f2ee0c12Skettenis if (ih.ih_type != PCI_INTX) { 631f52d4db4Skettenis struct interrupt_controller *ic = sc->sc_msi_ic; 632f2ee0c12Skettenis bus_dma_segment_t seg; 63356d02c00Skettenis uint64_t addr = 0, data; 634f2ee0c12Skettenis 635f52d4db4Skettenis KASSERT(ic); 63681657d7aSkettenis 6371d265412Skettenis /* Map Requester ID through IORT to get sideband data. */ 638aa5ad52dSjmatthew data = acpipci_iort_map_msi(ih.ih_pc, ih.ih_tag, &ic); 63981657d7aSkettenis cookie = ic->ic_establish_msi(ic->ic_cookie, &addr, 640d67371fdSpatrick &data, level, ci, func, arg, name); 64181657d7aSkettenis if (cookie == NULL) 64281657d7aSkettenis return NULL; 64381657d7aSkettenis 644cc0ede06Spatrick aih = malloc(sizeof(*aih), M_DEVBUF, M_WAITOK); 645cc0ede06Spatrick aih->aih_ih.ih_ic = ic; 646cc0ede06Spatrick aih->aih_ih.ih_ih = cookie; 647cc0ede06Spatrick aih->aih_dmat = ih.ih_dmat; 64881657d7aSkettenis 649cc0ede06Spatrick if (bus_dmamap_create(aih->aih_dmat, sizeof(uint32_t), 1, 650cc0ede06Spatrick sizeof(uint32_t), 0, BUS_DMA_WAITOK, &aih->aih_map)) { 651cc0ede06Spatrick free(aih, M_DEVBUF, sizeof(*aih)); 652cc0ede06Spatrick ic->ic_disestablish(cookie); 653cc0ede06Spatrick return NULL; 654cc0ede06Spatrick } 655cc0ede06Spatrick 656cc0ede06Spatrick memset(&seg, 0, sizeof(seg)); 657cc0ede06Spatrick seg.ds_addr = addr; 658cc0ede06Spatrick seg.ds_len = sizeof(uint32_t); 659cc0ede06Spatrick 660cc0ede06Spatrick if (bus_dmamap_load_raw(aih->aih_dmat, aih->aih_map, 661cc0ede06Spatrick &seg, 1, sizeof(uint32_t), BUS_DMA_WAITOK)) { 662cc0ede06Spatrick bus_dmamap_destroy(aih->aih_dmat, aih->aih_map); 663cc0ede06Spatrick free(aih, M_DEVBUF, sizeof(*aih)); 664cc0ede06Spatrick ic->ic_disestablish(cookie); 665cc0ede06Spatrick return NULL; 666cc0ede06Spatrick } 667cc0ede06Spatrick 668cc0ede06Spatrick addr = aih->aih_map->dm_segs[0].ds_addr; 669809fc743Skettenis if (ih.ih_type == PCI_MSIX) { 670809fc743Skettenis pci_msix_enable(ih.ih_pc, ih.ih_tag, 671809fc743Skettenis &sc->sc_bus_memt, ih.ih_intrpin, addr, data); 672a569ea7cSkettenis } else 673809fc743Skettenis pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data); 67472d45bb7Spatrick 67572d45bb7Spatrick cookie = aih; 6766550c394Skettenis } else { 677d67371fdSpatrick if (ci != NULL && !CPU_IS_PRIMARY(ci)) 678d67371fdSpatrick return NULL; 679809fc743Skettenis cookie = acpi_intr_establish(ih.ih_intrpin, 0, level, 6806550c394Skettenis func, arg, name); 68181657d7aSkettenis } 68281657d7aSkettenis 68381657d7aSkettenis return cookie; 68481657d7aSkettenis } 68581657d7aSkettenis 68681657d7aSkettenis void 68781657d7aSkettenis acpipci_intr_disestablish(void *v, void *cookie) 68881657d7aSkettenis { 689cc0ede06Spatrick struct acpipci_intr_handle *aih = cookie; 690cc0ede06Spatrick struct interrupt_controller *ic = aih->aih_ih.ih_ic; 691021a0979Skettenis 692cc0ede06Spatrick if (ic->ic_establish_msi) { 693cc0ede06Spatrick ic->ic_disestablish(aih->aih_ih.ih_ih); 694cc0ede06Spatrick bus_dmamap_unload(aih->aih_dmat, aih->aih_map); 695cc0ede06Spatrick bus_dmamap_destroy(aih->aih_dmat, aih->aih_map); 696cc0ede06Spatrick free(aih, M_DEVBUF, sizeof(*aih)); 697cc0ede06Spatrick } else 698021a0979Skettenis acpi_intr_disestablish(cookie); 69981657d7aSkettenis } 70081657d7aSkettenis 70181657d7aSkettenis /* 70281657d7aSkettenis * Translate memory address if needed. 70381657d7aSkettenis */ 70481657d7aSkettenis int 70581657d7aSkettenis acpipci_bs_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 70681657d7aSkettenis int flags, bus_space_handle_t *bshp) 70781657d7aSkettenis { 70881657d7aSkettenis struct acpipci_trans *at; 70981657d7aSkettenis 71081657d7aSkettenis for (at = t->bus_private; at; at = at->at_next) { 71181657d7aSkettenis if (addr >= at->at_base && addr < at->at_base + at->at_size) { 71281657d7aSkettenis return bus_space_map(at->at_iot, 71381657d7aSkettenis addr + at->at_offset, size, flags, bshp); 71481657d7aSkettenis } 71581657d7aSkettenis } 71681657d7aSkettenis 71781657d7aSkettenis return ENXIO; 71881657d7aSkettenis } 71981657d7aSkettenis 72082666eb1Skettenis paddr_t 72182666eb1Skettenis acpipci_bs_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, 72282666eb1Skettenis int prot, int flags) 72382666eb1Skettenis { 72482666eb1Skettenis struct acpipci_trans *at; 72582666eb1Skettenis 72682666eb1Skettenis for (at = t->bus_private; at; at = at->at_next) { 72782666eb1Skettenis if (addr >= at->at_base && addr < at->at_base + at->at_size) { 72882666eb1Skettenis return bus_space_mmap(at->at_iot, 72982666eb1Skettenis addr + at->at_offset, off, prot, flags); 73082666eb1Skettenis } 73182666eb1Skettenis } 73282666eb1Skettenis 73382666eb1Skettenis return -1; 73482666eb1Skettenis } 73582666eb1Skettenis 736d6a1c66eSkettenis SLIST_HEAD(,acpipci_mcfg) acpipci_mcfgs = 737d6a1c66eSkettenis SLIST_HEAD_INITIALIZER(acpipci_mcfgs); 738d6a1c66eSkettenis 739d6a1c66eSkettenis void 740d6a1c66eSkettenis pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment, 741d6a1c66eSkettenis int min_bus, int max_bus) 742d6a1c66eSkettenis { 743d6a1c66eSkettenis struct acpipci_mcfg *am; 744d6a1c66eSkettenis 745d6a1c66eSkettenis am = malloc(sizeof(struct acpipci_mcfg), M_DEVBUF, M_WAITOK | M_ZERO); 746d6a1c66eSkettenis am->am_segment = segment; 747d6a1c66eSkettenis am->am_min_bus = min_bus; 748d6a1c66eSkettenis am->am_max_bus = max_bus; 749d6a1c66eSkettenis 750d6a1c66eSkettenis am->am_iot = iot; 751d6a1c66eSkettenis if (bus_space_map(iot, addr, (max_bus + 1) << 20, 0, &am->am_ioh)) 752d6a1c66eSkettenis panic("%s: can't map config space", __func__); 753d6a1c66eSkettenis 754d6a1c66eSkettenis am->am_pc.pc_conf_v = am; 755d6a1c66eSkettenis am->am_pc.pc_attach_hook = acpipci_attach_hook; 756d6a1c66eSkettenis am->am_pc.pc_bus_maxdevs = acpipci_bus_maxdevs; 757d6a1c66eSkettenis am->am_pc.pc_make_tag = acpipci_make_tag; 758d6a1c66eSkettenis am->am_pc.pc_decompose_tag = acpipci_decompose_tag; 759d6a1c66eSkettenis am->am_pc.pc_conf_size = acpipci_conf_size; 760d6a1c66eSkettenis am->am_pc.pc_conf_read = acpipci_conf_read; 761d6a1c66eSkettenis am->am_pc.pc_conf_write = acpipci_conf_write; 762d6a1c66eSkettenis SLIST_INSERT_HEAD(&acpipci_mcfgs, am, am_list); 763d6a1c66eSkettenis } 76481657d7aSkettenis 76581657d7aSkettenis pcireg_t 766d6a1c66eSkettenis acpipci_dummy_conf_read(void *v, pcitag_t tag, int reg) 76781657d7aSkettenis { 768d6a1c66eSkettenis return 0xffffffff; 76981657d7aSkettenis } 77081657d7aSkettenis 77181657d7aSkettenis void 772d6a1c66eSkettenis acpipci_dummy_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 77381657d7aSkettenis { 77481657d7aSkettenis } 77581657d7aSkettenis 7762b0be198Skettenis struct machine_pci_chipset acpipci_dummy_chipset = { 777d6a1c66eSkettenis .pc_attach_hook = acpipci_attach_hook, 778d6a1c66eSkettenis .pc_bus_maxdevs = acpipci_bus_maxdevs, 779d6a1c66eSkettenis .pc_make_tag = acpipci_make_tag, 780d6a1c66eSkettenis .pc_decompose_tag = acpipci_decompose_tag, 781d6a1c66eSkettenis .pc_conf_size = acpipci_conf_size, 782d6a1c66eSkettenis .pc_conf_read = acpipci_dummy_conf_read, 783d6a1c66eSkettenis .pc_conf_write = acpipci_dummy_conf_write, 784d6a1c66eSkettenis }; 785d6a1c66eSkettenis 78681657d7aSkettenis pci_chipset_tag_t 787*eb3d9e2dSkettenis pci_lookup_segment(int segment, int bus) 78881657d7aSkettenis { 789d6a1c66eSkettenis struct acpipci_mcfg *am; 79081657d7aSkettenis 791d6a1c66eSkettenis SLIST_FOREACH(am, &acpipci_mcfgs, am_list) { 792*eb3d9e2dSkettenis if (segment == am->am_segment && 793*eb3d9e2dSkettenis bus >= am->am_min_bus && bus <= am->am_max_bus) 794d6a1c66eSkettenis return &am->am_pc; 795d6a1c66eSkettenis } 79681657d7aSkettenis 797d6a1c66eSkettenis return &acpipci_dummy_chipset; 79881657d7aSkettenis } 7991d265412Skettenis 8001d265412Skettenis /* 8011d265412Skettenis * IORT support. 8021d265412Skettenis */ 8031d265412Skettenis 804aa5ad52dSjmatthew uint32_t acpipci_iort_map(struct acpi_iort *, uint32_t, uint32_t, 805aa5ad52dSjmatthew struct interrupt_controller **); 80690f44db7Skettenis 8071d265412Skettenis uint32_t 80890f44db7Skettenis acpipci_iort_map_node(struct acpi_iort *iort, 809aa5ad52dSjmatthew struct acpi_iort_node *node, uint32_t id, struct interrupt_controller **ic) 8101d265412Skettenis { 8111d265412Skettenis struct acpi_iort_mapping *map = 8121d265412Skettenis (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); 8131d265412Skettenis int i; 8141d265412Skettenis 8151d265412Skettenis for (i = 0; i < node->number_of_mappings; i++) { 81690f44db7Skettenis uint32_t offset = map[i].output_reference; 8171d265412Skettenis 81890f44db7Skettenis if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { 81990f44db7Skettenis id = map[i].output_base; 820aa5ad52dSjmatthew return acpipci_iort_map(iort, offset, id, ic); 82190f44db7Skettenis } 8221d265412Skettenis 823fdbcad4cSkettenis /* Mapping encodes number of IDs in the range minus one. */ 8241d265412Skettenis if (map[i].input_base <= id && 825fdbcad4cSkettenis id <= map[i].input_base + map[i].number_of_ids) { 82690f44db7Skettenis id = map[i].output_base + (id - map[i].input_base); 827aa5ad52dSjmatthew return acpipci_iort_map(iort, offset, id, ic); 82890f44db7Skettenis } 82990f44db7Skettenis } 83090f44db7Skettenis 83190f44db7Skettenis return id; 83290f44db7Skettenis } 83390f44db7Skettenis 83490f44db7Skettenis uint32_t 835aa5ad52dSjmatthew acpipci_iort_map(struct acpi_iort *iort, uint32_t offset, uint32_t id, 836aa5ad52dSjmatthew struct interrupt_controller **ic) 83790f44db7Skettenis { 83890f44db7Skettenis struct acpi_iort_node *node = 83990f44db7Skettenis (struct acpi_iort_node *)((char *)iort + offset); 840aa5ad52dSjmatthew struct interrupt_controller *icl; 841aa5ad52dSjmatthew struct acpi_iort_its_node *itsn; 842aa5ad52dSjmatthew int i; 84390f44db7Skettenis 84490f44db7Skettenis switch (node->type) { 84590f44db7Skettenis case ACPI_IORT_ITS: 846aa5ad52dSjmatthew itsn = (struct acpi_iort_its_node *)&node[1]; 847aa5ad52dSjmatthew LIST_FOREACH(icl, &interrupt_controllers, ic_list) { 848aa5ad52dSjmatthew for (i = 0; i < itsn->number_of_itss; i++) { 84912199e7cSjmatthew if (icl->ic_establish_msi != NULL && 85012199e7cSjmatthew icl->ic_gic_its_id == itsn->its_ids[i]) { 851aa5ad52dSjmatthew *ic = icl; 852aa5ad52dSjmatthew break; 853aa5ad52dSjmatthew } 854aa5ad52dSjmatthew } 855aa5ad52dSjmatthew } 856aa5ad52dSjmatthew 85790f44db7Skettenis return id; 85890f44db7Skettenis case ACPI_IORT_SMMU: 8597449538fSkettenis case ACPI_IORT_SMMU_V3: 860aa5ad52dSjmatthew return acpipci_iort_map_node(iort, node, id, ic); 8611d265412Skettenis } 8621d265412Skettenis 8631d265412Skettenis return id; 8641d265412Skettenis } 8651d265412Skettenis 8661d265412Skettenis uint32_t 867aa5ad52dSjmatthew acpipci_iort_map_msi(pci_chipset_tag_t pc, pcitag_t tag, 868aa5ad52dSjmatthew struct interrupt_controller **ic) 8691d265412Skettenis { 8701d265412Skettenis struct acpipci_softc *sc = pc->pc_intr_v; 8711d265412Skettenis struct acpi_table_header *hdr; 8721d265412Skettenis struct acpi_iort *iort = NULL; 8731d265412Skettenis struct acpi_iort_node *node; 8746642123eSpatrick struct acpi_iort_rc_node *rc; 8751d265412Skettenis struct acpi_q *entry; 87690f44db7Skettenis uint32_t rid, offset; 8771d265412Skettenis int i; 8781d265412Skettenis 8791d265412Skettenis rid = pci_requester_id(pc, tag); 8801d265412Skettenis 8811d265412Skettenis /* Look for IORT table. */ 8821d265412Skettenis SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { 8831d265412Skettenis hdr = entry->q_table; 8841d265412Skettenis if (strncmp(hdr->signature, IORT_SIG, 8851d265412Skettenis sizeof(hdr->signature)) == 0) { 8861d265412Skettenis iort = entry->q_table; 8871d265412Skettenis break; 8881d265412Skettenis } 8891d265412Skettenis } 8901d265412Skettenis if (iort == NULL) 8911d265412Skettenis return rid; 8921d265412Skettenis 8931d265412Skettenis /* Find our root complex and map. */ 8941d265412Skettenis offset = iort->offset; 8951d265412Skettenis for (i = 0; i < iort->number_of_nodes; i++) { 8961d265412Skettenis node = (struct acpi_iort_node *)((char *)iort + offset); 8971d265412Skettenis switch (node->type) { 8981d265412Skettenis case ACPI_IORT_ROOT_COMPLEX: 8996642123eSpatrick rc = (struct acpi_iort_rc_node *)&node[1]; 9006642123eSpatrick if (rc->segment == sc->sc_seg) 901aa5ad52dSjmatthew return acpipci_iort_map_node(iort, node, rid, 902aa5ad52dSjmatthew ic); 9031d265412Skettenis break; 9041d265412Skettenis } 9051d265412Skettenis offset += node->length; 9061d265412Skettenis } 9071d265412Skettenis 9081d265412Skettenis return rid; 9091d265412Skettenis } 910