xref: /openbsd-src/sys/arch/arm64/dev/acpipci.c (revision eb3d9e2dd0357d3826bf04a6468e649c8525d43e)
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