Annotation of src/sys/arch/arm/acpi/acpipchb.c, Revision 1.25
1.25 ! thorpej 1: /* $NetBSD: acpipchb.c,v 1.24 2021/04/24 23:36:25 thorpej Exp $ */
1.1 jmcneill 2:
3: /*-
4: * Copyright (c) 2018 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Jared McNeill <jmcneill@invisible.ca>.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
1.25 ! thorpej 33: __KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.24 2021/04/24 23:36:25 thorpej Exp $");
1.1 jmcneill 34:
35: #include <sys/param.h>
36: #include <sys/bus.h>
37: #include <sys/device.h>
38: #include <sys/intr.h>
39: #include <sys/systm.h>
40: #include <sys/kernel.h>
41: #include <sys/queue.h>
42: #include <sys/mutex.h>
43: #include <sys/kmem.h>
1.19 ad 44: #include <sys/cpu.h>
1.1 jmcneill 45:
46: #include <arm/cpufunc.h>
47:
48: #include <dev/pci/pcireg.h>
49: #include <dev/pci/pcivar.h>
50: #include <dev/pci/pciconf.h>
51:
52: #include <dev/acpi/acpivar.h>
1.3 jmcneill 53: #include <dev/acpi/acpi_pci.h>
1.1 jmcneill 54: #include <dev/acpi/acpi_mcfg.h>
55:
1.2 jmcneill 56: #include <arm/acpi/acpi_pci_machdep.h>
57:
1.1 jmcneill 58: #define PCIHOST_CACHELINE_SIZE arm_dcache_align
59:
1.9 jmcneill 60: #define ACPIPCHB_MAX_RANGES 64 /* XXX arbitrary limit */
1.7 jmcneill 61:
1.9 jmcneill 62: struct acpipchb_bus_range {
1.7 jmcneill 63: bus_addr_t min;
64: bus_addr_t max;
65: bus_addr_t offset;
1.9 jmcneill 66: };
67:
68: struct acpipchb_bus_space {
69: struct bus_space bs;
70:
71: struct acpipchb_bus_range range[ACPIPCHB_MAX_RANGES];
72: int nrange;
1.7 jmcneill 73:
74: int (*map)(void *, bus_addr_t, bus_size_t,
75: int, bus_space_handle_t *);
1.14 jmcneill 76:
77: int flags;
1.7 jmcneill 78: };
79:
1.1 jmcneill 80: struct acpipchb_softc {
81: device_t sc_dev;
82:
1.9 jmcneill 83: bus_space_tag_t sc_memt;
84:
1.1 jmcneill 85: ACPI_HANDLE sc_handle;
86: ACPI_INTEGER sc_bus;
1.6 jmcneill 87:
1.9 jmcneill 88: struct acpipchb_bus_space sc_pcimem_bst;
1.7 jmcneill 89: struct acpipchb_bus_space sc_pciio_bst;
1.1 jmcneill 90: };
91:
92: static int acpipchb_match(device_t, cfdata_t, void *);
93: static void acpipchb_attach(device_t, device_t, void *);
94:
1.22 jmcneill 95: static void acpipchb_setup_ranges(struct acpipchb_softc *,
96: struct pcibus_attach_args *);
97: static void acpipchb_setup_quirks(struct acpipchb_softc *,
98: struct pcibus_attach_args *);
1.6 jmcneill 99:
1.1 jmcneill 100: CFATTACH_DECL_NEW(acpipchb, sizeof(struct acpipchb_softc),
101: acpipchb_match, acpipchb_attach, NULL, NULL);
102:
103: static const char * const compatible[] = {
104: "PNP0A08",
105: NULL
106: };
107:
108: static int
109: acpipchb_match(device_t parent, cfdata_t cf, void *aux)
110: {
111: struct acpi_attach_args *aa = aux;
112:
113: if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
114: return 0;
115:
116: return acpi_match_hid(aa->aa_node->ad_devinfo, compatible);
117: }
118:
119: static void
120: acpipchb_attach(device_t parent, device_t self, void *aux)
121: {
122: struct acpipchb_softc * const sc = device_private(self);
123: struct acpi_attach_args *aa = aux;
124: struct pcibus_attach_args pba;
1.15 jmcneill 125: ACPI_INTEGER seg;
1.22 jmcneill 126: ACPI_STATUS rv;
1.18 jmcneill 127: uint16_t bus_start;
1.1 jmcneill 128:
129: sc->sc_dev = self;
1.9 jmcneill 130: sc->sc_memt = aa->aa_memt;
1.1 jmcneill 131: sc->sc_handle = aa->aa_node->ad_handle;
132:
1.18 jmcneill 133: /*
134: * First try to derive the base bus number from _CRS. If that fails,
135: * try _BBN. If that fails too, assume bus 0.
136: */
137: if (ACPI_SUCCESS(acpi_pcidev_pciroot_bus(sc->sc_handle, &bus_start))) {
138: sc->sc_bus = bus_start;
139: } else {
1.22 jmcneill 140: rv = acpi_eval_integer(sc->sc_handle, "_BBN", &sc->sc_bus);
141: if (ACPI_FAILURE(rv)) {
1.18 jmcneill 142: sc->sc_bus = 0;
1.22 jmcneill 143: }
1.18 jmcneill 144: }
1.1 jmcneill 145:
1.22 jmcneill 146: if (ACPI_FAILURE(acpi_eval_integer(sc->sc_handle, "_SEG", &seg))) {
1.2 jmcneill 147: seg = 0;
1.22 jmcneill 148: }
1.2 jmcneill 149:
1.1 jmcneill 150: aprint_naive("\n");
151: aprint_normal(": PCI Express Host Bridge\n");
152:
1.23 jmcneill 153: acpi_claim_childdevs(self, aa->aa_node);
154:
1.5 jmcneill 155: if (acpi_pci_ignore_boot_config(sc->sc_handle)) {
1.22 jmcneill 156: if (acpimcfg_configure_bus(self, aa->aa_pc, sc->sc_handle,
157: sc->sc_bus, PCIHOST_CACHELINE_SIZE) != 0) {
1.3 jmcneill 158: aprint_error_dev(self, "failed to configure bus\n");
1.22 jmcneill 159: }
1.5 jmcneill 160: }
1.2 jmcneill 161:
1.1 jmcneill 162: memset(&pba, 0, sizeof(pba));
1.22 jmcneill 163: pba.pba_flags = aa->aa_pciflags &
164: ~(PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY);
1.9 jmcneill 165: pba.pba_memt = 0;
1.6 jmcneill 166: pba.pba_iot = 0;
1.17 jmcneill 167: pba.pba_dmat = aa->aa_dmat;
1.1 jmcneill 168: #ifdef _PCI_HAVE_DMA64
1.17 jmcneill 169: pba.pba_dmat64 = aa->aa_dmat64;
1.1 jmcneill 170: #endif
1.16 jmcneill 171: pba.pba_pc = aa->aa_pc;
1.1 jmcneill 172: pba.pba_bus = sc->sc_bus;
173:
1.9 jmcneill 174: acpipchb_setup_ranges(sc, &pba);
1.16 jmcneill 175: acpipchb_setup_quirks(sc, &pba);
1.6 jmcneill 176:
1.25 ! thorpej 177: config_found(self, &pba, pcibusprint,
! 178: CFARG_DEVHANDLE, device_handle(self),
! 179: CFARG_EOL);
1.1 jmcneill 180: }
1.6 jmcneill 181:
1.9 jmcneill 182: struct acpipchb_setup_ranges_args {
1.6 jmcneill 183: struct acpipchb_softc *sc;
184: struct pcibus_attach_args *pba;
185: };
186:
1.7 jmcneill 187: static int
188: acpipchb_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
189: bus_space_handle_t *bshp)
190: {
191: struct acpipchb_bus_space * const abs = t;
1.9 jmcneill 192: int i;
1.7 jmcneill 193:
1.9 jmcneill 194: if (size == 0)
1.7 jmcneill 195: return ERANGE;
196:
1.14 jmcneill 197: if ((abs->flags & PCI_FLAGS_IO_OKAY) != 0) {
198: /* Force strongly ordered mapping for all I/O space */
199: flag = _ARM_BUS_SPACE_MAP_STRONGLY_ORDERED;
200: }
201:
1.9 jmcneill 202: for (i = 0; i < abs->nrange; i++) {
203: struct acpipchb_bus_range * const range = &abs->range[i];
1.22 jmcneill 204: if (bpa >= range->min && bpa + size - 1 <= range->max) {
205: return abs->map(t, bpa + range->offset, size,
206: flag, bshp);
207: }
1.9 jmcneill 208: }
209:
210: return ERANGE;
1.7 jmcneill 211: }
212:
1.6 jmcneill 213: static ACPI_STATUS
1.9 jmcneill 214: acpipchb_setup_ranges_cb(ACPI_RESOURCE *res, void *ctx)
1.6 jmcneill 215: {
1.9 jmcneill 216: struct acpipchb_setup_ranges_args * const args = ctx;
1.6 jmcneill 217: struct acpipchb_softc * const sc = args->sc;
218: struct pcibus_attach_args *pba = args->pba;
1.9 jmcneill 219: struct acpipchb_bus_space *abs;
220: struct acpipchb_bus_range *range;
221: const char *range_type;
222: u_int pci_flags;
1.6 jmcneill 223:
224: if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
1.22 jmcneill 225: res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) {
1.6 jmcneill 226: return AE_OK;
1.22 jmcneill 227: }
1.6 jmcneill 228:
1.9 jmcneill 229: switch (res->Data.Address.ResourceType) {
230: case ACPI_IO_RANGE:
231: abs = &sc->sc_pciio_bst;
232: range_type = "I/O";
233: pci_flags = PCI_FLAGS_IO_OKAY;
234: break;
235: case ACPI_MEMORY_RANGE:
236: abs = &sc->sc_pcimem_bst;
237: range_type = "MEM";
238: pci_flags = PCI_FLAGS_MEM_OKAY;
239: break;
240: default:
1.6 jmcneill 241: return AE_OK;
1.9 jmcneill 242: }
1.6 jmcneill 243:
1.9 jmcneill 244: if (abs->nrange == ACPIPCHB_MAX_RANGES) {
245: aprint_error_dev(sc->sc_dev,
1.22 jmcneill 246: "maximum number of ranges reached (ACPIPCHB_MAX_RANGES)\n");
1.9 jmcneill 247: return AE_LIMIT;
248: }
1.6 jmcneill 249:
1.9 jmcneill 250: range = &abs->range[abs->nrange];
1.6 jmcneill 251: switch (res->Type) {
252: case ACPI_RESOURCE_TYPE_ADDRESS32:
1.9 jmcneill 253: range->min = res->Data.Address32.Address.Minimum;
254: range->max = res->Data.Address32.Address.Maximum;
255: range->offset = res->Data.Address32.Address.TranslationOffset;
1.6 jmcneill 256: break;
257: case ACPI_RESOURCE_TYPE_ADDRESS64:
1.9 jmcneill 258: range->min = res->Data.Address64.Address.Minimum;
259: range->max = res->Data.Address64.Address.Maximum;
260: range->offset = res->Data.Address64.Address.TranslationOffset;
1.6 jmcneill 261: break;
1.9 jmcneill 262: default:
263: return AE_OK;
1.6 jmcneill 264: }
1.9 jmcneill 265: abs->nrange++;
1.6 jmcneill 266:
1.22 jmcneill 267: aprint_debug_dev(sc->sc_dev, "PCI %s [%#lx-%#lx] -> %#lx\n",
268: range_type, range->min, range->max, range->offset);
1.6 jmcneill 269:
1.9 jmcneill 270: if ((pba->pba_flags & pci_flags) == 0) {
271: abs->bs = *sc->sc_memt;
272: abs->bs.bs_cookie = abs;
273: abs->map = abs->bs.bs_map;
1.14 jmcneill 274: abs->flags = pci_flags;
1.9 jmcneill 275: abs->bs.bs_map = acpipchb_bus_space_map;
1.22 jmcneill 276: if ((pci_flags & PCI_FLAGS_IO_OKAY) != 0) {
1.9 jmcneill 277: pba->pba_iot = &abs->bs;
1.22 jmcneill 278: } else if ((pci_flags & PCI_FLAGS_MEM_OKAY) != 0) {
1.9 jmcneill 279: pba->pba_memt = &abs->bs;
1.22 jmcneill 280: }
1.9 jmcneill 281: pba->pba_flags |= pci_flags;
282: }
1.6 jmcneill 283:
1.9 jmcneill 284: return AE_OK;
1.6 jmcneill 285: }
286:
287: static void
1.9 jmcneill 288: acpipchb_setup_ranges(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
1.6 jmcneill 289: {
1.9 jmcneill 290: struct acpipchb_setup_ranges_args args;
1.6 jmcneill 291:
292: args.sc = sc;
293: args.pba = pba;
294:
1.22 jmcneill 295: AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_ranges_cb,
296: &args);
1.6 jmcneill 297: }
1.16 jmcneill 298:
299: static void
300: acpipchb_setup_quirks(struct acpipchb_softc *sc, struct pcibus_attach_args *pba)
301: {
1.22 jmcneill 302: struct arm32_pci_chipset *md_pc =
303: (struct arm32_pci_chipset *)pba->pba_pc;
1.16 jmcneill 304: struct acpi_pci_context *ap = md_pc->pc_conf_v;
305:
306: pba->pba_flags &= ~ap->ap_pciflags_clear;
307: }
CVSweb <webmaster@jp.NetBSD.org>