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 2024 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
acpi_pci_probe(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
acpi_trim_bus_ranges(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 = pci_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 pci_memlist_free_all(&ranges); /* OK if ranges == NULL */
202 }
203
204 static int
acpi_find_bus_res(uint32_t bus,pci_prd_rsrc_t type,struct memlist ** res)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 /* pci_memlist_count() treats NULL head as zero-length */
228 return (pci_memlist_count(*res));
229 }
230
231 static struct memlist **
rlistpp(UINT8 t,UINT8 caching,int bus)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
acpi_dbg(uint_t bus,uint64_t addr,uint64_t len,uint8_t caching,uint8_t type,char * tag)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
acpi_wr_cb(ACPI_RESOURCE * rp,void * context)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 pci_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 pci_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 pci_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 pci_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 pci_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
mps_probe(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
mps_find_bus_res(uint32_t bus,pci_prd_rsrc_t rsrc,struct memlist ** res)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 pci_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 pci_memlist_free_all(res);
562 return (0);
563 }
564 }
565 return (res_cnt);
566 }
567
568 static void
hrt_probe(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
hrt_find_bus_res(uint32_t bus,pci_prd_rsrc_t type,struct memlist ** res)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 pci_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 pci_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 pci_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 *
find_sig(uchar_t * cp,int len,char * sig)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
checksum(unsigned char * cp,int len)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
pci_prd_max_bus(void)658 pci_prd_max_bus(void)
659 {
660 return ((uint32_t)pci_bios_maxbus);
661 }
662
663 struct memlist *
pci_prd_find_resource(uint32_t bus,pci_prd_rsrc_t rsrc)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
pci_process_acpi_device(ACPI_HANDLE hdl,UINT32 level,void * ctx,void ** rv)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
pci_prd_root_complex_iter(pci_prd_root_complex_f func,void * arg)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
pci_prd_slot_name(uint32_t bus,dev_info_t * dip)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
pci_prd_multi_root_ok(void)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
pci_prd_compat_flags(void)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
pci_prd_init(pci_prd_upcalls_t * upcalls)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
pci_prd_fini(void)854 pci_prd_fini(void)
855 {
856 int bus;
857
858 for (bus = 0; bus <= pci_bios_maxbus; bus++) {
859 pci_memlist_free_all(&acpi_io_res[bus]);
860 pci_memlist_free_all(&acpi_mem_res[bus]);
861 pci_memlist_free_all(&acpi_pmem_res[bus]);
862 pci_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
_init(void)877 _init(void)
878 {
879 return (mod_install(&pci_prd_modlinkage_i86pc));
880 }
881
882 int
_info(struct modinfo * modinfop)883 _info(struct modinfo *modinfop)
884 {
885 return (mod_info(&pci_prd_modlinkage_i86pc, modinfop));
886 }
887
888 int
_fini(void)889 _fini(void)
890 {
891 return (mod_remove(&pci_prd_modlinkage_i86pc));
892 }
893