xref: /openbsd-src/sys/arch/amd64/pci/acpipci.c (revision 84053e14a5f097f20156856cc9d8ae8b6571deea)
1*84053e14Sjsg /*	$OpenBSD: acpipci.c,v 1.9 2024/10/10 05:51:23 jsg Exp $	*/
203a88dc8Skettenis /*
303a88dc8Skettenis  * Copyright (c) 2018 Mark Kettenis
403a88dc8Skettenis  *
503a88dc8Skettenis  * Permission to use, copy, modify, and distribute this software for any
603a88dc8Skettenis  * purpose with or without fee is hereby granted, provided that the above
703a88dc8Skettenis  * copyright notice and this permission notice appear in all copies.
803a88dc8Skettenis  *
903a88dc8Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1003a88dc8Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1103a88dc8Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1203a88dc8Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1303a88dc8Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1403a88dc8Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1503a88dc8Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1603a88dc8Skettenis  */
1703a88dc8Skettenis 
1803a88dc8Skettenis #include <sys/param.h>
1903a88dc8Skettenis #include <sys/device.h>
2003a88dc8Skettenis #include <sys/extent.h>
2103a88dc8Skettenis #include <sys/malloc.h>
2203a88dc8Skettenis #include <sys/systm.h>
2303a88dc8Skettenis 
2403a88dc8Skettenis #include <dev/acpi/acpireg.h>
2503a88dc8Skettenis #include <dev/acpi/acpivar.h>
2603a88dc8Skettenis #include <dev/acpi/acpidev.h>
2703a88dc8Skettenis #include <dev/acpi/amltypes.h>
2803a88dc8Skettenis #include <dev/acpi/dsdt.h>
2903a88dc8Skettenis 
3003a88dc8Skettenis #include <dev/pci/pcidevs.h>
3103a88dc8Skettenis #include <dev/pci/pcireg.h>
3203a88dc8Skettenis #include <dev/pci/pcivar.h>
3303a88dc8Skettenis 
3403a88dc8Skettenis /* 33DB4D5B-1FF7-401C-9657-7441C03DD766 */
3503a88dc8Skettenis #define ACPI_PCI_UUID \
3603a88dc8Skettenis   { 0x5b, 0x4d, 0xdb, 0x33, \
3703a88dc8Skettenis     0xf7, 0x1f, \
3803a88dc8Skettenis     0x1c, 0x40, \
3903a88dc8Skettenis     0x96, 0x57, \
4003a88dc8Skettenis     0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 }
4103a88dc8Skettenis 
4203a88dc8Skettenis /* Support field. */
4303a88dc8Skettenis #define ACPI_PCI_PCIE_CONFIG	0x00000001
4403a88dc8Skettenis #define ACPI_PCI_ASPM		0x00000002
4503a88dc8Skettenis #define ACPI_PCI_CPMC		0x00000004
4603a88dc8Skettenis #define ACPI_PCI_SEGMENTS	0x00000008
4703a88dc8Skettenis #define ACPI_PCI_MSI		0x00000010
4803a88dc8Skettenis 
4903a88dc8Skettenis /* Control field. */
5003a88dc8Skettenis #define ACPI_PCI_PCIE_HOTPLUG	0x00000001
5103a88dc8Skettenis 
5203a88dc8Skettenis struct acpipci_softc {
5303a88dc8Skettenis 	struct device	sc_dev;
5403a88dc8Skettenis 	struct acpi_softc *sc_acpi;
5503a88dc8Skettenis 	struct aml_node *sc_node;
56a6e4dcfbSkettenis 
57a6e4dcfbSkettenis 	bus_space_tag_t	sc_iot;
58a6e4dcfbSkettenis 	bus_space_tag_t	sc_memt;
59a6e4dcfbSkettenis 	bus_dma_tag_t	sc_dmat;
60a6e4dcfbSkettenis 
61a6e4dcfbSkettenis 	struct extent	*sc_busex;
62a6e4dcfbSkettenis 	struct extent	*sc_memex;
63a6e4dcfbSkettenis 	struct extent	*sc_ioex;
64a6e4dcfbSkettenis 	char		sc_busex_name[32];
65a6e4dcfbSkettenis 	char		sc_ioex_name[32];
66a6e4dcfbSkettenis 	char		sc_memex_name[32];
67a6e4dcfbSkettenis 	int		sc_bus;
68a6e4dcfbSkettenis 	uint32_t	sc_seg;
6903a88dc8Skettenis };
7003a88dc8Skettenis 
7103a88dc8Skettenis int	acpipci_match(struct device *, void *, void *);
7203a88dc8Skettenis void	acpipci_attach(struct device *, struct device *, void *);
7303a88dc8Skettenis 
7406a6f48eSmpi const struct cfattach acpipci_ca = {
7503a88dc8Skettenis 	sizeof(struct acpipci_softc), acpipci_match, acpipci_attach
7603a88dc8Skettenis };
7703a88dc8Skettenis 
7803a88dc8Skettenis struct cfdriver acpipci_cd = {
7903a88dc8Skettenis 	NULL, "acpipci", DV_DULL
8003a88dc8Skettenis };
8103a88dc8Skettenis 
8203a88dc8Skettenis const char *acpipci_hids[] = {
8303a88dc8Skettenis 	"PNP0A08",
8403a88dc8Skettenis 	"PNP0A03",
8503a88dc8Skettenis 	NULL
8603a88dc8Skettenis };
8703a88dc8Skettenis 
88a6e4dcfbSkettenis int	acpipci_print(void *, const char *);
89a6e4dcfbSkettenis int	acpipci_parse_resources(int, union acpi_resource *, void *);
90a6e4dcfbSkettenis void	acpipci_osc(struct acpipci_softc *);
91a6e4dcfbSkettenis 
9203a88dc8Skettenis int
9303a88dc8Skettenis acpipci_match(struct device *parent, void *match, void *aux)
9403a88dc8Skettenis {
9503a88dc8Skettenis 	struct acpi_attach_args *aaa = aux;
9603a88dc8Skettenis 	struct cfdata *cf = match;
9703a88dc8Skettenis 
9803a88dc8Skettenis 	return acpi_matchhids(aaa, acpipci_hids, cf->cf_driver->cd_name);
9903a88dc8Skettenis }
10003a88dc8Skettenis 
10103a88dc8Skettenis void
10203a88dc8Skettenis acpipci_attach(struct device *parent, struct device *self, void *aux)
10303a88dc8Skettenis {
10403a88dc8Skettenis 	struct acpi_attach_args *aaa = aux;
10503a88dc8Skettenis 	struct acpipci_softc *sc = (struct acpipci_softc *)self;
1069a33df95Skettenis 	struct aml_value res;
107a6e4dcfbSkettenis 	uint64_t bbn = 0;
108a6e4dcfbSkettenis 	uint64_t seg = 0;
109a6e4dcfbSkettenis 
110a6e4dcfbSkettenis 	acpi_haspci = 1;
111a6e4dcfbSkettenis 
112a6e4dcfbSkettenis 	sc->sc_iot = aaa->aaa_iot;
113a6e4dcfbSkettenis 	sc->sc_memt = aaa->aaa_memt;
114a6e4dcfbSkettenis 	sc->sc_dmat = aaa->aaa_dmat;
1159a33df95Skettenis 
11638f3385cSkettenis 	sc->sc_acpi = (struct acpi_softc *)parent;
11738f3385cSkettenis 	sc->sc_node = aaa->aaa_node;
11838f3385cSkettenis 	printf(" %s", sc->sc_node->name);
11938f3385cSkettenis 
120a6e4dcfbSkettenis 	acpipci_osc(sc);
121a6e4dcfbSkettenis 
122a6e4dcfbSkettenis 	aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL, &bbn);
123a6e4dcfbSkettenis 	sc->sc_bus = bbn;
124a6e4dcfbSkettenis 
125a6e4dcfbSkettenis 	aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg);
126a6e4dcfbSkettenis 	sc->sc_seg = seg;
127a6e4dcfbSkettenis 
128a6e4dcfbSkettenis 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
129a6e4dcfbSkettenis 		printf(": can't find resources\n");
130a6e4dcfbSkettenis 
131a6e4dcfbSkettenis 		pci_init_extents();
132a6e4dcfbSkettenis 		sc->sc_busex = pcibus_ex;
133a6e4dcfbSkettenis 		sc->sc_ioex = pciio_ex;
134a6e4dcfbSkettenis 		sc->sc_memex = pcimem_ex;
135a6e4dcfbSkettenis 
136a6e4dcfbSkettenis 		return;
137a6e4dcfbSkettenis 	}
138a6e4dcfbSkettenis 
139a6e4dcfbSkettenis 	/* Create extents for our address spaces. */
140a6e4dcfbSkettenis 	snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name),
141a6e4dcfbSkettenis 	    "%s pcibus", sc->sc_dev.dv_xname);
142a6e4dcfbSkettenis 	snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
143a6e4dcfbSkettenis 	    "%s pciio", sc->sc_dev.dv_xname);
144a6e4dcfbSkettenis 	snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
145a6e4dcfbSkettenis 	    "%s pcimem", sc->sc_dev.dv_xname);
146a6e4dcfbSkettenis 	sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255,
147a6e4dcfbSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
148a6e4dcfbSkettenis 	sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff,
149a6e4dcfbSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
150a6e4dcfbSkettenis 	sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1,
151a6e4dcfbSkettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
152a6e4dcfbSkettenis 
153a6e4dcfbSkettenis 	aml_parse_resource(&res, acpipci_parse_resources, sc);
154a6e4dcfbSkettenis 
155a6e4dcfbSkettenis 	if (sc->sc_acpi->sc_major < 5) {
156a6e4dcfbSkettenis 		extent_destroy(sc->sc_ioex);
157a6e4dcfbSkettenis 		extent_destroy(sc->sc_memex);
158a6e4dcfbSkettenis 
159a6e4dcfbSkettenis 		pci_init_extents();
160a6e4dcfbSkettenis 		sc->sc_ioex =  pciio_ex;
161a6e4dcfbSkettenis 		sc->sc_memex = pcimem_ex;
162a6e4dcfbSkettenis 	}
163a6e4dcfbSkettenis 
164a6e4dcfbSkettenis 	printf("\n");
165a6e4dcfbSkettenis 
16623834b0fSkettenis #ifdef ACPIPCI_DEBUG
167a6e4dcfbSkettenis 	extent_print(sc->sc_busex);
168a6e4dcfbSkettenis 	extent_print(sc->sc_ioex);
169a6e4dcfbSkettenis 	extent_print(sc->sc_memex);
170a6e4dcfbSkettenis #endif
171a6e4dcfbSkettenis }
172a6e4dcfbSkettenis 
173a6e4dcfbSkettenis void
174a6e4dcfbSkettenis acpipci_attach_bus(struct device *parent, struct acpipci_softc *sc)
175a6e4dcfbSkettenis {
176a6e4dcfbSkettenis 	struct pcibus_attach_args pba;
177a6e4dcfbSkettenis 	pcitag_t tag;
178a6e4dcfbSkettenis 	pcireg_t id, class;
179a6e4dcfbSkettenis 
180a6e4dcfbSkettenis 	memset(&pba, 0, sizeof(pba));
181a6e4dcfbSkettenis 	pba.pba_busname = "pci";
182a6e4dcfbSkettenis 	pba.pba_iot = sc->sc_iot;
183a6e4dcfbSkettenis 	pba.pba_memt = sc->sc_memt;
184a6e4dcfbSkettenis 	pba.pba_dmat = sc->sc_dmat;
185a6e4dcfbSkettenis 	pba.pba_busex = sc->sc_busex;
186a6e4dcfbSkettenis 	pba.pba_ioex = sc->sc_ioex;
187a6e4dcfbSkettenis 	pba.pba_memex = sc->sc_memex;
188a6e4dcfbSkettenis 	pba.pba_pmemex = sc->sc_memex;
189a6e4dcfbSkettenis 	pba.pba_domain = pci_ndomains++;
190a6e4dcfbSkettenis 	pba.pba_bus = sc->sc_bus;
191a6e4dcfbSkettenis 
192a6e4dcfbSkettenis 	/* Enable MSI in ACPI 2.0 and above, unless we're told not to. */
193a6e4dcfbSkettenis 	if (sc->sc_acpi->sc_fadt->hdr.revision >= 2 &&
194a6e4dcfbSkettenis 	    (sc->sc_acpi->sc_fadt->iapc_boot_arch & FADT_NO_MSI) == 0)
195a6e4dcfbSkettenis 		pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
196a6e4dcfbSkettenis 
197*84053e14Sjsg 	/* Enable MSI for QEMU claiming ACPI 1.0 */
198*84053e14Sjsg 	tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 0, 0);
199*84053e14Sjsg 	id = pci_conf_read(pba.pba_pc, tag, PCI_SUBSYS_ID_REG);
200*84053e14Sjsg 	if (sc->sc_acpi->sc_fadt->hdr.revision == 1 &&
201*84053e14Sjsg 	    PCI_VENDOR(id) == PCI_VENDOR_QUMRANET)
202*84053e14Sjsg 		pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
203*84053e14Sjsg 
204a6e4dcfbSkettenis 	/*
20536fd90dcSjsg 	 * Don't enable MSI on chipsets from low-end manufacturers
206a6e4dcfbSkettenis 	 * like VIA and SiS.  We do this by looking at the host
207a6e4dcfbSkettenis 	 * bridge, which should be device 0 function 0.
208a6e4dcfbSkettenis 	 */
209a6e4dcfbSkettenis 	id = pci_conf_read(pba.pba_pc, tag, PCI_ID_REG);
210a6e4dcfbSkettenis 	class = pci_conf_read(pba.pba_pc, tag, PCI_CLASS_REG);
211a6e4dcfbSkettenis 	if (PCI_CLASS(class) == PCI_CLASS_BRIDGE &&
212a6e4dcfbSkettenis 	    PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_HOST &&
213a6e4dcfbSkettenis 	    PCI_VENDOR(id) != PCI_VENDOR_AMD &&
214a6e4dcfbSkettenis 	    PCI_VENDOR(id) != PCI_VENDOR_NVIDIA &&
215a6e4dcfbSkettenis 	    PCI_VENDOR(id) != PCI_VENDOR_INTEL)
216a6e4dcfbSkettenis 		pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
217a6e4dcfbSkettenis 
218a6e4dcfbSkettenis 	/*
219a6e4dcfbSkettenis 	 * Don't enable MSI on a HyperTransport bus.  In order to
220a6e4dcfbSkettenis 	 * determine that a bus is a HyperTransport bus, we look at
221a6e4dcfbSkettenis 	 * device 24 function 0, which is the HyperTransport
222a6e4dcfbSkettenis 	 * host/primary interface integrated on most 64-bit AMD CPUs.
223a6e4dcfbSkettenis 	 * If that device has a HyperTransport capability, this must
224a6e4dcfbSkettenis 	 * be a HyperTransport bus and we disable MSI.
225a6e4dcfbSkettenis 	 */
226a6e4dcfbSkettenis 	tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 24, 0);
227a6e4dcfbSkettenis 	if (pci_get_capability(pba.pba_pc, tag, PCI_CAP_HT, NULL, NULL))
228a6e4dcfbSkettenis 		pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
229a6e4dcfbSkettenis 
230a6e4dcfbSkettenis 	config_found(parent, &pba, acpipci_print);
231a6e4dcfbSkettenis }
232a6e4dcfbSkettenis 
233a6e4dcfbSkettenis void
234a6e4dcfbSkettenis acpipci_attach_busses(struct device *parent)
235a6e4dcfbSkettenis {
236a6e4dcfbSkettenis 	int i;
237a6e4dcfbSkettenis 
238a6e4dcfbSkettenis 	for (i = 0; i < acpipci_cd.cd_ndevs; i++) {
239a6e4dcfbSkettenis 		if (acpipci_cd.cd_devs[i])
240a6e4dcfbSkettenis 			acpipci_attach_bus(parent, acpipci_cd.cd_devs[i]);
241a6e4dcfbSkettenis 	}
242a6e4dcfbSkettenis }
243a6e4dcfbSkettenis 
244a6e4dcfbSkettenis int
245a6e4dcfbSkettenis acpipci_print(void *aux, const char *pnp)
246a6e4dcfbSkettenis {
247a6e4dcfbSkettenis 	struct pcibus_attach_args *pba = aux;
248a6e4dcfbSkettenis 
249a6e4dcfbSkettenis 	if (pnp)
250a6e4dcfbSkettenis 		printf("%s at %s", pba->pba_busname, pnp);
251a6e4dcfbSkettenis 	printf(" bus %d", pba->pba_bus);
252a6e4dcfbSkettenis 	return (UNCONF);
253a6e4dcfbSkettenis }
254a6e4dcfbSkettenis 
255a6e4dcfbSkettenis int
256a6e4dcfbSkettenis acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
257a6e4dcfbSkettenis {
258a6e4dcfbSkettenis 	struct acpipci_softc *sc = arg;
259a6e4dcfbSkettenis 	int type = AML_CRSTYPE(crs);
260a6e4dcfbSkettenis 	int restype, tflags = 0;
261a6e4dcfbSkettenis 	u_long min, len = 0, tra = 0;
262a6e4dcfbSkettenis 
263a6e4dcfbSkettenis 	switch (type) {
264a6e4dcfbSkettenis 	case LR_WORD:
265a6e4dcfbSkettenis 		restype = crs->lr_word.type;
266a6e4dcfbSkettenis 		tflags = crs->lr_word.tflags;
267a6e4dcfbSkettenis 		min = crs->lr_word._min;
268a6e4dcfbSkettenis 		len = crs->lr_word._len;
269a6e4dcfbSkettenis 		tra = crs->lr_word._tra;
270a6e4dcfbSkettenis 		break;
271a6e4dcfbSkettenis 	case LR_DWORD:
272a6e4dcfbSkettenis 		restype = crs->lr_dword.type;
273a6e4dcfbSkettenis 		tflags = crs->lr_dword.tflags;
274a6e4dcfbSkettenis 		min = crs->lr_dword._min;
275a6e4dcfbSkettenis 		len = crs->lr_dword._len;
276a6e4dcfbSkettenis 		tra = crs->lr_dword._tra;
277a6e4dcfbSkettenis 		break;
278a6e4dcfbSkettenis 	case LR_QWORD:
279a6e4dcfbSkettenis 		restype = crs->lr_qword.type;
280a6e4dcfbSkettenis 		tflags = crs->lr_qword.tflags;
281a6e4dcfbSkettenis 		min = crs->lr_qword._min;
282a6e4dcfbSkettenis 		len = crs->lr_qword._len;
283a6e4dcfbSkettenis 		tra = crs->lr_qword._tra;
284a6e4dcfbSkettenis 		break;
285a6e4dcfbSkettenis 	case LR_MEM32FIXED:
286a6e4dcfbSkettenis 		/*
287a6e4dcfbSkettenis 		 * Coreboot on the PC Engines apu2 incorrectly uses a
288a6e4dcfbSkettenis 		 * Memory32Fixed resource descriptor to describe mmio
289a6e4dcfbSkettenis 		 * address space forwarded to the PCI bus.
290a6e4dcfbSkettenis 		 */
291a6e4dcfbSkettenis 		restype = LR_TYPE_MEMORY;
292a6e4dcfbSkettenis 		min = crs->lr_m32fixed._bas;
293a6e4dcfbSkettenis 		len = crs->lr_m32fixed._len;
294a6e4dcfbSkettenis 		break;
295a6e4dcfbSkettenis 	}
296a6e4dcfbSkettenis 
297a6e4dcfbSkettenis 	if (len == 0)
298a6e4dcfbSkettenis 		return 0;
299a6e4dcfbSkettenis 
300a6e4dcfbSkettenis 	switch (restype) {
301a6e4dcfbSkettenis 	case LR_TYPE_MEMORY:
302a6e4dcfbSkettenis 		if (tflags & LR_MEMORY_TTP)
303a6e4dcfbSkettenis 			return 0;
304a6e4dcfbSkettenis 		extent_free(sc->sc_memex, min, len, EX_WAITOK | EX_CONFLICTOK);
305a6e4dcfbSkettenis 		break;
306a6e4dcfbSkettenis 	case LR_TYPE_IO:
307a6e4dcfbSkettenis 		if (tflags & LR_IO_TTP)
308a6e4dcfbSkettenis 			return 0;
309a6e4dcfbSkettenis 		extent_free(sc->sc_ioex, min, len, EX_WAITOK | EX_CONFLICTOK);
310a6e4dcfbSkettenis 		break;
311a6e4dcfbSkettenis 	case LR_TYPE_BUS:
312a6e4dcfbSkettenis 		extent_free(sc->sc_busex, min, len, EX_WAITOK);
313a6e4dcfbSkettenis 		/*
314a6e4dcfbSkettenis 		 * Let _CRS minimum bus number override _BBN.
315a6e4dcfbSkettenis 		 */
316a6e4dcfbSkettenis 		sc->sc_bus = min;
317a6e4dcfbSkettenis 		break;
318a6e4dcfbSkettenis 	}
319a6e4dcfbSkettenis 
320a6e4dcfbSkettenis 	return 0;
321a6e4dcfbSkettenis }
322a6e4dcfbSkettenis 
323a6e4dcfbSkettenis void
324a6e4dcfbSkettenis acpipci_osc(struct acpipci_softc *sc)
325a6e4dcfbSkettenis {
326a6e4dcfbSkettenis 	struct aml_value args[4];
327a6e4dcfbSkettenis 	struct aml_value res;
328a6e4dcfbSkettenis 	static uint8_t uuid[16] = ACPI_PCI_UUID;
329a6e4dcfbSkettenis 	uint32_t buf[3];
330a6e4dcfbSkettenis 
33103a88dc8Skettenis 	memset(args, 0, sizeof(args));
33203a88dc8Skettenis 	args[0].type = AML_OBJTYPE_BUFFER;
33303a88dc8Skettenis 	args[0].v_buffer = uuid;
33403a88dc8Skettenis 	args[0].length = sizeof(uuid);
33503a88dc8Skettenis 	args[1].type = AML_OBJTYPE_INTEGER;
33603a88dc8Skettenis 	args[1].v_integer = 1;
33703a88dc8Skettenis 	args[2].type = AML_OBJTYPE_INTEGER;
33803a88dc8Skettenis 	args[2].v_integer = 3;
33903a88dc8Skettenis 	args[3].type = AML_OBJTYPE_BUFFER;
34003a88dc8Skettenis 	args[3].v_buffer = (uint8_t *)buf;
34103a88dc8Skettenis 	args[3].length = sizeof(buf);
34203a88dc8Skettenis 
34303a88dc8Skettenis 	memset(buf, 0, sizeof(buf));
34403a88dc8Skettenis 	buf[0] = 0x0;
34503a88dc8Skettenis 	buf[1] = ACPI_PCI_PCIE_CONFIG | ACPI_PCI_MSI;
34603a88dc8Skettenis 	buf[2] = ACPI_PCI_PCIE_HOTPLUG;
34703a88dc8Skettenis 
348a6e4dcfbSkettenis 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_OSC", 4, args, &res))
34903a88dc8Skettenis 		return;
35003a88dc8Skettenis 
35103a88dc8Skettenis 	if (res.type == AML_OBJTYPE_BUFFER) {
35203a88dc8Skettenis 		size_t len = res.length;
35303a88dc8Skettenis 		uint32_t *p = (uint32_t *)res.v_buffer;
35403a88dc8Skettenis 
35503a88dc8Skettenis 		printf(":");
35603a88dc8Skettenis 		while (len >= 4) {
35703a88dc8Skettenis 			printf(" 0x%08x", *p);
35803a88dc8Skettenis 			p++;
35903a88dc8Skettenis 			len -= 4;
36003a88dc8Skettenis 		}
36103a88dc8Skettenis 	}
36203a88dc8Skettenis }
363