1 /* $OpenBSD: acpipci.c,v 1.9 2024/10/10 05:51:23 jsg Exp $ */
2 /*
3 * Copyright (c) 2018 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/extent.h>
21 #include <sys/malloc.h>
22 #include <sys/systm.h>
23
24 #include <dev/acpi/acpireg.h>
25 #include <dev/acpi/acpivar.h>
26 #include <dev/acpi/acpidev.h>
27 #include <dev/acpi/amltypes.h>
28 #include <dev/acpi/dsdt.h>
29
30 #include <dev/pci/pcidevs.h>
31 #include <dev/pci/pcireg.h>
32 #include <dev/pci/pcivar.h>
33
34 /* 33DB4D5B-1FF7-401C-9657-7441C03DD766 */
35 #define ACPI_PCI_UUID \
36 { 0x5b, 0x4d, 0xdb, 0x33, \
37 0xf7, 0x1f, \
38 0x1c, 0x40, \
39 0x96, 0x57, \
40 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 }
41
42 /* Support field. */
43 #define ACPI_PCI_PCIE_CONFIG 0x00000001
44 #define ACPI_PCI_ASPM 0x00000002
45 #define ACPI_PCI_CPMC 0x00000004
46 #define ACPI_PCI_SEGMENTS 0x00000008
47 #define ACPI_PCI_MSI 0x00000010
48
49 /* Control field. */
50 #define ACPI_PCI_PCIE_HOTPLUG 0x00000001
51
52 struct acpipci_softc {
53 struct device sc_dev;
54 struct acpi_softc *sc_acpi;
55 struct aml_node *sc_node;
56
57 bus_space_tag_t sc_iot;
58 bus_space_tag_t sc_memt;
59 bus_dma_tag_t sc_dmat;
60
61 struct extent *sc_busex;
62 struct extent *sc_memex;
63 struct extent *sc_ioex;
64 char sc_busex_name[32];
65 char sc_ioex_name[32];
66 char sc_memex_name[32];
67 int sc_bus;
68 uint32_t sc_seg;
69 };
70
71 int acpipci_match(struct device *, void *, void *);
72 void acpipci_attach(struct device *, struct device *, void *);
73
74 const struct cfattach acpipci_ca = {
75 sizeof(struct acpipci_softc), acpipci_match, acpipci_attach
76 };
77
78 struct cfdriver acpipci_cd = {
79 NULL, "acpipci", DV_DULL
80 };
81
82 const char *acpipci_hids[] = {
83 "PNP0A08",
84 "PNP0A03",
85 NULL
86 };
87
88 int acpipci_print(void *, const char *);
89 int acpipci_parse_resources(int, union acpi_resource *, void *);
90 void acpipci_osc(struct acpipci_softc *);
91
92 int
acpipci_match(struct device * parent,void * match,void * aux)93 acpipci_match(struct device *parent, void *match, void *aux)
94 {
95 struct acpi_attach_args *aaa = aux;
96 struct cfdata *cf = match;
97
98 return acpi_matchhids(aaa, acpipci_hids, cf->cf_driver->cd_name);
99 }
100
101 void
acpipci_attach(struct device * parent,struct device * self,void * aux)102 acpipci_attach(struct device *parent, struct device *self, void *aux)
103 {
104 struct acpi_attach_args *aaa = aux;
105 struct acpipci_softc *sc = (struct acpipci_softc *)self;
106 struct aml_value res;
107 uint64_t bbn = 0;
108 uint64_t seg = 0;
109
110 acpi_haspci = 1;
111
112 sc->sc_iot = aaa->aaa_iot;
113 sc->sc_memt = aaa->aaa_memt;
114 sc->sc_dmat = aaa->aaa_dmat;
115
116 sc->sc_acpi = (struct acpi_softc *)parent;
117 sc->sc_node = aaa->aaa_node;
118 printf(" %s", sc->sc_node->name);
119
120 acpipci_osc(sc);
121
122 aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL, &bbn);
123 sc->sc_bus = bbn;
124
125 aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg);
126 sc->sc_seg = seg;
127
128 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
129 printf(": can't find resources\n");
130
131 pci_init_extents();
132 sc->sc_busex = pcibus_ex;
133 sc->sc_ioex = pciio_ex;
134 sc->sc_memex = pcimem_ex;
135
136 return;
137 }
138
139 /* Create extents for our address spaces. */
140 snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name),
141 "%s pcibus", sc->sc_dev.dv_xname);
142 snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
143 "%s pciio", sc->sc_dev.dv_xname);
144 snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
145 "%s pcimem", sc->sc_dev.dv_xname);
146 sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255,
147 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
148 sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff,
149 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
150 sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1,
151 M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
152
153 aml_parse_resource(&res, acpipci_parse_resources, sc);
154
155 if (sc->sc_acpi->sc_major < 5) {
156 extent_destroy(sc->sc_ioex);
157 extent_destroy(sc->sc_memex);
158
159 pci_init_extents();
160 sc->sc_ioex = pciio_ex;
161 sc->sc_memex = pcimem_ex;
162 }
163
164 printf("\n");
165
166 #ifdef ACPIPCI_DEBUG
167 extent_print(sc->sc_busex);
168 extent_print(sc->sc_ioex);
169 extent_print(sc->sc_memex);
170 #endif
171 }
172
173 void
acpipci_attach_bus(struct device * parent,struct acpipci_softc * sc)174 acpipci_attach_bus(struct device *parent, struct acpipci_softc *sc)
175 {
176 struct pcibus_attach_args pba;
177 pcitag_t tag;
178 pcireg_t id, class;
179
180 memset(&pba, 0, sizeof(pba));
181 pba.pba_busname = "pci";
182 pba.pba_iot = sc->sc_iot;
183 pba.pba_memt = sc->sc_memt;
184 pba.pba_dmat = sc->sc_dmat;
185 pba.pba_busex = sc->sc_busex;
186 pba.pba_ioex = sc->sc_ioex;
187 pba.pba_memex = sc->sc_memex;
188 pba.pba_pmemex = sc->sc_memex;
189 pba.pba_domain = pci_ndomains++;
190 pba.pba_bus = sc->sc_bus;
191
192 /* Enable MSI in ACPI 2.0 and above, unless we're told not to. */
193 if (sc->sc_acpi->sc_fadt->hdr.revision >= 2 &&
194 (sc->sc_acpi->sc_fadt->iapc_boot_arch & FADT_NO_MSI) == 0)
195 pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
196
197 /* Enable MSI for QEMU claiming ACPI 1.0 */
198 tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 0, 0);
199 id = pci_conf_read(pba.pba_pc, tag, PCI_SUBSYS_ID_REG);
200 if (sc->sc_acpi->sc_fadt->hdr.revision == 1 &&
201 PCI_VENDOR(id) == PCI_VENDOR_QUMRANET)
202 pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
203
204 /*
205 * Don't enable MSI on chipsets from low-end manufacturers
206 * like VIA and SiS. We do this by looking at the host
207 * bridge, which should be device 0 function 0.
208 */
209 id = pci_conf_read(pba.pba_pc, tag, PCI_ID_REG);
210 class = pci_conf_read(pba.pba_pc, tag, PCI_CLASS_REG);
211 if (PCI_CLASS(class) == PCI_CLASS_BRIDGE &&
212 PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_HOST &&
213 PCI_VENDOR(id) != PCI_VENDOR_AMD &&
214 PCI_VENDOR(id) != PCI_VENDOR_NVIDIA &&
215 PCI_VENDOR(id) != PCI_VENDOR_INTEL)
216 pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
217
218 /*
219 * Don't enable MSI on a HyperTransport bus. In order to
220 * determine that a bus is a HyperTransport bus, we look at
221 * device 24 function 0, which is the HyperTransport
222 * host/primary interface integrated on most 64-bit AMD CPUs.
223 * If that device has a HyperTransport capability, this must
224 * be a HyperTransport bus and we disable MSI.
225 */
226 tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 24, 0);
227 if (pci_get_capability(pba.pba_pc, tag, PCI_CAP_HT, NULL, NULL))
228 pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
229
230 config_found(parent, &pba, acpipci_print);
231 }
232
233 void
acpipci_attach_busses(struct device * parent)234 acpipci_attach_busses(struct device *parent)
235 {
236 int i;
237
238 for (i = 0; i < acpipci_cd.cd_ndevs; i++) {
239 if (acpipci_cd.cd_devs[i])
240 acpipci_attach_bus(parent, acpipci_cd.cd_devs[i]);
241 }
242 }
243
244 int
acpipci_print(void * aux,const char * pnp)245 acpipci_print(void *aux, const char *pnp)
246 {
247 struct pcibus_attach_args *pba = aux;
248
249 if (pnp)
250 printf("%s at %s", pba->pba_busname, pnp);
251 printf(" bus %d", pba->pba_bus);
252 return (UNCONF);
253 }
254
255 int
acpipci_parse_resources(int crsidx,union acpi_resource * crs,void * arg)256 acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
257 {
258 struct acpipci_softc *sc = arg;
259 int type = AML_CRSTYPE(crs);
260 int restype, tflags = 0;
261 u_long min, len = 0, tra = 0;
262
263 switch (type) {
264 case LR_WORD:
265 restype = crs->lr_word.type;
266 tflags = crs->lr_word.tflags;
267 min = crs->lr_word._min;
268 len = crs->lr_word._len;
269 tra = crs->lr_word._tra;
270 break;
271 case LR_DWORD:
272 restype = crs->lr_dword.type;
273 tflags = crs->lr_dword.tflags;
274 min = crs->lr_dword._min;
275 len = crs->lr_dword._len;
276 tra = crs->lr_dword._tra;
277 break;
278 case LR_QWORD:
279 restype = crs->lr_qword.type;
280 tflags = crs->lr_qword.tflags;
281 min = crs->lr_qword._min;
282 len = crs->lr_qword._len;
283 tra = crs->lr_qword._tra;
284 break;
285 case LR_MEM32FIXED:
286 /*
287 * Coreboot on the PC Engines apu2 incorrectly uses a
288 * Memory32Fixed resource descriptor to describe mmio
289 * address space forwarded to the PCI bus.
290 */
291 restype = LR_TYPE_MEMORY;
292 min = crs->lr_m32fixed._bas;
293 len = crs->lr_m32fixed._len;
294 break;
295 }
296
297 if (len == 0)
298 return 0;
299
300 switch (restype) {
301 case LR_TYPE_MEMORY:
302 if (tflags & LR_MEMORY_TTP)
303 return 0;
304 extent_free(sc->sc_memex, min, len, EX_WAITOK | EX_CONFLICTOK);
305 break;
306 case LR_TYPE_IO:
307 if (tflags & LR_IO_TTP)
308 return 0;
309 extent_free(sc->sc_ioex, min, len, EX_WAITOK | EX_CONFLICTOK);
310 break;
311 case LR_TYPE_BUS:
312 extent_free(sc->sc_busex, min, len, EX_WAITOK);
313 /*
314 * Let _CRS minimum bus number override _BBN.
315 */
316 sc->sc_bus = min;
317 break;
318 }
319
320 return 0;
321 }
322
323 void
acpipci_osc(struct acpipci_softc * sc)324 acpipci_osc(struct acpipci_softc *sc)
325 {
326 struct aml_value args[4];
327 struct aml_value res;
328 static uint8_t uuid[16] = ACPI_PCI_UUID;
329 uint32_t buf[3];
330
331 memset(args, 0, sizeof(args));
332 args[0].type = AML_OBJTYPE_BUFFER;
333 args[0].v_buffer = uuid;
334 args[0].length = sizeof(uuid);
335 args[1].type = AML_OBJTYPE_INTEGER;
336 args[1].v_integer = 1;
337 args[2].type = AML_OBJTYPE_INTEGER;
338 args[2].v_integer = 3;
339 args[3].type = AML_OBJTYPE_BUFFER;
340 args[3].v_buffer = (uint8_t *)buf;
341 args[3].length = sizeof(buf);
342
343 memset(buf, 0, sizeof(buf));
344 buf[0] = 0x0;
345 buf[1] = ACPI_PCI_PCIE_CONFIG | ACPI_PCI_MSI;
346 buf[2] = ACPI_PCI_PCIE_HOTPLUG;
347
348 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_OSC", 4, args, &res))
349 return;
350
351 if (res.type == AML_OBJTYPE_BUFFER) {
352 size_t len = res.length;
353 uint32_t *p = (uint32_t *)res.v_buffer;
354
355 printf(":");
356 while (len >= 4) {
357 printf(" 0x%08x", *p);
358 p++;
359 len -= 4;
360 }
361 }
362 }
363