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]
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"
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;
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
,
97 if (acpi_find_bus_res(bus
, type
, &res
) > 0)
100 if (bios
&& hrt_find_bus_res(bus
, type
, &res
) > 0)
104 (void) mps_find_bus_res(bus
, type
, &res
);
116 if (acpi_resource_discovery
== 0)
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
;
123 (ACPI_FAILURE(acpica_get_handle(dip
, &ah
))))
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).
144 acpi_trim_bus_ranges()
146 struct memlist
*ranges
, *current
;
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
)
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
;
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
)
178 /* place at beginning of (possibly) empty list */
179 new->ml_next
= ranges
;
182 /* place in list (possibly at end) */
183 new->ml_next
= current
;
188 /* scan the list, perform trimming */
190 while (current
!= NULL
) {
191 struct memlist
*next
= current
->ml_next
;
193 /* done when no range above current */
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
;
208 /* discard the list */
209 memlist_free_all(&ranges
); /* OK if ranges == NULL */
213 acpi_find_bus_res(int bus
, int type
, struct memlist
**res
)
218 *res
= acpi_io_res
[bus
];
221 *res
= acpi_mem_res
[bus
];
224 *res
= acpi_pmem_res
[bus
];
227 *res
= acpi_bus_res
[bus
];
234 /* memlist_count() treats NULL head as zero-length */
235 return (memlist_count(*res
));
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
]);
253 rlistpp(UINT8 t
, UINT8 flags
, int bus
)
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
]);
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
);
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)
281 case ACPI_RESOURCE_TYPE_IRQ
:
282 /* never expect to see a PCI bus produce an Interrupt */
283 dprintf("%s\n", "IRQ");
286 case ACPI_RESOURCE_TYPE_DMA
:
287 /* never expect to see a PCI bus produce DMA */
288 dprintf("%s\n", "DMA");
291 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
292 dprintf("%s\n", "START_DEPENDENT");
295 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
296 dprintf("%s\n", "END_DEPENDENT");
299 case ACPI_RESOURCE_TYPE_IO
:
300 if (rp
->Data
.Io
.AddressLength
== 0)
303 memlist_insert(&acpi_io_res
[bus
], rp
->Data
.Io
.Minimum
,
304 rp
->Data
.Io
.AddressLength
);
307 case ACPI_RESOURCE_TYPE_FIXED_IO
:
308 /* only expect to see this as a consumer */
309 dprintf("%s\n", "FIXED_IO");
312 case ACPI_RESOURCE_TYPE_VENDOR
:
313 dprintf("%s\n", "VENDOR");
316 case ACPI_RESOURCE_TYPE_END_TAG
:
317 dprintf("%s\n", "END_TAG");
320 case ACPI_RESOURCE_TYPE_MEMORY24
:
321 /* only expect to see this as a consumer */
322 dprintf("%s\n", "MEMORY24");
325 case ACPI_RESOURCE_TYPE_MEMORY32
:
326 /* only expect to see this as a consumer */
327 dprintf("%s\n", "MEMORY32");
330 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
331 /* only expect to see this as a consumer */
332 dprintf("%s\n", "FIXED_MEMORY32");
335 case ACPI_RESOURCE_TYPE_ADDRESS16
:
336 if (rp
->Data
.Address16
.Address
.AddressLength
== 0)
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
);
345 case ACPI_RESOURCE_TYPE_ADDRESS32
:
346 if (rp
->Data
.Address32
.Address
.AddressLength
== 0)
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
);
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
362 if (rp
->Data
.Address64
.AddressLength
== 0)
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
);
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)
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
);
384 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
385 /* never expect to see a PCI bus produce an Interrupt */
386 dprintf("%s\n", "EXTENDED_IRQ");
389 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER
:
390 /* never expect to see a PCI bus produce an GAS */
391 dprintf("%s\n", "GENERIC_REGISTER");
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;
411 fpp
= (struct mps_fps_hdr
*)find_sig(
412 (uchar_t
*)ebda_start
, 1024, "_MP_");
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_");
423 fpp
= (struct mps_fps_hdr
*)find_sig(
424 (uchar_t
*)0xF0000, 0x10000, "_MP_");
428 dprintf("MP Spec table doesn't exist");
431 dprintf("Found MP Floating Pointer Structure at %p\n",
435 if (checksum((uchar_t
*)fpp
, fpp
->fps_len
* 16) != 0) {
436 dprintf("MP Floating Pointer Structure checksum error");
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");
446 base_len
= ctp
->ct_len
;
447 if (checksum((uchar_t
*)ctp
, base_len
) != 0) {
448 dprintf("MP Configuration Table checksum error");
451 if (ctp
->ct_spec_rev
!= 4) { /* not MPSpec rev 1.4 */
452 dprintf("MP Spec 1.1 found - extended table doesn't exist");
455 if ((ext_len
= ctp
->ct_ext_tbl_len
) == 0) {
456 dprintf("MP Spec 1.4 found - extended table doesn't exist");
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");
465 mps_ext_endp
= mps_extp
+ ext_len
;
470 mps_find_bus_res(int bus
, int type
, struct memlist
**res
)
476 if (mps_extp
== NULL
)
480 while (extp
< mps_ext_endp
) {
483 sasmp
= (struct sasm
*)extp
;
484 if (((int)sasmp
->sasm_as_type
) == type
&&
485 ((int)sasmp
->sasm_bus_id
) == bus
) {
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
);
495 extp
+= SYS_AS_MAPPING_SIZE
;
497 case BUS_HIERARCHY_DESC
:
498 extp
+= BUS_HIERARCHY_DESC_SIZE
;
500 case COMP_BUS_AS_MODIFIER
:
501 extp
+= COMP_BUS_AS_MODIFIER_SIZE
;
504 cmn_err(CE_WARN
, "Unknown descriptor type %d"
505 " in BIOS Multiprocessor Spec table.",
508 struct memlist
*tmp
= *res
;
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");
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");
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);
540 hrt_find_bus_res(int bus
, int type
, struct memlist
**res
)
543 struct php_entry
*hpep
;
545 if (hrt_hpep
== NULL
|| hrt_entry_cnt
== 0)
549 for (i
= 0; i
< hrt_entry_cnt
; i
++, hpep
++) {
550 if (hpep
->php_pri_bus
!= bus
)
552 if (type
== IO_TYPE
) {
553 if (hpep
->php_io_start
== 0 || hpep
->php_io_size
== 0)
555 memlist_insert(res
, (uint64_t)hpep
->php_io_start
,
556 (uint64_t)hpep
->php_io_size
);
558 } else if (type
== MEM_TYPE
) {
559 if (hpep
->php_mem_start
== 0 || hpep
->php_mem_size
== 0)
562 (uint64_t)(((int)hpep
->php_mem_start
) << 16),
563 (uint64_t)(((int)hpep
->php_mem_size
) << 16));
565 } else if (type
== PREFETCH_TYPE
) {
566 if (hpep
->php_pfmem_start
== 0 ||
567 hpep
->php_pfmem_size
== 0)
570 (uint64_t)(((int)hpep
->php_pfmem_start
) << 16),
571 (uint64_t)(((int)hpep
->php_pfmem_size
) << 16));
579 find_sig(uchar_t
*cp
, int len
, char *sig
)
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])
594 checksum(unsigned char *cp
, int len
)
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
614 mps_find_parent_bus(int bus
)
619 if (mps_extp
== NULL
)
623 while (extp
< mps_ext_endp
) {
624 bhdp
= (struct bhd
*)extp
;
627 extp
+= SYS_AS_MAPPING_SIZE
;
629 case BUS_HIERARCHY_DESC
:
630 if (bhdp
->bhd_bus_id
== bus
)
631 return (bhdp
->bhd_parent
);
632 extp
+= BUS_HIERARCHY_DESC_SIZE
;
634 case COMP_BUS_AS_MODIFIER
:
635 extp
+= COMP_BUS_AS_MODIFIER_SIZE
;
638 cmn_err(CE_WARN
, "Unknown descriptor type %d"
639 " in BIOS Multiprocessor Spec table.",
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) {
658 for (i
= 0; i
< hrt_entry_cnt
; i
++, hpep
++) {
659 if (hpep
->php_pri_bus
!= bus
)
661 sub_bus
= (int)hpep
->php_subord_bus
;
662 if (sub_bus
> max_bus
)
668 #endif /* UNUSED_BUS_HIERARY_INFO */