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