8702 PCI addresses with physaddr > 0xffffffff can't be mapped in
[unleashed.git] / usr / src / uts / intel / io / pci / pci_resource.c
blob4e5c7c051ac25e349fc6044e4e221a8f42ce16ee
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2016 Joyent, Inc.
27 * pci_resource.c -- routines to retrieve available bus resources from
28 * the MP Spec. Table and Hotplug Resource Table
31 #include <sys/types.h>
32 #include <sys/memlist.h>
33 #include <sys/pci_impl.h>
34 #include <sys/systm.h>
35 #include <sys/cmn_err.h>
36 #include <sys/acpi/acpi.h>
37 #include <sys/acpica.h>
38 #include "mps_table.h"
39 #include "pcihrt.h"
41 extern int pci_boot_debug;
42 extern int pci_bios_maxbus;
43 #define dprintf if (pci_boot_debug) printf
45 static int tbl_init = 0;
46 static uchar_t *mps_extp = NULL;
47 static uchar_t *mps_ext_endp = NULL;
48 static struct php_entry *hrt_hpep;
49 static int hrt_entry_cnt = 0;
50 static int acpi_cb_cnt = 0;
52 static void mps_probe(void);
53 static void acpi_pci_probe(void);
54 static int mps_find_bus_res(int, int, struct memlist **);
55 static void hrt_probe(void);
56 static int hrt_find_bus_res(int, int, struct memlist **);
57 static int acpi_find_bus_res(int, int, struct memlist **);
58 static uchar_t *find_sig(uchar_t *cp, int len, char *sig);
59 static int checksum(unsigned char *cp, int len);
60 static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context);
61 void bus_res_fini(void);
62 static void acpi_trim_bus_ranges(void);
64 struct memlist *acpi_io_res[256];
65 struct memlist *acpi_mem_res[256];
66 struct memlist *acpi_pmem_res[256];
67 struct memlist *acpi_bus_res[256];
70 * -1 = attempt ACPI resource discovery
71 * 0 = don't attempt ACPI resource discovery
72 * 1 = ACPI resource discovery successful
74 volatile int acpi_resource_discovery = -1;
76 struct memlist *
77 find_bus_res(int bus, int type)
79 struct memlist *res = NULL;
80 boolean_t bios = B_TRUE;
82 /* if efi-systab property exist, there is no BIOS */
83 if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
84 "efi-systab")) {
85 bios = B_FALSE;
88 if (tbl_init == 0) {
89 tbl_init = 1;
90 acpi_pci_probe();
91 if (bios) {
92 hrt_probe();
93 mps_probe();
97 if (acpi_find_bus_res(bus, type, &res) > 0)
98 return (res);
100 if (bios && hrt_find_bus_res(bus, type, &res) > 0)
101 return (res);
103 if (bios)
104 (void) mps_find_bus_res(bus, type, &res);
105 return (res);
109 static void
110 acpi_pci_probe(void)
112 ACPI_HANDLE ah;
113 dev_info_t *dip;
114 int bus;
116 if (acpi_resource_discovery == 0)
117 return;
119 for (bus = 0; bus <= pci_bios_maxbus; bus++) {
120 /* if no dip or no ACPI handle, no resources to discover */
121 dip = pci_bus_res[bus].dip;
122 if ((dip == NULL) ||
123 (ACPI_FAILURE(acpica_get_handle(dip, &ah))))
124 continue;
126 (void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb,
127 (void *)(uintptr_t)bus);
130 if (acpi_cb_cnt > 0) {
131 acpi_resource_discovery = 1;
132 acpi_trim_bus_ranges();
137 * Trim overlapping bus ranges in acpi_bus_res[]
138 * Some BIOSes report root-bridges with bus ranges that
139 * overlap, for example:"0..255" and "8..255". Lower-numbered
140 * ranges are trimmed by upper-numbered ranges (so "0..255" would
141 * be trimmed to "0..7", in the example).
143 static void
144 acpi_trim_bus_ranges()
146 struct memlist *ranges, *current;
147 int bus;
149 ranges = NULL;
152 * Assumptions:
153 * - there exists at most 1 bus range entry for each bus number
154 * - there are no (broken) ranges that start at the same bus number
156 for (bus = 0; bus < 256; bus++) {
157 struct memlist *prev, *orig, *new;
158 /* skip buses with no range entry */
159 if ((orig = acpi_bus_res[bus]) == NULL)
160 continue;
163 * create copy of existing range and overload
164 * 'prev' pointer to link existing to new copy
166 new = memlist_alloc();
167 new->ml_address = orig->ml_address;
168 new->ml_size = orig->ml_size;
169 new->ml_prev = orig;
171 /* sorted insertion of 'new' into ranges list */
172 for (current = ranges, prev = NULL; current != NULL;
173 prev = current, current = current->ml_next)
174 if (new->ml_address < current->ml_address)
175 break;
177 if (prev == NULL) {
178 /* place at beginning of (possibly) empty list */
179 new->ml_next = ranges;
180 ranges = new;
181 } else {
182 /* place in list (possibly at end) */
183 new->ml_next = current;
184 prev->ml_next = new;
188 /* scan the list, perform trimming */
189 current = ranges;
190 while (current != NULL) {
191 struct memlist *next = current->ml_next;
193 /* done when no range above current */
194 if (next == NULL)
195 break;
198 * trim size in original range element
199 * (current->ml_prev points to the original range)
201 if ((current->ml_address + current->ml_size) > next->ml_address)
202 current->ml_prev->ml_size =
203 next->ml_address - current->ml_address;
205 current = next;
208 /* discard the list */
209 memlist_free_all(&ranges); /* OK if ranges == NULL */
212 static int
213 acpi_find_bus_res(int bus, int type, struct memlist **res)
216 switch (type) {
217 case IO_TYPE:
218 *res = acpi_io_res[bus];
219 break;
220 case MEM_TYPE:
221 *res = acpi_mem_res[bus];
222 break;
223 case PREFETCH_TYPE:
224 *res = acpi_pmem_res[bus];
225 break;
226 case BUSRANGE_TYPE:
227 *res = acpi_bus_res[bus];
228 break;
229 default:
230 *res = NULL;
231 break;
234 /* memlist_count() treats NULL head as zero-length */
235 return (memlist_count(*res));
238 void
239 bus_res_fini(void)
241 int bus;
243 for (bus = 0; bus <= pci_bios_maxbus; bus++) {
244 memlist_free_all(&acpi_io_res[bus]);
245 memlist_free_all(&acpi_mem_res[bus]);
246 memlist_free_all(&acpi_pmem_res[bus]);
247 memlist_free_all(&acpi_bus_res[bus]);
252 struct memlist **
253 rlistpp(UINT8 t, UINT8 flags, int bus)
255 switch (t) {
257 case ACPI_MEMORY_RANGE:
258 /* is this really the best we've got? */
259 if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY)
260 return (&acpi_pmem_res[bus]);
261 else
262 return (&acpi_mem_res[bus]);
264 case ACPI_IO_RANGE: return &acpi_io_res[bus];
265 case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus];
267 return ((struct memlist **)NULL);
271 ACPI_STATUS
272 acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
274 int bus = (intptr_t)context;
276 /* ignore consumed resources */
277 if (rp->Data.Address.ProducerConsumer == 1)
278 return (AE_OK);
280 switch (rp->Type) {
281 case ACPI_RESOURCE_TYPE_IRQ:
282 /* never expect to see a PCI bus produce an Interrupt */
283 dprintf("%s\n", "IRQ");
284 break;
286 case ACPI_RESOURCE_TYPE_DMA:
287 /* never expect to see a PCI bus produce DMA */
288 dprintf("%s\n", "DMA");
289 break;
291 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
292 dprintf("%s\n", "START_DEPENDENT");
293 break;
295 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
296 dprintf("%s\n", "END_DEPENDENT");
297 break;
299 case ACPI_RESOURCE_TYPE_IO:
300 if (rp->Data.Io.AddressLength == 0)
301 break;
302 acpi_cb_cnt++;
303 memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum,
304 rp->Data.Io.AddressLength);
305 break;
307 case ACPI_RESOURCE_TYPE_FIXED_IO:
308 /* only expect to see this as a consumer */
309 dprintf("%s\n", "FIXED_IO");
310 break;
312 case ACPI_RESOURCE_TYPE_VENDOR:
313 dprintf("%s\n", "VENDOR");
314 break;
316 case ACPI_RESOURCE_TYPE_END_TAG:
317 dprintf("%s\n", "END_TAG");
318 break;
320 case ACPI_RESOURCE_TYPE_MEMORY24:
321 /* only expect to see this as a consumer */
322 dprintf("%s\n", "MEMORY24");
323 break;
325 case ACPI_RESOURCE_TYPE_MEMORY32:
326 /* only expect to see this as a consumer */
327 dprintf("%s\n", "MEMORY32");
328 break;
330 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
331 /* only expect to see this as a consumer */
332 dprintf("%s\n", "FIXED_MEMORY32");
333 break;
335 case ACPI_RESOURCE_TYPE_ADDRESS16:
336 if (rp->Data.Address16.Address.AddressLength == 0)
337 break;
338 acpi_cb_cnt++;
339 memlist_insert(rlistpp(rp->Data.Address16.ResourceType,
340 rp->Data.Address16.Info.TypeSpecific, bus),
341 rp->Data.Address16.Address.Minimum,
342 rp->Data.Address16.Address.AddressLength);
343 break;
345 case ACPI_RESOURCE_TYPE_ADDRESS32:
346 if (rp->Data.Address32.Address.AddressLength == 0)
347 break;
348 acpi_cb_cnt++;
349 memlist_insert(rlistpp(rp->Data.Address32.ResourceType,
350 rp->Data.Address32.Info.TypeSpecific, bus),
351 rp->Data.Address32.Address.Minimum,
352 rp->Data.Address32.Address.AddressLength);
353 break;
355 case ACPI_RESOURCE_TYPE_ADDRESS64:
357 * We comment out this block because we currently cannot deal with
358 * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO
359 * support.
361 #if 0
362 if (rp->Data.Address64.AddressLength == 0)
363 break;
364 acpi_cb_cnt++;
365 memlist_insert(rlistpp(rp->Data.Address64.ResourceType,
366 rp->Data.Address64.Info.TypeSpecific, bus),
367 rp->Data.Address64.Minimum,
368 rp->Data.Address64.AddressLength);
369 #endif
370 break;
372 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
373 #if 0 /* Will revisit this when we add PCI 64-bit MMIO support */
374 if (rp->Data.ExtAddress64.AddressLength == 0)
375 break;
376 acpi_cb_cnt++;
377 memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType,
378 rp->Data.ExtAddress64.Info.TypeSpecific, bus),
379 rp->Data.ExtAddress64.Minimum,
380 rp->Data.ExtAddress64.AddressLength);
381 #endif
382 break;
384 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
385 /* never expect to see a PCI bus produce an Interrupt */
386 dprintf("%s\n", "EXTENDED_IRQ");
387 break;
389 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
390 /* never expect to see a PCI bus produce an GAS */
391 dprintf("%s\n", "GENERIC_REGISTER");
392 break;
395 return (AE_OK);
398 static void
399 mps_probe()
401 uchar_t *extp;
402 struct mps_fps_hdr *fpp = NULL;
403 struct mps_ct_hdr *ctp;
404 uintptr_t ebda_start, base_end;
405 ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
407 base_size = *((ushort_t *)(0x413));
408 ebda_seg = *((ushort_t *)(0x40e));
409 ebda_start = ((uint32_t)ebda_seg) << 4;
410 if (ebda_seg != 0) {
411 fpp = (struct mps_fps_hdr *)find_sig(
412 (uchar_t *)ebda_start, 1024, "_MP_");
414 if (fpp == NULL) {
415 base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
416 if (base_end_seg != ebda_seg) {
417 base_end = ((uintptr_t)base_end_seg) << 4;
418 fpp = (struct mps_fps_hdr *)find_sig(
419 (uchar_t *)base_end, 1024, "_MP_");
422 if (fpp == NULL) {
423 fpp = (struct mps_fps_hdr *)find_sig(
424 (uchar_t *)0xF0000, 0x10000, "_MP_");
427 if (fpp == NULL) {
428 dprintf("MP Spec table doesn't exist");
429 return;
430 } else {
431 dprintf("Found MP Floating Pointer Structure at %p\n",
432 (void *)fpp);
435 if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
436 dprintf("MP Floating Pointer Structure checksum error");
437 return;
440 ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
441 if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
442 dprintf("MP Configuration Table signature is wrong");
443 return;
446 base_len = ctp->ct_len;
447 if (checksum((uchar_t *)ctp, base_len) != 0) {
448 dprintf("MP Configuration Table checksum error");
449 return;
451 if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
452 dprintf("MP Spec 1.1 found - extended table doesn't exist");
453 return;
455 if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
456 dprintf("MP Spec 1.4 found - extended table doesn't exist");
457 return;
459 extp = (uchar_t *)ctp + base_len;
460 if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
461 dprintf("MP Extended Table checksum error");
462 return;
464 mps_extp = extp;
465 mps_ext_endp = mps_extp + ext_len;
469 static int
470 mps_find_bus_res(int bus, int type, struct memlist **res)
472 struct sasm *sasmp;
473 uchar_t *extp;
474 int res_cnt;
476 if (mps_extp == NULL)
477 return (0);
478 extp = mps_extp;
479 res_cnt = 0;
480 while (extp < mps_ext_endp) {
481 switch (*extp) {
482 case SYS_AS_MAPPING:
483 sasmp = (struct sasm *)extp;
484 if (((int)sasmp->sasm_as_type) == type &&
485 ((int)sasmp->sasm_bus_id) == bus) {
486 uint64_t base, len;
488 base = (uint64_t)sasmp->sasm_as_base |
489 (uint64_t)sasmp->sasm_as_base_hi << 32;
490 len = (uint64_t)sasmp->sasm_as_len |
491 (uint64_t)sasmp->sasm_as_len_hi << 32;
492 memlist_insert(res, base, len);
493 res_cnt++;
495 extp += SYS_AS_MAPPING_SIZE;
496 break;
497 case BUS_HIERARCHY_DESC:
498 extp += BUS_HIERARCHY_DESC_SIZE;
499 break;
500 case COMP_BUS_AS_MODIFIER:
501 extp += COMP_BUS_AS_MODIFIER_SIZE;
502 break;
503 default:
504 cmn_err(CE_WARN, "Unknown descriptor type %d"
505 " in BIOS Multiprocessor Spec table.",
506 *extp);
507 while (*res) {
508 struct memlist *tmp = *res;
509 *res = tmp->ml_next;
510 memlist_free(tmp);
512 return (0);
515 return (res_cnt);
518 static void
519 hrt_probe()
521 struct hrt_hdr *hrtp;
523 dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
524 if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
525 0x10000, "$HRT")) == NULL) {
526 dprintf("NO PCI Hot-Plug Resource Table");
527 return;
529 dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
530 if (hrtp->hrt_ver != 1) {
531 dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
532 return;
534 hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
535 dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
536 hrt_hpep = (struct php_entry *)(hrtp + 1);
539 static int
540 hrt_find_bus_res(int bus, int type, struct memlist **res)
542 int res_cnt, i;
543 struct php_entry *hpep;
545 if (hrt_hpep == NULL || hrt_entry_cnt == 0)
546 return (0);
547 hpep = hrt_hpep;
548 res_cnt = 0;
549 for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
550 if (hpep->php_pri_bus != bus)
551 continue;
552 if (type == IO_TYPE) {
553 if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
554 continue;
555 memlist_insert(res, (uint64_t)hpep->php_io_start,
556 (uint64_t)hpep->php_io_size);
557 res_cnt++;
558 } else if (type == MEM_TYPE) {
559 if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
560 continue;
561 memlist_insert(res,
562 (uint64_t)(((int)hpep->php_mem_start) << 16),
563 (uint64_t)(((int)hpep->php_mem_size) << 16));
564 res_cnt++;
565 } else if (type == PREFETCH_TYPE) {
566 if (hpep->php_pfmem_start == 0 ||
567 hpep->php_pfmem_size == 0)
568 continue;
569 memlist_insert(res,
570 (uint64_t)(((int)hpep->php_pfmem_start) << 16),
571 (uint64_t)(((int)hpep->php_pfmem_size) << 16));
572 res_cnt++;
575 return (res_cnt);
578 static uchar_t *
579 find_sig(uchar_t *cp, int len, char *sig)
581 long i;
583 /* Search for the "_MP_" or "$HRT" signature */
584 for (i = 0; i < len; i += 16) {
585 if (cp[0] == sig[0] && cp[1] == sig[1] &&
586 cp[2] == sig[2] && cp[3] == sig[3])
587 return (cp);
588 cp += 16;
590 return (NULL);
593 static int
594 checksum(unsigned char *cp, int len)
596 int i;
597 unsigned int cksum;
599 for (i = cksum = 0; i < len; i++)
600 cksum += (unsigned int) *cp++;
602 return ((int)(cksum & 0xFF));
605 #ifdef UNUSED_BUS_HIERARY_INFO
608 * At this point, the bus hierarchy entries do not appear to
609 * provide anything we can't find out from PCI config space.
610 * The only interesting bit is the ISA bus number, which we
611 * don't care.
614 mps_find_parent_bus(int bus)
616 struct sasm *sasmp;
617 uchar_t *extp;
619 if (mps_extp == NULL)
620 return (-1);
622 extp = mps_extp;
623 while (extp < mps_ext_endp) {
624 bhdp = (struct bhd *)extp;
625 switch (*extp) {
626 case SYS_AS_MAPPING:
627 extp += SYS_AS_MAPPING_SIZE;
628 break;
629 case BUS_HIERARCHY_DESC:
630 if (bhdp->bhd_bus_id == bus)
631 return (bhdp->bhd_parent);
632 extp += BUS_HIERARCHY_DESC_SIZE;
633 break;
634 case COMP_BUS_AS_MODIFIER:
635 extp += COMP_BUS_AS_MODIFIER_SIZE;
636 break;
637 default:
638 cmn_err(CE_WARN, "Unknown descriptor type %d"
639 " in BIOS Multiprocessor Spec table.",
640 *extp);
641 return (-1);
644 return (-1);
648 hrt_find_bus_range(int bus)
650 int i, max_bus, sub_bus;
651 struct php_entry *hpep;
653 if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
654 return (-1);
656 hpep = hrt_hpep;
657 max_bus = -1;
658 for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
659 if (hpep->php_pri_bus != bus)
660 continue;
661 sub_bus = (int)hpep->php_subord_bus;
662 if (sub_bus > max_bus)
663 max_bus = sub_bus;
665 return (max_bus);
668 #endif /* UNUSED_BUS_HIERARY_INFO */