xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c (revision e00bdde3c6d406f40f53f3025defadc22f7ec31a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2016 Joyent, Inc.
24  * Copyright 2019 Western Digital Corporation
25  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
26  * Copyright 2023 Oxide Computer Company
27  */
28 
29 /*
30  * This file contains the x86 PCI platform resource discovery backend. This uses
31  * data from a combination of sources, preferring ACPI, if present, and if not,
32  * falling back to either the PCI hot-plug resource table or the mps tables.
33  *
34  * Today, to get information from ACPI we need to start from a dev_info_t. This
35  * is partly why the PRD interface has a callback for getting information about
36  * a dev_info_t. It also means we cannot initialize the tables with information
37  * until all devices have been initially scanned.
38  */
39 
40 #include <sys/types.h>
41 #include <sys/memlist.h>
42 #include <sys/pci.h>
43 #include <sys/pci_impl.h>
44 #include <sys/pci_cfgspace_impl.h>
45 #include <sys/sunndi.h>
46 #include <sys/systm.h>
47 #include <sys/cmn_err.h>
48 #include <sys/acpi/acpi.h>
49 #include <sys/acpica.h>
50 #include <sys/plat/pci_prd.h>
51 #include "mps_table.h"
52 #include "pcihrt.h"
53 
54 extern int pci_bios_maxbus;
55 
56 int pci_prd_debug = 0;
57 #define	dprintf	if (pci_prd_debug) printf
58 #define	dcmn_err	if (pci_prd_debug != 0) cmn_err
59 
60 static int tbl_init = 0;
61 static uchar_t *mps_extp = NULL;
62 static uchar_t *mps_ext_endp = NULL;
63 static struct php_entry *hrt_hpep;
64 static uint_t hrt_entry_cnt = 0;
65 static int acpi_cb_cnt = 0;
66 static pci_prd_upcalls_t *prd_upcalls;
67 
68 static void mps_probe(void);
69 static void acpi_pci_probe(void);
70 static int mps_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
71 static void hrt_probe(void);
72 static int hrt_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
73 static int acpi_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
74 static uchar_t *find_sig(uchar_t *cp, int len, char *sig);
75 static int checksum(unsigned char *cp, int len);
76 static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context);
77 static void acpi_trim_bus_ranges(void);
78 
79 /*
80  * -1 = attempt ACPI resource discovery
81  *  0 = don't attempt ACPI resource discovery
82  *  1 = ACPI resource discovery successful
83  */
84 volatile int acpi_resource_discovery = -1;
85 
86 struct memlist *acpi_io_res[PCI_MAX_BUS_NUM];
87 struct memlist *acpi_mem_res[PCI_MAX_BUS_NUM];
88 struct memlist *acpi_pmem_res[PCI_MAX_BUS_NUM];
89 struct memlist *acpi_bus_res[PCI_MAX_BUS_NUM];
90 
91 /*
92  * This indicates whether or not we have a traditional x86 BIOS present or not.
93  */
94 static boolean_t pci_prd_have_bios = B_TRUE;
95 
96 /*
97  * This value is set up as part of PCI configuration space initialization.
98  */
99 extern int pci_bios_maxbus;
100 
101 static void
102 acpi_pci_probe(void)
103 {
104 	ACPI_HANDLE ah;
105 	int bus;
106 
107 	if (acpi_resource_discovery == 0)
108 		return;
109 
110 	for (bus = 0; bus <= pci_bios_maxbus; bus++) {
111 		dev_info_t *dip;
112 
113 		dip = prd_upcalls->pru_bus2dip_f(bus);
114 		if (dip == NULL ||
115 		    (ACPI_FAILURE(acpica_get_handle(dip, &ah))))
116 			continue;
117 
118 		(void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb,
119 		    (void *)(uintptr_t)bus);
120 	}
121 
122 	if (acpi_cb_cnt > 0) {
123 		acpi_resource_discovery = 1;
124 		acpi_trim_bus_ranges();
125 	}
126 }
127 
128 /*
129  * Trim overlapping bus ranges in acpi_bus_res[]
130  * Some BIOSes report root-bridges with bus ranges that
131  * overlap, for example:"0..255" and "8..255". Lower-numbered
132  * ranges are trimmed by upper-numbered ranges (so "0..255" would
133  * be trimmed to "0..7", in the example).
134  */
135 static void
136 acpi_trim_bus_ranges(void)
137 {
138 	struct memlist *ranges, *current;
139 	int bus;
140 
141 	ranges = NULL;
142 
143 	/*
144 	 * Assumptions:
145 	 *  - there exists at most 1 bus range entry for each bus number
146 	 *  - there are no (broken) ranges that start at the same bus number
147 	 */
148 	for (bus = 0; bus < PCI_MAX_BUS_NUM; bus++) {
149 		struct memlist *prev, *orig, *new;
150 		/* skip buses with no range entry */
151 		if ((orig = acpi_bus_res[bus]) == NULL)
152 			continue;
153 
154 		/*
155 		 * create copy of existing range and overload
156 		 * 'prev' pointer to link existing to new copy
157 		 */
158 		new = memlist_alloc();
159 		new->ml_address = orig->ml_address;
160 		new->ml_size = orig->ml_size;
161 		new->ml_prev = orig;
162 
163 		/* sorted insertion of 'new' into ranges list */
164 		for (current = ranges, prev = NULL; current != NULL;
165 		    prev = current, current = current->ml_next)
166 			if (new->ml_address < current->ml_address)
167 				break;
168 
169 		if (prev == NULL) {
170 			/* place at beginning of (possibly) empty list */
171 			new->ml_next = ranges;
172 			ranges = new;
173 		} else {
174 			/* place in list (possibly at end) */
175 			new->ml_next = current;
176 			prev->ml_next = new;
177 		}
178 	}
179 
180 	/* scan the list, perform trimming */
181 	current = ranges;
182 	while (current != NULL) {
183 		struct memlist *next = current->ml_next;
184 
185 		/* done when no range above current */
186 		if (next == NULL)
187 			break;
188 
189 		/*
190 		 * trim size in original range element
191 		 * (current->ml_prev points to the original range)
192 		 */
193 		if ((current->ml_address + current->ml_size) > next->ml_address)
194 			current->ml_prev->ml_size =
195 			    next->ml_address - current->ml_address;
196 
197 		current = next;
198 	}
199 
200 	/* discard the list */
201 	memlist_free_all(&ranges);	/* OK if ranges == NULL */
202 }
203 
204 static int
205 acpi_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res)
206 {
207 	ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
208 
209 	switch (type) {
210 	case PCI_PRD_R_IO:
211 		*res = acpi_io_res[bus];
212 		break;
213 	case PCI_PRD_R_MMIO:
214 		*res = acpi_mem_res[bus];
215 		break;
216 	case PCI_PRD_R_PREFETCH:
217 		*res = acpi_pmem_res[bus];
218 		break;
219 	case PCI_PRD_R_BUS:
220 		*res = acpi_bus_res[bus];
221 		break;
222 	default:
223 		*res = NULL;
224 		break;
225 	}
226 
227 	/* memlist_count() treats NULL head as zero-length */
228 	return (memlist_count(*res));
229 }
230 
231 static struct memlist **
232 rlistpp(UINT8 t, UINT8 caching, int bus)
233 {
234 	switch (t) {
235 	case ACPI_MEMORY_RANGE:
236 		if (caching == ACPI_PREFETCHABLE_MEMORY)
237 			return (&acpi_pmem_res[bus]);
238 		else
239 			return (&acpi_mem_res[bus]);
240 		break;
241 
242 	case ACPI_IO_RANGE:
243 		return (&acpi_io_res[bus]);
244 		break;
245 
246 	case ACPI_BUS_NUMBER_RANGE:
247 		return (&acpi_bus_res[bus]);
248 		break;
249 	}
250 
251 	return (NULL);
252 }
253 
254 static void
255 acpi_dbg(uint_t bus, uint64_t addr, uint64_t len, uint8_t caching, uint8_t type,
256     char *tag)
257 {
258 	char *s;
259 
260 	switch (type) {
261 	case ACPI_MEMORY_RANGE:
262 		s = "MEM";
263 		break;
264 	case ACPI_IO_RANGE:
265 		s = "IO";
266 		break;
267 	case ACPI_BUS_NUMBER_RANGE:
268 		s = "BUS";
269 		break;
270 	default:
271 		s = "???";
272 		break;
273 	}
274 
275 	dprintf("ACPI: bus %x %s/%s %lx/%lx (Caching: %x)\n", bus,
276 	    tag, s, addr, len, caching);
277 }
278 
279 
280 static ACPI_STATUS
281 acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
282 {
283 	int bus = (intptr_t)context;
284 
285 	/* ignore consumed resources */
286 	if (rp->Data.Address.ProducerConsumer == 1)
287 		return (AE_OK);
288 
289 	switch (rp->Type) {
290 	case ACPI_RESOURCE_TYPE_IRQ:
291 		/* never expect to see a PCI bus produce an Interrupt */
292 		dprintf("%s\n", "IRQ");
293 		break;
294 
295 	case ACPI_RESOURCE_TYPE_DMA:
296 		/* never expect to see a PCI bus produce DMA */
297 		dprintf("%s\n", "DMA");
298 		break;
299 
300 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
301 		dprintf("%s\n", "START_DEPENDENT");
302 		break;
303 
304 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
305 		dprintf("%s\n", "END_DEPENDENT");
306 		break;
307 
308 	case ACPI_RESOURCE_TYPE_IO:
309 		if (rp->Data.Io.AddressLength == 0)
310 			break;
311 		acpi_cb_cnt++;
312 		memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum,
313 		    rp->Data.Io.AddressLength);
314 		if (pci_prd_debug != 0) {
315 			acpi_dbg(bus, rp->Data.Io.Minimum,
316 			    rp->Data.Io.AddressLength, 0, ACPI_IO_RANGE, "IO");
317 		}
318 		break;
319 
320 	case ACPI_RESOURCE_TYPE_FIXED_IO:
321 		/* only expect to see this as a consumer */
322 		dprintf("%s\n", "FIXED_IO");
323 		break;
324 
325 	case ACPI_RESOURCE_TYPE_VENDOR:
326 		dprintf("%s\n", "VENDOR");
327 		break;
328 
329 	case ACPI_RESOURCE_TYPE_END_TAG:
330 		dprintf("%s\n", "END_TAG");
331 		break;
332 
333 	case ACPI_RESOURCE_TYPE_MEMORY24:
334 		/* only expect to see this as a consumer */
335 		dprintf("%s\n", "MEMORY24");
336 		break;
337 
338 	case ACPI_RESOURCE_TYPE_MEMORY32:
339 		/* only expect to see this as a consumer */
340 		dprintf("%s\n", "MEMORY32");
341 		break;
342 
343 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
344 		/* only expect to see this as a consumer */
345 		dprintf("%s\n", "FIXED_MEMORY32");
346 		break;
347 
348 	case ACPI_RESOURCE_TYPE_ADDRESS16:
349 		if (rp->Data.Address16.Address.AddressLength == 0)
350 			break;
351 		acpi_cb_cnt++;
352 		memlist_insert(rlistpp(rp->Data.Address16.ResourceType,
353 		    rp->Data.Address.Info.Mem.Caching, bus),
354 		    rp->Data.Address16.Address.Minimum,
355 		    rp->Data.Address16.Address.AddressLength);
356 		if (pci_prd_debug != 0) {
357 			acpi_dbg(bus,
358 			    rp->Data.Address16.Address.Minimum,
359 			    rp->Data.Address16.Address.AddressLength,
360 			    rp->Data.Address.Info.Mem.Caching,
361 			    rp->Data.Address16.ResourceType, "ADDRESS16");
362 		}
363 		break;
364 
365 	case ACPI_RESOURCE_TYPE_ADDRESS32:
366 		if (rp->Data.Address32.Address.AddressLength == 0)
367 			break;
368 		acpi_cb_cnt++;
369 		memlist_insert(rlistpp(rp->Data.Address32.ResourceType,
370 		    rp->Data.Address.Info.Mem.Caching, bus),
371 		    rp->Data.Address32.Address.Minimum,
372 		    rp->Data.Address32.Address.AddressLength);
373 		if (pci_prd_debug != 0) {
374 			acpi_dbg(bus,
375 			    rp->Data.Address32.Address.Minimum,
376 			    rp->Data.Address32.Address.AddressLength,
377 			    rp->Data.Address.Info.Mem.Caching,
378 			    rp->Data.Address32.ResourceType, "ADDRESS32");
379 		}
380 		break;
381 
382 	case ACPI_RESOURCE_TYPE_ADDRESS64:
383 		if (rp->Data.Address64.Address.AddressLength == 0)
384 			break;
385 
386 		acpi_cb_cnt++;
387 		memlist_insert(rlistpp(rp->Data.Address64.ResourceType,
388 		    rp->Data.Address.Info.Mem.Caching, bus),
389 		    rp->Data.Address64.Address.Minimum,
390 		    rp->Data.Address64.Address.AddressLength);
391 		if (pci_prd_debug != 0) {
392 			acpi_dbg(bus,
393 			    rp->Data.Address64.Address.Minimum,
394 			    rp->Data.Address64.Address.AddressLength,
395 			    rp->Data.Address.Info.Mem.Caching,
396 			    rp->Data.Address64.ResourceType, "ADDRESS64");
397 		}
398 		break;
399 
400 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
401 		if (rp->Data.ExtAddress64.Address.AddressLength == 0)
402 			break;
403 		acpi_cb_cnt++;
404 		memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType,
405 		    rp->Data.Address.Info.Mem.Caching, bus),
406 		    rp->Data.ExtAddress64.Address.Minimum,
407 		    rp->Data.ExtAddress64.Address.AddressLength);
408 		if (pci_prd_debug != 0) {
409 			acpi_dbg(bus,
410 			    rp->Data.ExtAddress64.Address.Minimum,
411 			    rp->Data.ExtAddress64.Address.AddressLength,
412 			    rp->Data.Address.Info.Mem.Caching,
413 			    rp->Data.ExtAddress64.ResourceType, "EXTADDRESS64");
414 		}
415 		break;
416 
417 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
418 		/* never expect to see a PCI bus produce an Interrupt */
419 		dprintf("%s\n", "EXTENDED_IRQ");
420 		break;
421 
422 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
423 		/* never expect to see a PCI bus produce an GAS */
424 		dprintf("%s\n", "GENERIC_REGISTER");
425 		break;
426 	}
427 
428 	return (AE_OK);
429 }
430 
431 static void
432 mps_probe(void)
433 {
434 	uchar_t *extp;
435 	struct mps_fps_hdr *fpp = NULL;
436 	struct mps_ct_hdr *ctp;
437 	uintptr_t ebda_start, base_end;
438 	ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
439 
440 	base_size = *((ushort_t *)(0x413));
441 	ebda_seg = *((ushort_t *)(0x40e));
442 	ebda_start = ((uint32_t)ebda_seg) << 4;
443 	if (ebda_seg != 0) {
444 		fpp = (struct mps_fps_hdr *)find_sig(
445 		    (uchar_t *)ebda_start, 1024, "_MP_");
446 	}
447 	if (fpp == NULL) {
448 		base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
449 		if (base_end_seg != ebda_seg) {
450 			base_end = ((uintptr_t)base_end_seg) << 4;
451 			fpp = (struct mps_fps_hdr *)find_sig(
452 			    (uchar_t *)base_end, 1024, "_MP_");
453 		}
454 	}
455 	if (fpp == NULL) {
456 		fpp = (struct mps_fps_hdr *)find_sig(
457 		    (uchar_t *)0xF0000, 0x10000, "_MP_");
458 	}
459 
460 	if (fpp == NULL) {
461 		dprintf("MP Spec table doesn't exist");
462 		return;
463 	} else {
464 		dprintf("Found MP Floating Pointer Structure at %p\n",
465 		    (void *)fpp);
466 	}
467 
468 	if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
469 		dprintf("MP Floating Pointer Structure checksum error");
470 		return;
471 	}
472 
473 	ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
474 	if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
475 		dprintf("MP Configuration Table signature is wrong");
476 		return;
477 	}
478 
479 	base_len = ctp->ct_len;
480 	if (checksum((uchar_t *)ctp, base_len) != 0) {
481 		dprintf("MP Configuration Table checksum error");
482 		return;
483 	}
484 	if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
485 		dprintf("MP Spec 1.1 found - extended table doesn't exist");
486 		return;
487 	}
488 	if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
489 		dprintf("MP Spec 1.4 found - extended table doesn't exist");
490 		return;
491 	}
492 	extp = (uchar_t *)ctp + base_len;
493 	if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
494 		dprintf("MP Extended Table checksum error");
495 		return;
496 	}
497 	mps_extp = extp;
498 	mps_ext_endp = mps_extp + ext_len;
499 }
500 
501 
502 static int
503 mps_find_bus_res(uint32_t bus, pci_prd_rsrc_t rsrc, struct memlist **res)
504 {
505 	struct sasm *sasmp;
506 	uchar_t *extp;
507 	int res_cnt, type;
508 
509 	ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
510 
511 	if (mps_extp == NULL)
512 		return (0);
513 
514 	switch (rsrc) {
515 	case PCI_PRD_R_IO:
516 		type = IO_TYPE;
517 		break;
518 	case PCI_PRD_R_MMIO:
519 		type = MEM_TYPE;
520 		break;
521 	case PCI_PRD_R_PREFETCH:
522 		type = PREFETCH_TYPE;
523 		break;
524 	case PCI_PRD_R_BUS:
525 		type = BUSRANGE_TYPE;
526 		break;
527 	default:
528 		*res = NULL;
529 		return (0);
530 	}
531 
532 	extp = mps_extp;
533 	res_cnt = 0;
534 	while (extp < mps_ext_endp) {
535 		switch (*extp) {
536 		case SYS_AS_MAPPING:
537 			sasmp = (struct sasm *)extp;
538 			if (sasmp->sasm_as_type == type &&
539 			    sasmp->sasm_bus_id == bus) {
540 				uint64_t base, len;
541 
542 				base = (uint64_t)sasmp->sasm_as_base |
543 				    (uint64_t)sasmp->sasm_as_base_hi << 32;
544 				len = (uint64_t)sasmp->sasm_as_len |
545 				    (uint64_t)sasmp->sasm_as_len_hi << 32;
546 				memlist_insert(res, base, len);
547 				res_cnt++;
548 			}
549 			extp += SYS_AS_MAPPING_SIZE;
550 			break;
551 		case BUS_HIERARCHY_DESC:
552 			extp += BUS_HIERARCHY_DESC_SIZE;
553 			break;
554 		case COMP_BUS_AS_MODIFIER:
555 			extp += COMP_BUS_AS_MODIFIER_SIZE;
556 			break;
557 		default:
558 			cmn_err(CE_WARN, "Unknown descriptor type %d"
559 			    " in BIOS Multiprocessor Spec table.",
560 			    *extp);
561 			memlist_free_all(res);
562 			return (0);
563 		}
564 	}
565 	return (res_cnt);
566 }
567 
568 static void
569 hrt_probe(void)
570 {
571 	struct hrt_hdr *hrtp;
572 
573 	dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
574 	if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
575 	    0x10000, "$HRT")) == NULL) {
576 		dprintf("NO PCI Hot-Plug Resource Table");
577 		return;
578 	}
579 	dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
580 	if (hrtp->hrt_ver != 1) {
581 		dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
582 		return;
583 	}
584 	hrt_entry_cnt = (uint_t)hrtp->hrt_entry_cnt;
585 	dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
586 	hrt_hpep = (struct php_entry *)(hrtp + 1);
587 }
588 
589 static int
590 hrt_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res)
591 {
592 	int res_cnt;
593 	struct php_entry *hpep;
594 
595 	ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
596 
597 	if (hrt_hpep == NULL || hrt_entry_cnt == 0)
598 		return (0);
599 	hpep = hrt_hpep;
600 	res_cnt = 0;
601 	for (uint_t i = 0; i < hrt_entry_cnt; i++, hpep++) {
602 		if (hpep->php_pri_bus != bus)
603 			continue;
604 		if (type == PCI_PRD_R_IO) {
605 			if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
606 				continue;
607 			memlist_insert(res, (uint64_t)hpep->php_io_start,
608 			    (uint64_t)hpep->php_io_size);
609 			res_cnt++;
610 		} else if (type == PCI_PRD_R_MMIO) {
611 			if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
612 				continue;
613 			memlist_insert(res,
614 			    ((uint64_t)hpep->php_mem_start) << 16,
615 			    ((uint64_t)hpep->php_mem_size) << 16);
616 			res_cnt++;
617 		} else if (type == PCI_PRD_R_PREFETCH) {
618 			if (hpep->php_pfmem_start == 0 ||
619 			    hpep->php_pfmem_size == 0)
620 				continue;
621 			memlist_insert(res,
622 			    ((uint64_t)hpep->php_pfmem_start) << 16,
623 			    ((uint64_t)hpep->php_pfmem_size) << 16);
624 			res_cnt++;
625 		}
626 	}
627 	return (res_cnt);
628 }
629 
630 static uchar_t *
631 find_sig(uchar_t *cp, int len, char *sig)
632 {
633 	long i;
634 
635 	/* Search for the "_MP_"  or "$HRT" signature */
636 	for (i = 0; i < len; i += 16) {
637 		if (cp[0] == sig[0] && cp[1] == sig[1] &&
638 		    cp[2] == sig[2] && cp[3] == sig[3])
639 			return (cp);
640 		cp += 16;
641 	}
642 	return (NULL);
643 }
644 
645 static int
646 checksum(unsigned char *cp, int len)
647 {
648 	int i;
649 	unsigned int cksum;
650 
651 	for (i = cksum = 0; i < len; i++)
652 		cksum += (unsigned int) *cp++;
653 
654 	return ((int)(cksum & 0xFF));
655 }
656 
657 uint32_t
658 pci_prd_max_bus(void)
659 {
660 	return ((uint32_t)pci_bios_maxbus);
661 }
662 
663 struct memlist *
664 pci_prd_find_resource(uint32_t bus, pci_prd_rsrc_t rsrc)
665 {
666 	struct memlist *res = NULL;
667 
668 	if (bus > pci_bios_maxbus)
669 		return (NULL);
670 
671 	if (tbl_init == 0) {
672 		tbl_init = 1;
673 		acpi_pci_probe();
674 		if (pci_prd_have_bios) {
675 			hrt_probe();
676 			mps_probe();
677 		}
678 	}
679 
680 	if (acpi_find_bus_res(bus, rsrc, &res) > 0)
681 		return (res);
682 
683 	if (pci_prd_have_bios && hrt_find_bus_res(bus, rsrc, &res) > 0)
684 		return (res);
685 
686 	if (pci_prd_have_bios)
687 		(void) mps_find_bus_res(bus, rsrc, &res);
688 	return (res);
689 }
690 
691 typedef struct {
692 	pci_prd_root_complex_f	ppac_func;
693 	void			*ppac_arg;
694 } pci_prd_acpi_cb_t;
695 
696 static ACPI_STATUS
697 pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv)
698 {
699 	ACPI_DEVICE_INFO *adi;
700 	int busnum;
701 	pci_prd_acpi_cb_t *cb = ctx;
702 
703 	/*
704 	 * Use AcpiGetObjectInfo() to find the device _HID
705 	 * If not a PCI root-bus, ignore this device and continue
706 	 * the walk
707 	 */
708 	if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi)))
709 		return (AE_OK);
710 
711 	if (!(adi->Valid & ACPI_VALID_HID)) {
712 		AcpiOsFree(adi);
713 		return (AE_OK);
714 	}
715 
716 	if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING,
717 	    sizeof (PCI_ROOT_HID_STRING)) &&
718 	    strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING,
719 	    sizeof (PCI_EXPRESS_ROOT_HID_STRING))) {
720 		AcpiOsFree(adi);
721 		return (AE_OK);
722 	}
723 
724 	AcpiOsFree(adi);
725 
726 	/*
727 	 * acpica_get_busno() will check the presence of _BBN and
728 	 * fail if not present. It will then use the _CRS method to
729 	 * retrieve the actual bus number assigned, it will fall back
730 	 * to _BBN should the _CRS method fail.
731 	 */
732 	if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) {
733 		/*
734 		 * Ignore invalid _BBN return values here (rather
735 		 * than panic) and emit a warning; something else
736 		 * may suffer failure as a result of the broken BIOS.
737 		 */
738 		if (busnum < 0) {
739 			dcmn_err(CE_NOTE,
740 			    "pci_process_acpi_device: invalid _BBN 0x%x",
741 			    busnum);
742 			return (AE_CTRL_DEPTH);
743 		}
744 
745 		if (cb->ppac_func((uint32_t)busnum, cb->ppac_arg))
746 			return (AE_CTRL_DEPTH);
747 		return (AE_CTRL_TERMINATE);
748 	}
749 
750 	/* PCI and no _BBN, continue walk */
751 	return (AE_OK);
752 }
753 
754 void
755 pci_prd_root_complex_iter(pci_prd_root_complex_f func, void *arg)
756 {
757 	void *rv;
758 	pci_prd_acpi_cb_t cb;
759 
760 	cb.ppac_func = func;
761 	cb.ppac_arg = arg;
762 
763 	/*
764 	 * First scan ACPI devices for anything that might be here. After that,
765 	 * go through and check the old BIOS IRQ routing table for additional
766 	 * buses. Note, slot naming from the IRQ table comes later.
767 	 */
768 	(void) AcpiGetDevices(NULL, pci_process_acpi_device, &cb, &rv);
769 	pci_bios_bus_iter(func, arg);
770 
771 }
772 
773 
774 /*
775  * If there is actually a PCI IRQ routing table present, then we want to use
776  * this to go back and update the slot name. In particular, if we have no PCI
777  * IRQ routing table, then we use the existing slot names that were already set
778  * up for us in picex_slot_names_prop() from the capability register. Otherwise,
779  * we actually delete all slot-names properties from buses and instead use
780  * something from the IRQ routing table if it exists.
781  *
782  * Note, the property is always deleted regardless of whether or not it exists
783  * in the IRQ routing table. Finally, we have traditionally kept "pcie0" names
784  * as special as apparently that can't be represented in the IRQ routing table.
785  */
786 void
787 pci_prd_slot_name(uint32_t bus, dev_info_t *dip)
788 {
789 	char slotprop[256];
790 	int len;
791 	char *slotcap_name;
792 
793 	if (pci_irq_nroutes == 0)
794 		return;
795 
796 	if (dip != NULL) {
797 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip,
798 		    DDI_PROP_DONTPASS, "slot-names", &slotcap_name) !=
799 		    DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0) {
800 			(void) ndi_prop_remove(DDI_DEV_T_NONE,
801 			    pci_bus_res[bus].dip, "slot-names");
802 		}
803 	}
804 
805 
806 	len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop));
807 	if (len > 0) {
808 		if (dip != NULL) {
809 			ASSERT((len % sizeof (int)) == 0);
810 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
811 			    pci_bus_res[bus].dip, "slot-names",
812 			    (int *)slotprop, len / sizeof (int));
813 		} else {
814 			cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI "
815 			    "IRQ routing table; Not adding slot-names "
816 			    "property for incorrect bus %d", bus);
817 		}
818 	}
819 }
820 
821 boolean_t
822 pci_prd_multi_root_ok(void)
823 {
824 	return (acpi_resource_discovery > 0);
825 }
826 
827 /*
828  * These compatibility flags generally exist for i86pc. We need to still
829  * enumerate ISA bridges and the naming of device nodes and aliases must be kept
830  * consistent lest we break boot. See uts/common/io/pciex/pci_props.c theory
831  * statement for more information.
832  */
833 pci_prd_compat_flags_t
834 pci_prd_compat_flags(void)
835 {
836 	return (PCI_PRD_COMPAT_ISA | PCI_PRD_COMPAT_PCI_NODE_NAME |
837 	    PCI_PRD_COMPAT_SUBSYS);
838 }
839 
840 int
841 pci_prd_init(pci_prd_upcalls_t *upcalls)
842 {
843 	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
844 	    "efi-systab")) {
845 		pci_prd_have_bios = B_FALSE;
846 	}
847 
848 	prd_upcalls = upcalls;
849 
850 	return (0);
851 }
852 
853 void
854 pci_prd_fini(void)
855 {
856 	int bus;
857 
858 	for (bus = 0; bus <= pci_bios_maxbus; bus++) {
859 		memlist_free_all(&acpi_io_res[bus]);
860 		memlist_free_all(&acpi_mem_res[bus]);
861 		memlist_free_all(&acpi_pmem_res[bus]);
862 		memlist_free_all(&acpi_bus_res[bus]);
863 	}
864 }
865 
866 static struct modlmisc pci_prd_modlmisc_i86pc = {
867 	.misc_modops = &mod_miscops,
868 	.misc_linkinfo = "i86pc PCI Resource Discovery"
869 };
870 
871 static struct modlinkage pci_prd_modlinkage_i86pc = {
872 	.ml_rev = MODREV_1,
873 	.ml_linkage = { &pci_prd_modlmisc_i86pc, NULL }
874 };
875 
876 int
877 _init(void)
878 {
879 	return (mod_install(&pci_prd_modlinkage_i86pc));
880 }
881 
882 int
883 _info(struct modinfo *modinfop)
884 {
885 	return (mod_info(&pci_prd_modlinkage_i86pc, modinfop));
886 }
887 
888 int
889 _fini(void)
890 {
891 	return (mod_remove(&pci_prd_modlinkage_i86pc));
892 }
893