xref: /netbsd-src/sys/dev/acpi/acpi_mcfg.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
1 /*	$NetBSD: acpi_mcfg.c,v 1.25 2022/02/27 14:19:07 riastradh Exp $	*/
2 
3 /*-
4  * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "opt_pci.h"
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.25 2022/02/27 14:19:07 riastradh Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/kmem.h>
36 #include <sys/systm.h>
37 
38 #include <dev/pci/pcireg.h>
39 #include <dev/pci/pcivar.h>
40 #include <dev/pci/pciconf.h>
41 #include <dev/pci/pcidevs.h>
42 
43 #include <dev/acpi/acpireg.h>
44 #include <dev/acpi/acpivar.h>
45 #include <dev/acpi/acpi_mcfg.h>
46 
47 #include "locators.h"
48 
49 #define _COMPONENT      ACPI_RESOURCE_COMPONENT
50 ACPI_MODULE_NAME	("acpi_mcfg")
51 
52 #define	EXTCONF_OFFSET(d, f, r)	((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r))
53 
54 #define	PCIDEV_SET_VALID(mb, d, f)	((mb)->valid_devs[(d)] |= __BIT((f)))
55 #define	PCIDEV_SET_INVALID(mb, d, f)	((mb)->valid_devs[(d)] &= ~__BIT((f)))
56 #define	PCIDEV_IS_VALID(mb, d, f)	((mb)->valid_devs[(d)] & __BIT((f)))
57 
58 #define	EXTCONF_SET_VALID(mb, d, f)	((mb)->valid_extconf[(d)] |= __BIT((f)))
59 #define	EXTCONF_SET_INVALID(mb, d, f)	((mb)->valid_extconf[(d)] &= ~__BIT((f)))
60 #define	EXTCONF_IS_VALID(mb, d, f)	((mb)->valid_extconf[(d)] & __BIT((f)))
61 
62 struct mcfg_segment {
63 	uint64_t ms_address;		/* Base address */
64 	int ms_segment;			/* Segment # */
65 	int ms_bus_start;		/* Start bus # */
66 	int ms_bus_end;			/* End bus # */
67 	bus_space_tag_t ms_bst;
68 	struct mcfg_bus {
69 		bus_space_handle_t bsh[32][8];
70 		uint8_t valid_devs[32];
71 		uint8_t valid_extconf[32];
72 		int valid_ndevs;
73 		pcitag_t last_probed;
74 	} *ms_bus;
75 };
76 
77 static struct mcfg_segment *mcfg_segs;
78 static int mcfg_nsegs;
79 static ACPI_TABLE_MCFG *mcfg;
80 static int mcfg_inited;
81 static struct acpi_softc *acpi_sc;
82 
83 static const struct acpimcfg_ops mcfg_default_ops = {
84 	.ao_validate = acpimcfg_default_validate,
85 
86 	.ao_read = acpimcfg_default_read,
87 	.ao_write = acpimcfg_default_write,
88 };
89 static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops;
90 
91 /*
92  * default operations.
93  */
94 bool
95 acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end)
96 {
97 
98 	/* Always Ok */
99 	return true;
100 }
101 
102 uint32_t
103 acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh,
104     bus_addr_t addr)
105 {
106 
107 	return bus_space_read_4(bst, bsh, addr);
108 }
109 
110 void
111 acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh,
112     bus_addr_t addr, uint32_t data)
113 {
114 
115 	bus_space_write_4(bst, bsh, addr, data);
116 }
117 
118 
119 /*
120  * Check MCFG memory region at system resource
121  */
122 struct acpimcfg_memrange {
123 	const char	*hid;
124 	uint64_t	address;
125 	int		bus_start;
126 	int		bus_end;
127 	bool		found;
128 };
129 
130 static ACPI_STATUS
131 acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx)
132 {
133 	struct acpimcfg_memrange *mr = ctx;
134 	const char *type;
135 	uint64_t size, mapaddr, mapsize;
136 	int n;
137 
138 	switch (res->Type) {
139 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
140 		type = "FIXED_MEMORY32";
141 		mapaddr = res->Data.FixedMemory32.Address;
142 		mapsize = res->Data.FixedMemory32.AddressLength;
143 		break;
144 
145 	case ACPI_RESOURCE_TYPE_ADDRESS32:
146 		/* XXX Only fixed size supported for now */
147 		if (res->Data.Address32.Address.AddressLength == 0 ||
148 		    res->Data.Address32.ProducerConsumer != ACPI_CONSUMER)
149 			goto out;
150 
151 		if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE)
152 			goto out;
153 
154 		if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED ||
155 		    res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED)
156 			goto out;
157 
158 		type = "ADDRESS32";
159 		mapaddr = res->Data.Address32.Address.Minimum;
160 		mapsize = res->Data.Address32.Address.AddressLength;
161 		break;
162 
163 #ifdef _LP64
164 	case ACPI_RESOURCE_TYPE_ADDRESS64:
165 		/* XXX Only fixed size supported for now */
166 		if (res->Data.Address64.Address.AddressLength == 0 ||
167 		    res->Data.Address64.ProducerConsumer != ACPI_CONSUMER)
168 			goto out;
169 
170 		if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE)
171 			goto out;
172 
173 		if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED ||
174 		    res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED)
175 			goto out;
176 
177 		type = "ADDRESS64";
178 		mapaddr = res->Data.Address64.Address.Minimum;
179 		mapsize = res->Data.Address64.Address.AddressLength;
180 		break;
181 #endif
182 
183 	default:
184  out:
185 		aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n",
186 		    mr->hid, res->Type);
187 		return_ACPI_STATUS(AE_OK);
188 	}
189 
190 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), "
191 	    "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n",
192 	    mr->hid, res->Type, type, mapaddr, mapsize);
193 
194 	if (mr->address < mapaddr || mr->address >= mapaddr + mapsize)
195 		return_ACPI_STATUS(AE_OK);
196 
197 	size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS;
198 
199 	/* full map */
200 	if (mr->address + size <= mapaddr + mapsize) {
201 		mr->found = true;
202 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
203 	}
204 
205 	/* partial map */
206 	n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS;
207 	/* bus_start == bus_end is not allowed. */
208 	if (n > 1) {
209 		mr->bus_end = mr->bus_start + n - 1;
210 		mr->found = true;
211 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
212 	}
213 
214 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, "
215 	    "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64
216 	    ", actual 0x%016" PRIx64 "\n",
217 	    mr->bus_start, mr->bus_end, mr->address, size, mapsize);
218 
219 	return_ACPI_STATUS(AE_OK);
220 }
221 
222 static ACPI_STATUS
223 acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx,
224     void **retval)
225 {
226 	struct acpimcfg_memrange *mr = ctx;
227 	ACPI_STATUS status;
228 
229 	status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr);
230 	if (ACPI_FAILURE(status))
231 		return_ACPI_STATUS(status);
232 
233 	if (mr->found)
234 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
235 
236 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, "
237 	    "address 0x%016" PRIx64 ": no valid region\n", mr->hid,
238 	    mr->bus_start, mr->bus_end, mr->address);
239 
240 	return_ACPI_STATUS(AE_OK);
241 }
242 
243 static bool
244 acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end)
245 {
246 	static const char *system_resource_hid[] = {
247 		"PNP0C01",	/* System Board */
248 		"PNP0C02"	/* General ID for reserving resources */
249 	};
250 	struct acpimcfg_memrange mr;
251 	ACPI_STATUS status;
252 	int i;
253 
254 	mr.address = address;
255 	mr.bus_start = bus_start;
256 	mr.bus_end = *bus_end;
257 	mr.found = false;
258 
259 	for (i = 0; i < __arraycount(system_resource_hid); i++) {
260 		mr.hid = system_resource_hid[i];
261 		status = AcpiGetDevices(__UNCONST(system_resource_hid[i]),
262 		    acpimcfg_check_system_resource, &mr, NULL);
263 		if (ACPI_FAILURE(status))
264 			continue;
265 		if (mr.found) {
266 			*bus_end = mr.bus_end;
267 			return true;
268 		}
269 	}
270 	return false;
271 }
272 
273 
274 /*
275  * ACPI MCFG
276  */
277 void
278 acpimcfg_probe(struct acpi_softc *sc)
279 {
280 	ACPI_MCFG_ALLOCATION *ama;
281 	ACPI_STATUS status;
282 	uint32_t offset;
283 	int i, nsegs;
284 
285 	if (acpi_sc != NULL)
286 		panic("acpi_sc != NULL");
287 	acpi_sc = sc;
288 
289 	status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg);
290 	if (ACPI_FAILURE(status)) {
291 		mcfg = NULL;
292 		return;
293 	}
294 
295 	nsegs = 0;
296 	offset = sizeof(ACPI_TABLE_MCFG);
297 	ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
298 	for (i = 0; offset + sizeof(ACPI_MCFG_ALLOCATION) <=
299 	    mcfg->Header.Length; i++) {
300 		aprint_debug_dev(sc->sc_dev,
301 		    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
302 		    ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber,
303 		    ama->Address);
304 		nsegs++;
305 		offset += sizeof(ACPI_MCFG_ALLOCATION);
306 		ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
307 	}
308 	if (nsegs == 0) {
309 		mcfg = NULL;
310 		return;
311 	}
312 
313 	mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP);
314 	mcfg_nsegs = nsegs;
315 }
316 
317 int
318 acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops)
319 {
320 	ACPI_MCFG_ALLOCATION *ama;
321 	struct mcfg_segment *seg;
322 	uint32_t offset;
323 	int i, n, nsegs, bus_end;
324 
325 	if (mcfg == NULL)
326 		return ENXIO;
327 
328 	if (mcfg_inited)
329 		return 0;
330 
331 	if (ops != NULL)
332 		mcfg_ops = ops;
333 
334 	nsegs = 0;
335 	offset = sizeof(ACPI_TABLE_MCFG);
336 	ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
337 	for (i = 0; offset < mcfg->Header.Length; i++) {
338 #ifndef _LP64
339 		if (ama->Address >= 0x100000000ULL) {
340 			aprint_debug_dev(acpi_sc->sc_dev,
341 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
342 			    ": ignore (64bit address)\n", ama->PciSegment,
343 			    ama->StartBusNumber, ama->EndBusNumber,
344 			    ama->Address);
345 			goto next;
346 		}
347 #endif
348 		/*
349 		 * Some (broken?) BIOSen have an MCFG table for an empty
350 		 * bus range.  Ignore those tables.
351 		 */
352 		if (ama->StartBusNumber > ama->EndBusNumber) {
353 			aprint_debug_dev(acpi_sc->sc_dev,
354 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
355 			    ": ignore (bus %d > %d)\n", ama->PciSegment,
356 			    ama->StartBusNumber, ama->EndBusNumber,
357 			    ama->Address, ama->StartBusNumber,
358 			    ama->EndBusNumber);
359 			goto next;
360 		}
361 
362 		/* Validate MCFG memory range */
363 		bus_end = ama->EndBusNumber;
364 		if (mcfg_ops->ao_validate != NULL &&
365 		    !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber,
366 		      &bus_end)) {
367 			if (!acpimcfg_find_system_resource(ama->Address,
368 			    ama->StartBusNumber, &bus_end)) {
369 				aprint_debug_dev(acpi_sc->sc_dev,
370 				    "MCFG: segment %d, bus %d-%d, "
371 				    "address 0x%016" PRIx64
372 				    ": ignore (invalid address)\n",
373 				    ama->PciSegment,
374 				    ama->StartBusNumber, ama->EndBusNumber,
375 				    ama->Address);
376 				goto next;
377 			}
378 		}
379 		if (ama->EndBusNumber != bus_end) {
380 			aprint_debug_dev(acpi_sc->sc_dev,
381 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
382 			    " -> bus %d-%d\n", ama->PciSegment,
383 			    ama->StartBusNumber, ama->EndBusNumber,
384 			    ama->Address, ama->StartBusNumber, bus_end);
385 		}
386 
387 #ifndef __HAVE_PCI_GET_SEGMENT
388 		if (ama->PciSegment != 0) {
389 			aprint_debug_dev(acpi_sc->sc_dev,
390 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
391 			    ": ignore (non PCI segment 0)\n", ama->PciSegment,
392 			    ama->StartBusNumber, bus_end, ama->Address);
393 			goto next;
394 		}
395 #endif
396 
397 		seg = &mcfg_segs[nsegs++];
398 		seg->ms_address = ama->Address;
399 		seg->ms_segment = ama->PciSegment;
400 		seg->ms_bus_start = ama->StartBusNumber;
401 		seg->ms_bus_end = bus_end;
402 		seg->ms_bst = memt;
403 		n = seg->ms_bus_end - seg->ms_bus_start + 1;
404 		seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP);
405 
406  next:
407 		offset += sizeof(ACPI_MCFG_ALLOCATION);
408 		ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
409 	}
410 	if (nsegs == 0)
411 		return ENOENT;
412 
413 	for (i = 0; i < nsegs; i++) {
414 		seg = &mcfg_segs[i];
415 		aprint_verbose_dev(acpi_sc->sc_dev,
416 		    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
417 		    seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end,
418 		    seg->ms_address);
419 	}
420 
421 	/* Update # of segment */
422 	mcfg_nsegs = nsegs;
423 	mcfg_inited = true;
424 
425 	return 0;
426 }
427 
428 static int
429 acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag)
430 {
431 	pcireg_t id;
432 	int i;
433 
434 	id = pci_conf_read(pc, tag, PCI_ID_REG);
435 	for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) {
436 		if (pci_conf_read(pc, tag, i) != id)
437 			return false;
438 	}
439 	return true;
440 }
441 
442 static struct mcfg_segment *
443 acpimcfg_get_segment(pci_chipset_tag_t pc, int bus)
444 {
445 	struct mcfg_segment *seg;
446 	u_int segment;
447 	int i;
448 
449 	segment = pci_get_segment(pc);
450 	for (i = 0; i < mcfg_nsegs; i++) {
451 		seg = &mcfg_segs[i];
452 		if (segment == seg->ms_segment &&
453 		    bus >= seg->ms_bus_start && bus <= seg->ms_bus_end)
454 			return seg;
455 	}
456 	return NULL;
457 }
458 
459 static int
460 acpimcfg_device_probe(const struct pci_attach_args *pa)
461 {
462 	pci_chipset_tag_t pc = pa->pa_pc;
463 	struct mcfg_segment *seg;
464 	struct mcfg_bus *mb;
465 	pcitag_t tag;
466 	pcireg_t reg;
467 	int bus = pa->pa_bus;
468 	int dev = pa->pa_device;
469 	int func = pa->pa_function;
470 	int last_dev, last_func, end_func;
471 	int alias = 0;
472 	const struct pci_quirkdata *qd;
473 	bool force_hasextcnf = false;
474 	bool force_noextcnf = false;
475 	int i, j;
476 
477 	seg = acpimcfg_get_segment(pc, bus);
478 	if (seg == NULL)
479 		return 0;
480 
481 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
482 	tag = pci_make_tag(pc, bus, dev, func);
483 
484 	/* Mark invalid between last probed device to probed device. */
485 	pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
486 	if (dev != 0 || func != 0) {
487 		for (i = last_dev; i <= dev; i++) {
488 			end_func = (i == dev) ? func : 8;
489 			for (j = last_func; j < end_func; j++) {
490 				if (i == last_dev && j == last_func)
491 					continue;
492 				PCIDEV_SET_INVALID(mb, i, j);
493 			}
494 			last_func = 0;
495 		}
496 	}
497 	mb->last_probed = tag;
498 
499 	reg = pci_conf_read(pc, tag, PCI_ID_REG);
500 	qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
501 	if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0)
502 		force_hasextcnf = true;
503 	if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0)
504 		force_noextcnf = true;
505 
506 	/* Probe extended configuration space. */
507 	if ((!force_hasextcnf) && ((force_noextcnf) ||
508 		((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1)
509 		|| (reg == 0)
510 		|| (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) {
511 		aprint_debug_dev(acpi_sc->sc_dev,
512 		    "MCFG: %03d:%02d:%d: invalid config space "
513 		    "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func,
514 		    PCI_CONF_SIZE, reg, alias ? "true" : "false");
515 		EXTCONF_SET_INVALID(mb, dev, func);
516 	}
517 
518 	aprint_debug_dev(acpi_sc->sc_dev,
519 	    "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n",
520 	    bus, dev, func, PCI_CONF_SIZE, reg,
521 	    EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N');
522 	mb->valid_ndevs++;
523 
524 	return 0;
525 }
526 
527 #ifdef PCI_MACHDEP_ENUMERATE_BUS
528 #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS
529 #endif
530 
531 static void
532 acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus)
533 {
534 	static const int wildcard[PCICF_NLOCS] = {
535 		PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT
536 	};
537 
538 	sc->sc_bus = bus;	/* XXX */
539 	sc->sc_pc = pc;
540 
541 	pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL);
542 }
543 
544 int
545 acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus)
546 {
547 	struct pci_softc *sc = device_private(self);
548 	struct mcfg_segment *seg = NULL;
549 	struct mcfg_bus *mb;
550 	bus_space_handle_t bsh;
551 	bus_addr_t baddr;
552 	pcitag_t tag;
553 	pcireg_t reg;
554 	bool is_e7520_mch;
555 	int boff;
556 	int last_dev, last_func;
557 	int i, j;
558 	int error;
559 
560 	if (!mcfg_inited)
561 		return ENXIO;
562 
563 	seg = acpimcfg_get_segment(pc, bus);
564 	if (seg == NULL)
565 		return ENOENT;
566 
567 	boff = bus - seg->ms_bus_start;
568 	if (seg->ms_bus[boff].valid_ndevs > 0)
569 		return 0;
570 
571 	mb = &seg->ms_bus[boff];
572 	baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS);
573 
574 	/* Map extended configuration space of all dev/func. */
575 	error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0,
576 	    &bsh);
577 	if (error != 0)
578 		return error;
579 	for (i = 0; i < 32; i++) {
580 		for (j = 0; j < 8; j++) {
581 			error = bus_space_subregion(seg->ms_bst, bsh,
582 			    EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
583 			    &mb->bsh[i][j]);
584 			if (error != 0)
585 				break;
586 		}
587 	}
588 	if (error != 0)
589 		return error;
590 
591 	aprint_debug("\n");
592 
593 	/* Probe extended configuration space of all devices. */
594 	memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
595 	memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf));
596 	mb->valid_ndevs = 0;
597 	mb->last_probed = pci_make_tag(pc, bus, 0, 0);
598 
599 	/*
600 	 * On an Intel E7520 we have to temporarily disable
601 	 * Enhanced Config Access error detection and reporting
602 	 * by setting the appropriate error mask in HI_ERRMASK register.
603 	 *
604 	 * See "Intel E7520 Memory Controller Hub (MCH) Datasheet",
605 	 * Document 303006-002, pg. 82
606 	 */
607 	tag = pci_make_tag(pc, 0, 0, 1);
608 	reg = pci_conf_read(pc, tag, PCI_ID_REG);
609 	is_e7520_mch = (reg ==
610 	    PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER));
611 	if (is_e7520_mch) {
612 		reg = pci_conf_read(pc, tag, 0x54);
613 		pci_conf_write(pc, tag, 0x54, reg | 0x20);
614 	}
615 
616 	acpimcfg_scan_bus(sc, pc, bus);
617 
618 	if (is_e7520_mch) {
619 		pci_conf_write(pc, tag, 0x54, reg);
620 	}
621 
622 	/* Unmap configuration space of all dev/func. */
623 	bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS);
624 	memset(mb->bsh, 0, sizeof(mb->bsh));
625 
626 	if (mb->valid_ndevs == 0) {
627 		aprint_debug_dev(acpi_sc->sc_dev,
628 		    "MCFG: bus %d: no valid devices.\n", bus);
629 		memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
630 		goto out;
631 	}
632 
633 	/* Mark invalid on remaining all devices. */
634 	pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
635 	for (i = last_dev; i < 32; i++) {
636 		for (j = last_func; j < 8; j++) {
637 			if (i == last_dev && j == last_func) {
638 				/* Don't mark invalid to last probed device. */
639 				continue;
640 			}
641 			PCIDEV_SET_INVALID(mb, i, j);
642 		}
643 		last_func = 0;
644 	}
645 
646 	/* Map configuration space per dev/func. */
647 	for (i = 0; i < 32; i++) {
648 		for (j = 0; j < 8; j++) {
649 			if (!PCIDEV_IS_VALID(mb, i, j))
650 				continue;
651 			error = bus_space_map(seg->ms_bst,
652 			    baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
653 			    0, &mb->bsh[i][j]);
654 			if (error != 0) {
655 				/* Unmap all handles when map failed. */
656 				do {
657 					while (--j >= 0) {
658 						if (!PCIDEV_IS_VALID(mb, i, j))
659 							continue;
660 						bus_space_unmap(seg->ms_bst,
661 						    mb->bsh[i][j],
662 						    PCI_EXTCONF_SIZE);
663 					}
664 					j = 8;
665 				} while (--i >= 0);
666 				memset(mb->valid_devs, 0,
667 				    sizeof(mb->valid_devs));
668 				goto out;
669 			}
670 		}
671 	}
672 
673 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus);
674 	for (i = 0; i < 32; i++) {
675 		for (j = 0; j < 8; j++) {
676 			if (PCIDEV_IS_VALID(mb, i, j)) {
677 				aprint_debug_dev(acpi_sc->sc_dev,
678 				    "MCFG: %03d:%02d:%d\n", bus, i, j);
679 			}
680 		}
681 	}
682 
683 	error = 0;
684 out:
685 	aprint_debug_dev(acpi_sc->sc_dev, "%s done", __func__);
686 
687 	return error;
688 }
689 
690 #ifdef PCI_NETBSD_CONFIGURE
691 ACPI_STATUS
692 acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx)
693 {
694 	struct pciconf_resources *pcires = ctx;
695 	int type;
696 	bus_addr_t addr;
697 	bus_size_t size;
698 	const char *s;
699 	int error;
700 
701 	if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
702 	    res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
703 	    res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)
704 		return AE_OK;
705 
706 	if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER)
707 		return AE_OK;
708 
709 	if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
710 	    res->Data.Address.ResourceType != ACPI_IO_RANGE)
711 		return AE_OK;
712 
713 	if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
714 	    res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) {
715 		type = PCICONF_RESOURCE_PREFETCHABLE_MEM;
716 		s = "prefetchable";
717 	} else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
718 	    res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) {
719 		type = PCICONF_RESOURCE_MEM;
720 		s = "non-prefetchable";
721 	} else {
722 		KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE);
723 		type = PCICONF_RESOURCE_IO;
724 		s = "i/o";
725 	}
726 
727 	switch (res->Type) {
728 	case ACPI_RESOURCE_TYPE_ADDRESS16:
729 		aprint_debug(
730 		    "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n",
731 		    res->Data.Address16.Address.Minimum,
732 		    res->Data.Address16.Address.AddressLength,
733 		    s);
734 		addr = res->Data.Address16.Address.Minimum;
735 		size = res->Data.Address16.Address.AddressLength;
736 		break;
737 	case ACPI_RESOURCE_TYPE_ADDRESS32:
738 		aprint_debug(
739 		    "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n",
740 		    res->Data.Address32.Address.Minimum,
741 		    res->Data.Address32.Address.AddressLength,
742 		    s);
743 		addr = res->Data.Address32.Address.Minimum;
744 		size = res->Data.Address32.Address.AddressLength;
745 		break;
746 	case ACPI_RESOURCE_TYPE_ADDRESS64:
747 		aprint_debug(
748 		    "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n",
749 		    res->Data.Address64.Address.Minimum,
750 		    res->Data.Address64.Address.AddressLength,
751 		    s);
752 		addr = res->Data.Address64.Address.Minimum;
753 		size = res->Data.Address64.Address.AddressLength;
754 		break;
755 
756 	default:
757 		return AE_OK;
758 	}
759 
760 	error = pciconf_resource_add(pcires, type, addr, size);
761 
762 	return error == 0 ? AE_OK : AE_NO_MEMORY;
763 }
764 
765 int
766 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
767     int bus, int cacheline_size)
768 {
769 	struct pciconf_resources *pcires;
770 	struct mcfg_segment *seg;
771 	struct mcfg_bus *mb;
772 	bus_space_handle_t bsh[256];
773 	bool bsh_mapped[256];
774 	int error, boff, b, d, f;
775 	bus_addr_t baddr;
776 	ACPI_STATUS rv;
777 
778 	seg = acpimcfg_get_segment(pc, bus);
779 	if (seg == NULL)
780 		return ENOENT;
781 
782 	pcires = pciconf_resource_init();
783 
784 	/*
785 	 * Map config space for all possible busses and mark them valid during
786 	 * configuration so pci_configure_bus can access them through our chipset
787 	 * tag with acpimcfg_conf_read/write below.
788 	 */
789 	memset(bsh_mapped, 0, sizeof(bsh_mapped));
790 	for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
791 		boff = b - seg->ms_bus_start;
792 		mb = &seg->ms_bus[boff];
793 		baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS);
794 
795 		/* Map extended configuration space of all dev/func. */
796 		error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0,
797 		    &bsh[b]);
798 		if (error != 0)
799 			goto cleanup;
800 		bsh_mapped[b] = true;
801 		for (d = 0; d < 32; d++) {
802 			for (f = 0; f < 8; f++) {
803 				error = bus_space_subregion(seg->ms_bst, bsh[b],
804 				    EXTCONF_OFFSET(d, f, 0), PCI_EXTCONF_SIZE,
805 				    &mb->bsh[d][f]);
806 				if (error != 0)
807 					break;
808 			}
809 		}
810 		if (error != 0)
811 			goto cleanup;
812 
813 		memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
814 	}
815 
816 	rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb,
817 	    pcires);
818 	if (ACPI_FAILURE(rv)) {
819 		error = ENXIO;
820 		goto cleanup;
821 	}
822 
823 	error = pci_configure_bus(pc, pcires, bus, cacheline_size);
824 
825 cleanup:
826 	/*
827 	 * Unmap config space for the segment's busses. Valid devices will be
828 	 * re-mapped later on by acpimcfg_map_bus.
829 	 */
830 	for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
831 		boff = b - seg->ms_bus_start;
832 		mb = &seg->ms_bus[boff];
833 		memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
834 
835 		if (bsh_mapped[b])
836 			bus_space_unmap(seg->ms_bst, bsh[b], ACPIMCFG_SIZE_PER_BUS);
837 	}
838 
839 	pciconf_resource_fini(pcires);
840 
841 	return error;
842 }
843 #else
844 int
845 acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
846     int bus, int cacheline_size)
847 {
848 	return ENXIO;
849 }
850 #endif
851 
852 int
853 acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data)
854 {
855 	struct mcfg_segment *seg = NULL;
856 	struct mcfg_bus *mb;
857 	int bus, dev, func;
858 
859 	KASSERT(reg < PCI_EXTCONF_SIZE);
860 	KASSERT((reg & 3) == 0);
861 
862 	if (!mcfg_inited) {
863 		*data = -1;
864 		return ENXIO;
865 	}
866 
867 	pci_decompose_tag(pc, tag, &bus, &dev, &func);
868 
869 	seg = acpimcfg_get_segment(pc, bus);
870 	if (seg == NULL) {
871 		*data = -1;
872 		return ERANGE;
873 	}
874 
875 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
876 	if (!PCIDEV_IS_VALID(mb, dev, func)) {
877 		*data = -1;
878 		return EINVAL;
879 	}
880 	if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) {
881 		*data = -1;
882 		return EINVAL;
883 	}
884 
885 	*data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg);
886 	return 0;
887 }
888 
889 int
890 acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
891 {
892 	struct mcfg_segment *seg = NULL;
893 	struct mcfg_bus *mb;
894 	int bus, dev, func;
895 
896 	KASSERT(reg < PCI_EXTCONF_SIZE);
897 	KASSERT((reg & 3) == 0);
898 
899 	if (!mcfg_inited)
900 		return ENXIO;
901 
902 	pci_decompose_tag(pc, tag, &bus, &dev, &func);
903 
904 	seg = acpimcfg_get_segment(pc, bus);
905 	if (seg == NULL)
906 		return ERANGE;
907 
908 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
909 	if (!PCIDEV_IS_VALID(mb, dev, func))
910 		return EINVAL;
911 	if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE)
912 		return EINVAL;
913 
914 	mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data);
915 	return 0;
916 }
917 
918 bool
919 acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg)
920 {
921 	struct mcfg_segment *seg = NULL;
922 	struct mcfg_bus *mb;
923 	int bus, dev, func;
924 
925 	if (!mcfg_inited)
926 		return false;
927 
928 	pci_decompose_tag(pc, tag, &bus, &dev, &func);
929 
930 	seg = acpimcfg_get_segment(pc, bus);
931 	if (seg == NULL)
932 		return false;
933 
934 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
935 	if (!PCIDEV_IS_VALID(mb, dev, func))
936 		return false;
937 	if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE)
938 		return false;
939 
940 	return true;
941 }
942