xref: /netbsd-src/sys/arch/arm/acpi/acpi_pci_machdep.c (revision 9c4bb73692a82581b61ab51b97ffd672f74b9652)
1*9c4bb736Sjmcneill /* $NetBSD: acpi_pci_machdep.c,v 1.22 2022/08/13 20:07:13 jmcneill Exp $ */
2e2ed649eSjmcneill 
3e2ed649eSjmcneill /*-
4cf660908Sad  * Copyright (c) 2018, 2020 The NetBSD Foundation, Inc.
5e2ed649eSjmcneill  * All rights reserved.
6e2ed649eSjmcneill  *
7e2ed649eSjmcneill  * This code is derived from software contributed to The NetBSD Foundation
8e2ed649eSjmcneill  * by Jared McNeill <jmcneill@invisible.ca>.
9e2ed649eSjmcneill  *
10e2ed649eSjmcneill  * Redistribution and use in source and binary forms, with or without
11e2ed649eSjmcneill  * modification, are permitted provided that the following conditions
12e2ed649eSjmcneill  * are met:
13e2ed649eSjmcneill  * 1. Redistributions of source code must retain the above copyright
14e2ed649eSjmcneill  *    notice, this list of conditions and the following disclaimer.
15e2ed649eSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
16e2ed649eSjmcneill  *    notice, this list of conditions and the following disclaimer in the
17e2ed649eSjmcneill  *    documentation and/or other materials provided with the distribution.
18e2ed649eSjmcneill  *
19e2ed649eSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e2ed649eSjmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e2ed649eSjmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e2ed649eSjmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e2ed649eSjmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e2ed649eSjmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e2ed649eSjmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e2ed649eSjmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e2ed649eSjmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e2ed649eSjmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e2ed649eSjmcneill  * POSSIBILITY OF SUCH DAMAGE.
30e2ed649eSjmcneill  */
31e2ed649eSjmcneill 
3212a41c4dSjmcneill #include "opt_pci.h"
3312a41c4dSjmcneill 
3453f33807Sjmcneill #define	_INTR_PRIVATE
3553f33807Sjmcneill 
36e2ed649eSjmcneill #include <sys/cdefs.h>
37*9c4bb736Sjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_pci_machdep.c,v 1.22 2022/08/13 20:07:13 jmcneill Exp $");
38e2ed649eSjmcneill 
39e2ed649eSjmcneill #include <sys/param.h>
40e2ed649eSjmcneill #include <sys/bus.h>
41e2ed649eSjmcneill #include <sys/device.h>
42e2ed649eSjmcneill #include <sys/intr.h>
43e2ed649eSjmcneill #include <sys/systm.h>
44e2ed649eSjmcneill #include <sys/kernel.h>
45e2ed649eSjmcneill #include <sys/queue.h>
46e2ed649eSjmcneill #include <sys/mutex.h>
47e2ed649eSjmcneill #include <sys/kmem.h>
48cf660908Sad #include <sys/cpu.h>
49e2ed649eSjmcneill 
50e2ed649eSjmcneill #include <arm/cpufunc.h>
51e2ed649eSjmcneill 
5253f33807Sjmcneill #include <arm/pic/picvar.h>
5353f33807Sjmcneill 
54e2ed649eSjmcneill #include <dev/pci/pcireg.h>
55e2ed649eSjmcneill #include <dev/pci/pcivar.h>
56e2ed649eSjmcneill #include <dev/pci/pciconf.h>
57e2ed649eSjmcneill 
58e2ed649eSjmcneill #include <dev/acpi/acpivar.h>
59e2ed649eSjmcneill #include <dev/acpi/acpi_mcfg.h>
60e2ed649eSjmcneill #include <dev/acpi/acpi_pci.h>
61e2ed649eSjmcneill 
62e23c320eSjmcneill #include <arm/acpi/acpi_iort.h>
634fb00351Sjmcneill #include <arm/acpi/acpi_pci_machdep.h>
644fb00351Sjmcneill 
6512a41c4dSjmcneill #ifdef PCI_SMCCC
6612a41c4dSjmcneill #include <arm/pci/pci_smccc.h>
6712a41c4dSjmcneill #endif
6812a41c4dSjmcneill 
69187fa5a9Sjmcneill #include <arm/pci/pci_msi_machdep.h>
70e2ed649eSjmcneill 
71e2ed649eSjmcneill struct acpi_pci_prt {
72760c661cSjmcneill 	u_int				prt_segment;
73e2ed649eSjmcneill 	u_int				prt_bus;
74*9c4bb736Sjmcneill 	u_int				prt_bridge_dev;
75*9c4bb736Sjmcneill 	bool				prt_derived;
76e2ed649eSjmcneill 	ACPI_HANDLE			prt_handle;
77e2ed649eSjmcneill 	TAILQ_ENTRY(acpi_pci_prt)	prt_list;
78e2ed649eSjmcneill };
79e2ed649eSjmcneill 
80e2ed649eSjmcneill static TAILQ_HEAD(, acpi_pci_prt) acpi_pci_irq_routes =
81e2ed649eSjmcneill     TAILQ_HEAD_INITIALIZER(acpi_pci_irq_routes);
82e2ed649eSjmcneill 
836f25f864Sjmcneill struct acpi_pci_pct {
846f25f864Sjmcneill 	struct acpi_pci_context		pct_ap;
856f25f864Sjmcneill 	TAILQ_ENTRY(acpi_pci_pct)	pct_list;
866f25f864Sjmcneill };
876f25f864Sjmcneill 
886f25f864Sjmcneill static TAILQ_HEAD(, acpi_pci_pct) acpi_pci_chipset_tags =
896f25f864Sjmcneill     TAILQ_HEAD_INITIALIZER(acpi_pci_chipset_tags);
906f25f864Sjmcneill 
9153f33807Sjmcneill struct acpi_pci_intr {
9253f33807Sjmcneill 	struct pic_softc		pi_pic;
9353f33807Sjmcneill 	int				pi_irqbase;
9453f33807Sjmcneill 	int				pi_irq;
9553f33807Sjmcneill 	uint32_t			pi_unblocked;
9653f33807Sjmcneill 	void				*pi_ih;
9753f33807Sjmcneill 	TAILQ_ENTRY(acpi_pci_intr)	pi_list;
9853f33807Sjmcneill };
9953f33807Sjmcneill 
10053f33807Sjmcneill static TAILQ_HEAD(, acpi_pci_intr) acpi_pci_intrs =
10153f33807Sjmcneill     TAILQ_HEAD_INITIALIZER(acpi_pci_intrs);
10253f33807Sjmcneill 
10312a41c4dSjmcneill static const struct acpi_pci_quirk acpi_pci_mcfg_quirks[] = {
1046f25f864Sjmcneill 	/* OEM ID	OEM Table ID	Revision	Seg	Func */
1056f25f864Sjmcneill 	{ "AMAZON",	"GRAVITON",	0,		-1,	acpi_pci_graviton_init },
1066f25f864Sjmcneill 	{ "ARMLTD",	"ARMN1SDP",	0x20181101,	0,	acpi_pci_n1sdp_init },
1076f25f864Sjmcneill 	{ "ARMLTD",	"ARMN1SDP",	0x20181101,	1,	acpi_pci_n1sdp_init },
1081583ac80Sjmcneill 	{ "NXP   ",     "LX2160  ",     0,              -1,	acpi_pci_layerscape_gen4_init },
1096f25f864Sjmcneill };
1106f25f864Sjmcneill 
11112a41c4dSjmcneill #ifdef PCI_SMCCC
11212a41c4dSjmcneill static const struct acpi_pci_quirk acpi_pci_smccc_quirk = {
11312a41c4dSjmcneill 	.q_segment = -1,
11412a41c4dSjmcneill 	.q_init = acpi_pci_smccc_init,
11512a41c4dSjmcneill };
11612a41c4dSjmcneill #endif
11712a41c4dSjmcneill 
1186f25f864Sjmcneill pci_chipset_tag_t acpi_pci_md_get_chipset_tag(struct acpi_softc *, int, int);
1196f25f864Sjmcneill 
120e2ed649eSjmcneill static void	acpi_pci_md_attach_hook(device_t, device_t,
121e2ed649eSjmcneill 				       struct pcibus_attach_args *);
122e2ed649eSjmcneill static int	acpi_pci_md_bus_maxdevs(void *, int);
123e2ed649eSjmcneill static pcitag_t	acpi_pci_md_make_tag(void *, int, int, int);
124e2ed649eSjmcneill static void	acpi_pci_md_decompose_tag(void *, pcitag_t, int *, int *, int *);
12599199cfcSjmcneill static u_int	acpi_pci_md_get_segment(void *);
126e23c320eSjmcneill static uint32_t	acpi_pci_md_get_devid(void *, uint32_t);
1278b7fb0a6Sjmcneill static uint32_t	acpi_pci_md_get_frameid(void *, uint32_t);
128e2ed649eSjmcneill static pcireg_t	acpi_pci_md_conf_read(void *, pcitag_t, int);
129e2ed649eSjmcneill static void	acpi_pci_md_conf_write(void *, pcitag_t, int, pcireg_t);
130e2ed649eSjmcneill static int	acpi_pci_md_conf_hook(void *, int, int, int, pcireg_t);
131e2ed649eSjmcneill static void	acpi_pci_md_conf_interrupt(void *, int, int, int, int, int *);
132e2ed649eSjmcneill 
133e2ed649eSjmcneill static int	acpi_pci_md_intr_map(const struct pci_attach_args *,
134e2ed649eSjmcneill 				    pci_intr_handle_t *);
135e2ed649eSjmcneill static const char *acpi_pci_md_intr_string(void *, pci_intr_handle_t,
136e2ed649eSjmcneill 					  char *, size_t);
137e2ed649eSjmcneill static const struct evcnt *acpi_pci_md_intr_evcnt(void *, pci_intr_handle_t);
138e2ed649eSjmcneill static int	acpi_pci_md_intr_setattr(void *, pci_intr_handle_t *, int,
139e2ed649eSjmcneill 					uint64_t);
140e2ed649eSjmcneill static void *	acpi_pci_md_intr_establish(void *, pci_intr_handle_t,
141cce19cc2Sjmcneill 					 int, int (*)(void *), void *,
142cce19cc2Sjmcneill 					 const char *);
143e2ed649eSjmcneill static void	acpi_pci_md_intr_disestablish(void *, void *);
144e2ed649eSjmcneill 
145e2ed649eSjmcneill struct arm32_pci_chipset arm_acpi_pci_chipset = {
146e2ed649eSjmcneill 	.pc_attach_hook = acpi_pci_md_attach_hook,
147e2ed649eSjmcneill 	.pc_bus_maxdevs = acpi_pci_md_bus_maxdevs,
148e2ed649eSjmcneill 	.pc_make_tag = acpi_pci_md_make_tag,
149e2ed649eSjmcneill 	.pc_decompose_tag = acpi_pci_md_decompose_tag,
15099199cfcSjmcneill 	.pc_get_segment = acpi_pci_md_get_segment,
151e23c320eSjmcneill 	.pc_get_devid = acpi_pci_md_get_devid,
1528b7fb0a6Sjmcneill 	.pc_get_frameid = acpi_pci_md_get_frameid,
153e2ed649eSjmcneill 	.pc_conf_read = acpi_pci_md_conf_read,
154e2ed649eSjmcneill 	.pc_conf_write = acpi_pci_md_conf_write,
155e2ed649eSjmcneill 	.pc_conf_hook = acpi_pci_md_conf_hook,
156e2ed649eSjmcneill 	.pc_conf_interrupt = acpi_pci_md_conf_interrupt,
157e2ed649eSjmcneill 
158e2ed649eSjmcneill 	.pc_intr_map = acpi_pci_md_intr_map,
159e2ed649eSjmcneill 	.pc_intr_string = acpi_pci_md_intr_string,
160e2ed649eSjmcneill 	.pc_intr_evcnt = acpi_pci_md_intr_evcnt,
161e2ed649eSjmcneill 	.pc_intr_setattr = acpi_pci_md_intr_setattr,
162e2ed649eSjmcneill 	.pc_intr_establish = acpi_pci_md_intr_establish,
163e2ed649eSjmcneill 	.pc_intr_disestablish = acpi_pci_md_intr_disestablish,
164e2ed649eSjmcneill };
165e2ed649eSjmcneill 
166e2ed649eSjmcneill static ACPI_STATUS
acpi_pci_md_pci_link(ACPI_HANDLE handle,pci_chipset_tag_t pc,int bus)1676f25f864Sjmcneill acpi_pci_md_pci_link(ACPI_HANDLE handle, pci_chipset_tag_t pc, int bus)
168e2ed649eSjmcneill {
169e2ed649eSjmcneill 	ACPI_PCI_ROUTING_TABLE *prt;
170e2ed649eSjmcneill 	ACPI_HANDLE linksrc;
171e2ed649eSjmcneill 	ACPI_BUFFER buf;
172e2ed649eSjmcneill 	ACPI_STATUS rv;
173e2ed649eSjmcneill 	void *linkdev;
174e2ed649eSjmcneill 
175e2ed649eSjmcneill 	rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
176e2ed649eSjmcneill 	if (ACPI_FAILURE(rv))
177e2ed649eSjmcneill 		return rv;
178e2ed649eSjmcneill 
179e2ed649eSjmcneill 	for (char *p = buf.Pointer; ; p += prt->Length) {
180e2ed649eSjmcneill 		prt = (ACPI_PCI_ROUTING_TABLE *)p;
181e2ed649eSjmcneill 		if (prt->Length == 0)
182e2ed649eSjmcneill 			break;
183e2ed649eSjmcneill 
184e2ed649eSjmcneill 		const u_int dev = ACPI_HIWORD(prt->Address);
185e2ed649eSjmcneill 		if (prt->Source[0] != 0) {
186e2ed649eSjmcneill 			aprint_debug("ACPI: %s dev %u INT%c on lnkdev %s\n",
187e2ed649eSjmcneill 			    acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->Source);
188e2ed649eSjmcneill 			rv = AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &linksrc);
189e2ed649eSjmcneill 			if (ACPI_FAILURE(rv)) {
190e2ed649eSjmcneill 				aprint_debug("ACPI: AcpiGetHandle failed for '%s': %s\n",
191e2ed649eSjmcneill 				    prt->Source, AcpiFormatException(rv));
192e2ed649eSjmcneill 				continue;
193e2ed649eSjmcneill 			}
194e2ed649eSjmcneill 
195e2ed649eSjmcneill 			linkdev = acpi_pci_link_devbyhandle(linksrc);
1966f25f864Sjmcneill 			acpi_pci_link_add_reference(linkdev, pc, 0, bus, dev, prt->Pin & 3);
197e2ed649eSjmcneill 		} else {
198e2ed649eSjmcneill 			aprint_debug("ACPI: %s dev %u INT%c on globint %d\n",
199e2ed649eSjmcneill 			    acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->SourceIndex);
200e2ed649eSjmcneill 		}
201e2ed649eSjmcneill 	}
202e2ed649eSjmcneill 
203e2ed649eSjmcneill 	return AE_OK;
204e2ed649eSjmcneill }
205e2ed649eSjmcneill 
206e2ed649eSjmcneill static void
acpi_pci_md_attach_hook(device_t parent,device_t self,struct pcibus_attach_args * pba)207e2ed649eSjmcneill acpi_pci_md_attach_hook(device_t parent, device_t self,
208e2ed649eSjmcneill     struct pcibus_attach_args *pba)
209e2ed649eSjmcneill {
2104fb00351Sjmcneill 	struct acpi_pci_context *ap = pba->pba_pc->pc_conf_v;
211e2ed649eSjmcneill 	struct acpi_pci_prt *prt, *prtp;
212e2ed649eSjmcneill 	struct acpi_devnode *ad;
213e2ed649eSjmcneill 	ACPI_HANDLE handle;
214e2ed649eSjmcneill 	int seg, bus, dev, func;
215*9c4bb736Sjmcneill 	u_int bridge_dev = 0;
216*9c4bb736Sjmcneill 	bool derived = false;
217e2ed649eSjmcneill 
2184fb00351Sjmcneill 	seg = ap->ap_seg;
219e2ed649eSjmcneill 	handle = NULL;
220e2ed649eSjmcneill 
221e2ed649eSjmcneill 	if (pba->pba_bridgetag) {
222e2ed649eSjmcneill 		/*
223e2ed649eSjmcneill 		 * Find the PCI address of our parent bridge and look for the
224e2ed649eSjmcneill 		 * corresponding ACPI device node. If there is no node for this
225e2ed649eSjmcneill 		 * bus, use the parent bridge routing information.
226e2ed649eSjmcneill 		 */
227e2ed649eSjmcneill 		acpi_pci_md_decompose_tag(NULL, *pba->pba_bridgetag, &bus, &dev, &func);
228e2ed649eSjmcneill 		ad = acpi_pcidev_find(seg, bus, dev, func);
229e2ed649eSjmcneill 		if (ad != NULL) {
230e2ed649eSjmcneill 			handle = ad->ad_handle;
231e2ed649eSjmcneill 		} else {
232*9c4bb736Sjmcneill 			/* No routes defined for this bus, derive from parent */
233e2ed649eSjmcneill 			TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list)
234*9c4bb736Sjmcneill 				if (prtp->prt_bus == bus &&
235*9c4bb736Sjmcneill 				    prtp->prt_segment == seg) {
236e2ed649eSjmcneill 					handle = prtp->prt_handle;
237*9c4bb736Sjmcneill 					bridge_dev = dev;
238*9c4bb736Sjmcneill 					derived = true;
239e2ed649eSjmcneill 					break;
240e2ed649eSjmcneill 				}
241e2ed649eSjmcneill 		}
242e2ed649eSjmcneill 	} else {
243e2ed649eSjmcneill 		/*
244e2ed649eSjmcneill 		 * Lookup the ACPI device node for the root bus.
245e2ed649eSjmcneill 		 */
246e2ed649eSjmcneill 		ad = acpi_pciroot_find(seg, 0);
247e2ed649eSjmcneill 		if (ad != NULL)
248e2ed649eSjmcneill 			handle = ad->ad_handle;
249e2ed649eSjmcneill 	}
250e2ed649eSjmcneill 
251e2ed649eSjmcneill 	if (handle != NULL) {
252e2ed649eSjmcneill 		prt = kmem_alloc(sizeof(*prt), KM_SLEEP);
253e2ed649eSjmcneill 		prt->prt_bus = pba->pba_bus;
254*9c4bb736Sjmcneill 		prt->prt_segment = seg;
255e2ed649eSjmcneill 		prt->prt_handle = handle;
256*9c4bb736Sjmcneill 		prt->prt_bridge_dev = bridge_dev;
257*9c4bb736Sjmcneill 		prt->prt_derived = derived;
258e2ed649eSjmcneill 		TAILQ_INSERT_TAIL(&acpi_pci_irq_routes, prt, prt_list);
259e2ed649eSjmcneill 	}
260e2ed649eSjmcneill 
261e2ed649eSjmcneill 	acpimcfg_map_bus(self, pba->pba_pc, pba->pba_bus);
2623d4bf5baSjmcneill 
2633d4bf5baSjmcneill 	if (ad != NULL) {
2643d4bf5baSjmcneill 		/*
2653d4bf5baSjmcneill 		 * This is a new ACPI managed bus. Add PCI link references.
2663d4bf5baSjmcneill 		 */
2676f25f864Sjmcneill 		acpi_pci_md_pci_link(ad->ad_handle, pba->pba_pc, pba->pba_bus);
2683d4bf5baSjmcneill 	}
269e2ed649eSjmcneill }
270e2ed649eSjmcneill 
271e2ed649eSjmcneill static int
acpi_pci_md_bus_maxdevs(void * v,int busno)272e2ed649eSjmcneill acpi_pci_md_bus_maxdevs(void *v, int busno)
273e2ed649eSjmcneill {
274e2ed649eSjmcneill 	return 32;
275e2ed649eSjmcneill }
276e2ed649eSjmcneill 
277e2ed649eSjmcneill static pcitag_t
acpi_pci_md_make_tag(void * v,int b,int d,int f)278e2ed649eSjmcneill acpi_pci_md_make_tag(void *v, int b, int d, int f)
279e2ed649eSjmcneill {
280e2ed649eSjmcneill 	return (b << 16) | (d << 11) | (f << 8);
281e2ed649eSjmcneill }
282e2ed649eSjmcneill 
283e2ed649eSjmcneill static void
acpi_pci_md_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)284e2ed649eSjmcneill acpi_pci_md_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
285e2ed649eSjmcneill {
286e2ed649eSjmcneill 	if (bp)
287e2ed649eSjmcneill 		*bp = (tag >> 16) & 0xff;
288e2ed649eSjmcneill 	if (dp)
289e2ed649eSjmcneill 		*dp = (tag >> 11) & 0x1f;
290e2ed649eSjmcneill 	if (fp)
291e2ed649eSjmcneill 		*fp = (tag >> 8) & 0x7;
292e2ed649eSjmcneill }
293e2ed649eSjmcneill 
29499199cfcSjmcneill static u_int
acpi_pci_md_get_segment(void * v)29599199cfcSjmcneill acpi_pci_md_get_segment(void *v)
29699199cfcSjmcneill {
29799199cfcSjmcneill 	struct acpi_pci_context * const ap = v;
29899199cfcSjmcneill 
29999199cfcSjmcneill 	return ap->ap_seg;
30099199cfcSjmcneill }
30199199cfcSjmcneill 
302e23c320eSjmcneill static uint32_t
acpi_pci_md_get_devid(void * v,uint32_t devid)303e23c320eSjmcneill acpi_pci_md_get_devid(void *v, uint32_t devid)
304e23c320eSjmcneill {
305e23c320eSjmcneill 	struct acpi_pci_context * const ap = v;
306e23c320eSjmcneill 
307e23c320eSjmcneill 	return acpi_iort_pci_root_map(ap->ap_seg, devid);
308e23c320eSjmcneill }
309e23c320eSjmcneill 
3108b7fb0a6Sjmcneill static uint32_t
acpi_pci_md_get_frameid(void * v,uint32_t devid)3118b7fb0a6Sjmcneill acpi_pci_md_get_frameid(void *v, uint32_t devid)
3128b7fb0a6Sjmcneill {
3138b7fb0a6Sjmcneill 	struct acpi_pci_context * const ap = v;
3148b7fb0a6Sjmcneill 
3158b7fb0a6Sjmcneill 	return acpi_iort_its_id_map(ap->ap_seg, devid);
3168b7fb0a6Sjmcneill }
3178b7fb0a6Sjmcneill 
318e2ed649eSjmcneill static pcireg_t
acpi_pci_md_conf_read(void * v,pcitag_t tag,int offset)319e2ed649eSjmcneill acpi_pci_md_conf_read(void *v, pcitag_t tag, int offset)
320e2ed649eSjmcneill {
3214fb00351Sjmcneill 	struct acpi_pci_context * const ap = v;
322e2ed649eSjmcneill 	pcireg_t val;
323e2ed649eSjmcneill 
324e2ed649eSjmcneill 	if (offset < 0 || offset >= PCI_EXTCONF_SIZE)
325e2ed649eSjmcneill 		return (pcireg_t) -1;
326e2ed649eSjmcneill 
3274d90935bSjmcneill 	if (ap->ap_conf_read != NULL)
3284d90935bSjmcneill 		ap->ap_conf_read(&ap->ap_pc, tag, offset, &val);
3294d90935bSjmcneill 	else
3304fb00351Sjmcneill 		acpimcfg_conf_read(&ap->ap_pc, tag, offset, &val);
331e2ed649eSjmcneill 
332e2ed649eSjmcneill 	return val;
333e2ed649eSjmcneill }
334e2ed649eSjmcneill 
335e2ed649eSjmcneill static void
acpi_pci_md_conf_write(void * v,pcitag_t tag,int offset,pcireg_t val)336e2ed649eSjmcneill acpi_pci_md_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
337e2ed649eSjmcneill {
3384fb00351Sjmcneill 	struct acpi_pci_context * const ap = v;
3394fb00351Sjmcneill 
340e2ed649eSjmcneill 	if (offset < 0 || offset >= PCI_EXTCONF_SIZE)
341e2ed649eSjmcneill 		return;
342e2ed649eSjmcneill 
3434d90935bSjmcneill 	if (ap->ap_conf_write != NULL)
3444d90935bSjmcneill 		ap->ap_conf_write(&ap->ap_pc, tag, offset, val);
3454d90935bSjmcneill 	else
3464fb00351Sjmcneill 		acpimcfg_conf_write(&ap->ap_pc, tag, offset, val);
347e2ed649eSjmcneill }
348e2ed649eSjmcneill 
349e2ed649eSjmcneill static int
acpi_pci_md_conf_hook(void * v,int b,int d,int f,pcireg_t id)350e2ed649eSjmcneill acpi_pci_md_conf_hook(void *v, int b, int d, int f, pcireg_t id)
351e2ed649eSjmcneill {
352e2ed649eSjmcneill 	return PCI_CONF_DEFAULT;
353e2ed649eSjmcneill }
354e2ed649eSjmcneill 
355e2ed649eSjmcneill static void
acpi_pci_md_conf_interrupt(void * v,int bus,int dev,int ipin,int sqiz,int * ilinep)356e2ed649eSjmcneill acpi_pci_md_conf_interrupt(void *v, int bus, int dev, int ipin, int sqiz, int *ilinep)
357e2ed649eSjmcneill {
358e2ed649eSjmcneill }
359e2ed649eSjmcneill 
360e2ed649eSjmcneill static struct acpi_pci_prt *
acpi_pci_md_intr_find_prt(pci_chipset_tag_t pc,u_int bus)361760c661cSjmcneill acpi_pci_md_intr_find_prt(pci_chipset_tag_t pc, u_int bus)
362e2ed649eSjmcneill {
363e2ed649eSjmcneill 	struct acpi_pci_prt *prt, *prtp;
364760c661cSjmcneill 	u_int segment;
365760c661cSjmcneill 
366760c661cSjmcneill 	segment = pci_get_segment(pc);
367e2ed649eSjmcneill 
368e2ed649eSjmcneill 	prt = NULL;
369e2ed649eSjmcneill 	TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list)
370760c661cSjmcneill 		if (prtp->prt_segment == segment && prtp->prt_bus == bus) {
371e2ed649eSjmcneill 			prt = prtp;
372e2ed649eSjmcneill 			break;
373e2ed649eSjmcneill 		}
374e2ed649eSjmcneill 
375e2ed649eSjmcneill 	return prt;
376e2ed649eSjmcneill }
377e2ed649eSjmcneill 
378e2ed649eSjmcneill static int
acpi_pci_md_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ih)379e2ed649eSjmcneill acpi_pci_md_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih)
380e2ed649eSjmcneill {
381e2ed649eSjmcneill 	struct acpi_pci_prt *prt;
382e2ed649eSjmcneill 	ACPI_PCI_ROUTING_TABLE *tab;
383e2ed649eSjmcneill 	int line, pol, trig, error;
384e2ed649eSjmcneill 	ACPI_HANDLE linksrc;
385e2ed649eSjmcneill 	ACPI_BUFFER buf;
386e2ed649eSjmcneill 	void *linkdev;
387*9c4bb736Sjmcneill 	u_int pin;
388e2ed649eSjmcneill 
389e2ed649eSjmcneill 	if (pa->pa_intrpin == PCI_INTERRUPT_PIN_NONE)
390e2ed649eSjmcneill 		return EINVAL;
391e2ed649eSjmcneill 
392760c661cSjmcneill 	prt = acpi_pci_md_intr_find_prt(pa->pa_pc, pa->pa_bus);
393e2ed649eSjmcneill 	if (prt == NULL)
394e2ed649eSjmcneill 		return ENXIO;
395e2ed649eSjmcneill 
396e2ed649eSjmcneill 	if (ACPI_FAILURE(acpi_get(prt->prt_handle, &buf, AcpiGetIrqRoutingTable)))
397e2ed649eSjmcneill 		return EIO;
398e2ed649eSjmcneill 
399*9c4bb736Sjmcneill 	/*
400*9c4bb736Sjmcneill 	 * For busses with no direct _PRT entry, derive the pin from the
401*9c4bb736Sjmcneill 	 * parent bridge.
402*9c4bb736Sjmcneill 	 */
403*9c4bb736Sjmcneill 	if (prt->prt_derived) {
404*9c4bb736Sjmcneill 		pin = (((pa->pa_rawintrpin + prt->prt_bridge_dev) - 1) % 4) + 1;
405*9c4bb736Sjmcneill 	} else {
406*9c4bb736Sjmcneill 		pin = pa->pa_intrpin;
407*9c4bb736Sjmcneill 	}
408*9c4bb736Sjmcneill 
409*9c4bb736Sjmcneill 	aprint_debug("%s: bus=%u pin=%u pa_rawintrpin=%u pa_intrpin=%u "
410*9c4bb736Sjmcneill 		     "pa_intrswiz=%u prt_bridge_dev=%u\n",
411*9c4bb736Sjmcneill        		     __func__, pa->pa_bus, pin, pa->pa_rawintrpin,
412*9c4bb736Sjmcneill 		     pa->pa_intrpin, pa->pa_intrswiz, prt->prt_bridge_dev);
413*9c4bb736Sjmcneill 
414e2ed649eSjmcneill 	error = ENOENT;
415e2ed649eSjmcneill 	for (char *p = buf.Pointer; ; p += tab->Length) {
416e2ed649eSjmcneill 		tab = (ACPI_PCI_ROUTING_TABLE *)p;
417e2ed649eSjmcneill 		if (tab->Length == 0)
418e2ed649eSjmcneill 			break;
419e2ed649eSjmcneill 
420e2ed649eSjmcneill 		if (pa->pa_device == ACPI_HIWORD(tab->Address) &&
421*9c4bb736Sjmcneill 		    (pin - 1) == (tab->Pin & 3)) {
422e2ed649eSjmcneill 			if (tab->Source[0] != 0) {
423e2ed649eSjmcneill 				if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, tab->Source, &linksrc)))
424e2ed649eSjmcneill 					goto done;
425e2ed649eSjmcneill 				linkdev = acpi_pci_link_devbyhandle(linksrc);
4266f25f864Sjmcneill 				*ih = acpi_pci_link_route_interrupt(linkdev,
4276f25f864Sjmcneill 				    pa->pa_pc, tab->SourceIndex,
428e2ed649eSjmcneill 				    &line, &pol, &trig);
429e2ed649eSjmcneill 				error = 0;
430e2ed649eSjmcneill 				goto done;
431e2ed649eSjmcneill 			} else {
432e2ed649eSjmcneill 				*ih = tab->SourceIndex;
433e2ed649eSjmcneill 				error = 0;
434e2ed649eSjmcneill 				goto done;
435e2ed649eSjmcneill 			}
436e2ed649eSjmcneill 		}
437e2ed649eSjmcneill 	}
438e2ed649eSjmcneill 
439e2ed649eSjmcneill done:
440e2ed649eSjmcneill 	ACPI_FREE(buf.Pointer);
441e2ed649eSjmcneill 	return error;
442e2ed649eSjmcneill }
443e2ed649eSjmcneill 
444e2ed649eSjmcneill static const char *
acpi_pci_md_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)445e2ed649eSjmcneill acpi_pci_md_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
446e2ed649eSjmcneill {
447187fa5a9Sjmcneill 	const int irq = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ);
4488537f778Sjmcneill 	const int vec = __SHIFTOUT(ih, ARM_PCI_INTR_MSI_VEC);
449187fa5a9Sjmcneill 
4508537f778Sjmcneill 	if (ih & ARM_PCI_INTR_MSIX)
4518537f778Sjmcneill 		snprintf(buf, len, "irq %d (MSI-X vec %d)", irq, vec);
4528537f778Sjmcneill 	else if (ih & ARM_PCI_INTR_MSI)
4538537f778Sjmcneill 		snprintf(buf, len, "irq %d (MSI vec %d)", irq, vec);
454187fa5a9Sjmcneill 	else
455187fa5a9Sjmcneill 		snprintf(buf, len, "irq %d", irq);
456187fa5a9Sjmcneill 
457e2ed649eSjmcneill 	return buf;
458e2ed649eSjmcneill }
459e2ed649eSjmcneill 
460e2ed649eSjmcneill static const struct evcnt *
acpi_pci_md_intr_evcnt(void * v,pci_intr_handle_t ih)461e2ed649eSjmcneill acpi_pci_md_intr_evcnt(void *v, pci_intr_handle_t ih)
462e2ed649eSjmcneill {
463e2ed649eSjmcneill 	return NULL;
464e2ed649eSjmcneill }
465e2ed649eSjmcneill 
466e2ed649eSjmcneill static int
acpi_pci_md_intr_setattr(void * v,pci_intr_handle_t * ih,int attr,uint64_t data)467e2ed649eSjmcneill acpi_pci_md_intr_setattr(void *v, pci_intr_handle_t *ih, int attr, uint64_t data)
468e2ed649eSjmcneill {
469e2ed649eSjmcneill 	switch (attr) {
470e2ed649eSjmcneill 	case PCI_INTR_MPSAFE:
471e2ed649eSjmcneill 		if (data)
472187fa5a9Sjmcneill 			*ih |= ARM_PCI_INTR_MPSAFE;
473e2ed649eSjmcneill 		else
474187fa5a9Sjmcneill 			*ih &= ~ARM_PCI_INTR_MPSAFE;
475e2ed649eSjmcneill 		return 0;
476e2ed649eSjmcneill 	default:
477e2ed649eSjmcneill 		return ENODEV;
478e2ed649eSjmcneill 	}
479e2ed649eSjmcneill }
480e2ed649eSjmcneill 
48153f33807Sjmcneill static struct acpi_pci_intr *
acpi_pci_md_intr_lookup(int irq)48253f33807Sjmcneill acpi_pci_md_intr_lookup(int irq)
48353f33807Sjmcneill {
48453f33807Sjmcneill 	struct acpi_pci_intr *pi;
48553f33807Sjmcneill 
48653f33807Sjmcneill 	TAILQ_FOREACH(pi, &acpi_pci_intrs, pi_list)
48753f33807Sjmcneill 		if (pi->pi_irq == irq)
48853f33807Sjmcneill 			return pi;
48953f33807Sjmcneill 
49053f33807Sjmcneill 	return NULL;
49153f33807Sjmcneill }
49253f33807Sjmcneill 
49353f33807Sjmcneill static void
acpi_pci_md_unblock_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irqmask)49453f33807Sjmcneill acpi_pci_md_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irqmask)
49553f33807Sjmcneill {
49653f33807Sjmcneill 	struct acpi_pci_intr * const pi = (struct acpi_pci_intr *)pic;
49753f33807Sjmcneill 
49853f33807Sjmcneill 	pi->pi_unblocked |= irqmask;
49953f33807Sjmcneill }
50053f33807Sjmcneill 
50153f33807Sjmcneill static void
acpi_pci_md_block_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irqmask)50253f33807Sjmcneill acpi_pci_md_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irqmask)
50353f33807Sjmcneill {
50453f33807Sjmcneill 	struct acpi_pci_intr * const pi = (struct acpi_pci_intr *)pic;
50553f33807Sjmcneill 
50653f33807Sjmcneill 	pi->pi_unblocked &= ~irqmask;
50753f33807Sjmcneill }
50853f33807Sjmcneill 
50953f33807Sjmcneill static int
acpi_pci_md_find_pending_irqs(struct pic_softc * pic)51053f33807Sjmcneill acpi_pci_md_find_pending_irqs(struct pic_softc *pic)
51153f33807Sjmcneill {
51253f33807Sjmcneill 	struct acpi_pci_intr * const pi = (struct acpi_pci_intr *)pic;
51353f33807Sjmcneill 
51453f33807Sjmcneill 	pic_mark_pending_sources(pic, 0, pi->pi_unblocked);
51553f33807Sjmcneill 
51653f33807Sjmcneill 	return 1;
51753f33807Sjmcneill }
51853f33807Sjmcneill 
51953f33807Sjmcneill static void
acpi_pci_md_establish_irq(struct pic_softc * pic,struct intrsource * is)52053f33807Sjmcneill acpi_pci_md_establish_irq(struct pic_softc *pic, struct intrsource *is)
52153f33807Sjmcneill {
52253f33807Sjmcneill }
52353f33807Sjmcneill 
52453f33807Sjmcneill static void
acpi_pci_md_source_name(struct pic_softc * pic,int irq,char * buf,size_t len)52553f33807Sjmcneill acpi_pci_md_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
52653f33807Sjmcneill {
52753f33807Sjmcneill 	snprintf(buf, len, "slot %d", irq);
52853f33807Sjmcneill }
52953f33807Sjmcneill 
53053f33807Sjmcneill static struct pic_ops acpi_pci_pic_ops = {
53153f33807Sjmcneill 	.pic_unblock_irqs = acpi_pci_md_unblock_irqs,
53253f33807Sjmcneill 	.pic_block_irqs = acpi_pci_md_block_irqs,
53353f33807Sjmcneill 	.pic_find_pending_irqs = acpi_pci_md_find_pending_irqs,
53453f33807Sjmcneill 	.pic_establish_irq = acpi_pci_md_establish_irq,
53553f33807Sjmcneill 	.pic_source_name = acpi_pci_md_source_name,
53653f33807Sjmcneill };
53753f33807Sjmcneill 
538e2ed649eSjmcneill static void *
acpi_pci_md_intr_establish(void * v,pci_intr_handle_t ih,int ipl,int (* callback)(void *),void * arg,const char * xname)539e2ed649eSjmcneill acpi_pci_md_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
540cce19cc2Sjmcneill     int (*callback)(void *), void *arg, const char *xname)
541e2ed649eSjmcneill {
542187fa5a9Sjmcneill 	struct acpi_pci_context * const ap = v;
54353f33807Sjmcneill 	struct acpi_pci_intr *pi;
54453f33807Sjmcneill 	int slot;
545187fa5a9Sjmcneill 
5468537f778Sjmcneill 	if ((ih & (ARM_PCI_INTR_MSI | ARM_PCI_INTR_MSIX)) != 0)
547cce19cc2Sjmcneill 		return arm_pci_msi_intr_establish(&ap->ap_pc, ih, ipl, callback, arg, xname);
548187fa5a9Sjmcneill 
549187fa5a9Sjmcneill 	const int irq = (int)__SHIFTOUT(ih, ARM_PCI_INTR_IRQ);
550187fa5a9Sjmcneill 	const int mpsafe = (ih & ARM_PCI_INTR_MPSAFE) ? IST_MPSAFE : 0;
551e2ed649eSjmcneill 
55253f33807Sjmcneill 	pi = acpi_pci_md_intr_lookup(irq);
55353f33807Sjmcneill 	if (pi == NULL) {
55453f33807Sjmcneill 		pi = kmem_zalloc(sizeof(*pi), KM_SLEEP);
55553f33807Sjmcneill 		pi->pi_irq = irq;
55653f33807Sjmcneill 		snprintf(pi->pi_pic.pic_name, sizeof(pi->pi_pic.pic_name),
55753f33807Sjmcneill 		    "PCI irq %d", irq);
55853f33807Sjmcneill 		pi->pi_pic.pic_maxsources = 32;
55953f33807Sjmcneill 		pi->pi_pic.pic_ops = &acpi_pci_pic_ops;
56053f33807Sjmcneill 		pi->pi_irqbase = pic_add(&pi->pi_pic, PIC_IRQBASE_ALLOC);
56153f33807Sjmcneill 		TAILQ_INSERT_TAIL(&acpi_pci_intrs, pi, pi_list);
5620a249149Sjmcneill 		pi->pi_ih = intr_establish_xname(irq, IPL_VM, IST_LEVEL | IST_MPSAFE,
56353f33807Sjmcneill 		    pic_handle_intr, &pi->pi_pic, device_xname(ap->ap_dev));
56453f33807Sjmcneill 	}
56553f33807Sjmcneill 	if (pi->pi_ih == NULL)
56653f33807Sjmcneill 		return NULL;
56753f33807Sjmcneill 
56853f33807Sjmcneill 	/* Find a free slot */
56953f33807Sjmcneill 	for (slot = 0; slot < pi->pi_pic.pic_maxsources; slot++)
57053f33807Sjmcneill 		if (pi->pi_pic.pic_sources[slot] == NULL)
57153f33807Sjmcneill 			break;
57253f33807Sjmcneill 	if (slot == pi->pi_pic.pic_maxsources)
57353f33807Sjmcneill 		return NULL;
57453f33807Sjmcneill 
57553f33807Sjmcneill 	return intr_establish_xname(pi->pi_irqbase + slot, ipl, IST_LEVEL | mpsafe,
57653f33807Sjmcneill 	    callback, arg, xname);
577e2ed649eSjmcneill }
578e2ed649eSjmcneill 
579e2ed649eSjmcneill static void
acpi_pci_md_intr_disestablish(void * v,void * vih)580e2ed649eSjmcneill acpi_pci_md_intr_disestablish(void *v, void *vih)
581e2ed649eSjmcneill {
582e2ed649eSjmcneill 	intr_disestablish(vih);
583e2ed649eSjmcneill }
5846f25f864Sjmcneill 
5856f25f864Sjmcneill const struct acpi_pci_quirk *
acpi_pci_md_find_quirk(int seg)5866f25f864Sjmcneill acpi_pci_md_find_quirk(int seg)
5876f25f864Sjmcneill {
5886f25f864Sjmcneill 	ACPI_STATUS rv;
5896f25f864Sjmcneill 	ACPI_TABLE_MCFG *mcfg;
5906f25f864Sjmcneill 	u_int n;
5916f25f864Sjmcneill 
5926f25f864Sjmcneill 	rv = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg);
59312a41c4dSjmcneill 	if (ACPI_FAILURE(rv)) {
59412a41c4dSjmcneill #ifdef PCI_SMCCC
59512a41c4dSjmcneill 		uint32_t ver = pci_smccc_version();
59612a41c4dSjmcneill 		aprint_debug("%s: SMCCC version %#x\n", __func__, ver);
59712a41c4dSjmcneill 		if (PCI_SMCCC_SUCCESS(ver)) {
59812a41c4dSjmcneill 			return &acpi_pci_smccc_quirk;
59912a41c4dSjmcneill 		}
60012a41c4dSjmcneill #endif
6016f25f864Sjmcneill 		return NULL;
60212a41c4dSjmcneill 	}
6036f25f864Sjmcneill 
60412a41c4dSjmcneill 	for (n = 0; n < __arraycount(acpi_pci_mcfg_quirks); n++) {
60512a41c4dSjmcneill 		const struct acpi_pci_quirk *q = &acpi_pci_mcfg_quirks[n];
6066f25f864Sjmcneill 		if (memcmp(q->q_oemid, mcfg->Header.OemId, ACPI_OEM_ID_SIZE) == 0 &&
6076f25f864Sjmcneill 		    memcmp(q->q_oemtableid, mcfg->Header.OemTableId, ACPI_OEM_TABLE_ID_SIZE) == 0 &&
6086f25f864Sjmcneill 		    q->q_oemrevision == mcfg->Header.OemRevision &&
6096f25f864Sjmcneill 		    (q->q_segment == -1 || q->q_segment == seg))
6106f25f864Sjmcneill 			return q;
6116f25f864Sjmcneill 	}
6126f25f864Sjmcneill 
6136f25f864Sjmcneill 	return NULL;
6146f25f864Sjmcneill }
6156f25f864Sjmcneill 
6166f25f864Sjmcneill pci_chipset_tag_t
acpi_pci_md_get_chipset_tag(struct acpi_softc * sc,int seg,int bbn)6176f25f864Sjmcneill acpi_pci_md_get_chipset_tag(struct acpi_softc *sc, int seg, int bbn)
6186f25f864Sjmcneill {
6196f25f864Sjmcneill 	struct acpi_pci_pct *pct = NULL, *pctp;
6206f25f864Sjmcneill 	const struct acpi_pci_quirk *q;
6216f25f864Sjmcneill 
6226f25f864Sjmcneill 	TAILQ_FOREACH(pctp, &acpi_pci_chipset_tags, pct_list)
6236f25f864Sjmcneill 		if (pctp->pct_ap.ap_seg == seg) {
6246f25f864Sjmcneill 			pct = pctp;
6256f25f864Sjmcneill 			break;
6266f25f864Sjmcneill 		}
6276f25f864Sjmcneill 
6286f25f864Sjmcneill 	if (pct == NULL) {
6296f25f864Sjmcneill 		pct = kmem_zalloc(sizeof(*pct), KM_SLEEP);
6306f25f864Sjmcneill 		pct->pct_ap.ap_dev = sc->sc_dev;
6316f25f864Sjmcneill 		pct->pct_ap.ap_pc = arm_acpi_pci_chipset;
6326f25f864Sjmcneill 		pct->pct_ap.ap_pc.pc_conf_v = &pct->pct_ap;
63353f33807Sjmcneill 		pct->pct_ap.ap_pc.pc_intr_v = &pct->pct_ap;
6346f25f864Sjmcneill 		pct->pct_ap.ap_seg = seg;
6356f25f864Sjmcneill 		pct->pct_ap.ap_bus = bbn;
63612a41c4dSjmcneill 		pct->pct_ap.ap_maxbus = -1;
6376f25f864Sjmcneill 		pct->pct_ap.ap_bst = acpi_softc->sc_memt;
6386f25f864Sjmcneill 
6396f25f864Sjmcneill 		q = acpi_pci_md_find_quirk(seg);
6406f25f864Sjmcneill 		if (q != NULL)
6416f25f864Sjmcneill 			q->q_init(&pct->pct_ap);
6426f25f864Sjmcneill 
6436f25f864Sjmcneill 		TAILQ_INSERT_TAIL(&acpi_pci_chipset_tags, pct, pct_list);
6446f25f864Sjmcneill 	}
6456f25f864Sjmcneill 
6466f25f864Sjmcneill 	return &pct->pct_ap.ap_pc;
6476f25f864Sjmcneill }
6486f25f864Sjmcneill __strong_alias(acpi_get_pci_chipset_tag,acpi_pci_md_get_chipset_tag);
649