1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 58fc7923fSDana Myers * Common Development and Distribution License (the "License"). 68fc7923fSDana Myers * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj /* 2256f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23ae115bc7Smrj * Use is subject to license terms. 24ae115bc7Smrj * 25385cc6b4SJerry Jelinek * Copyright 2016 Joyent, Inc. 26385cc6b4SJerry Jelinek * 27ae115bc7Smrj * pci_resource.c -- routines to retrieve available bus resources from 28ae115bc7Smrj * the MP Spec. Table and Hotplug Resource Table 29ae115bc7Smrj */ 30ae115bc7Smrj 31ae115bc7Smrj #include <sys/types.h> 32ae115bc7Smrj #include <sys/memlist.h> 33ae115bc7Smrj #include <sys/pci_impl.h> 34ae115bc7Smrj #include <sys/systm.h> 35ae115bc7Smrj #include <sys/cmn_err.h> 368fc7923fSDana Myers #include <sys/acpi/acpi.h> 378fc7923fSDana Myers #include <sys/acpica.h> 38ae115bc7Smrj #include "mps_table.h" 39ae115bc7Smrj #include "pcihrt.h" 40ae115bc7Smrj 41ae115bc7Smrj extern int pci_boot_debug; 4247310cedSDana Myers extern int pci_bios_maxbus; 43ae115bc7Smrj #define dprintf if (pci_boot_debug) printf 44ae115bc7Smrj 45ae115bc7Smrj static int tbl_init = 0; 46ae115bc7Smrj static uchar_t *mps_extp = NULL; 47ae115bc7Smrj static uchar_t *mps_ext_endp = NULL; 48ae115bc7Smrj static struct php_entry *hrt_hpep; 49ae115bc7Smrj static int hrt_entry_cnt = 0; 508fc7923fSDana Myers static int acpi_cb_cnt = 0; 51ae115bc7Smrj 52ae115bc7Smrj static void mps_probe(void); 538fc7923fSDana Myers static void acpi_pci_probe(void); 54ae115bc7Smrj static int mps_find_bus_res(int, int, struct memlist **); 55ae115bc7Smrj static void hrt_probe(void); 56ae115bc7Smrj static int hrt_find_bus_res(int, int, struct memlist **); 578fc7923fSDana Myers static int acpi_find_bus_res(int, int, struct memlist **); 58ae115bc7Smrj static uchar_t *find_sig(uchar_t *cp, int len, char *sig); 59ae115bc7Smrj static int checksum(unsigned char *cp, int len); 608fc7923fSDana Myers static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context); 618fc7923fSDana Myers void bus_res_fini(void); 62eaeab0c1SDana Myers static void acpi_trim_bus_ranges(void); 638fc7923fSDana Myers 648fc7923fSDana Myers struct memlist *acpi_io_res[256]; 658fc7923fSDana Myers struct memlist *acpi_mem_res[256]; 668fc7923fSDana Myers struct memlist *acpi_pmem_res[256]; 678fc7923fSDana Myers struct memlist *acpi_bus_res[256]; 688fc7923fSDana Myers 698fc7923fSDana Myers /* 708fc7923fSDana Myers * -1 = attempt ACPI resource discovery 718fc7923fSDana Myers * 0 = don't attempt ACPI resource discovery 728fc7923fSDana Myers * 1 = ACPI resource discovery successful 738fc7923fSDana Myers */ 748fc7923fSDana Myers volatile int acpi_resource_discovery = -1; 75ae115bc7Smrj 76ae115bc7Smrj struct memlist * 77ae115bc7Smrj find_bus_res(int bus, int type) 78ae115bc7Smrj { 79ae115bc7Smrj struct memlist *res = NULL; 80ae115bc7Smrj 81ae115bc7Smrj if (tbl_init == 0) { 82ae115bc7Smrj tbl_init = 1; 838fc7923fSDana Myers acpi_pci_probe(); 84ae115bc7Smrj hrt_probe(); 85ae115bc7Smrj mps_probe(); 86ae115bc7Smrj } 87ae115bc7Smrj 888fc7923fSDana Myers if (acpi_find_bus_res(bus, type, &res) > 0) 898fc7923fSDana Myers return (res); 908fc7923fSDana Myers 91ae115bc7Smrj if (hrt_find_bus_res(bus, type, &res) > 0) 92ae115bc7Smrj return (res); 93ae115bc7Smrj 94ae115bc7Smrj (void) mps_find_bus_res(bus, type, &res); 95ae115bc7Smrj return (res); 96ae115bc7Smrj } 97ae115bc7Smrj 988fc7923fSDana Myers 998fc7923fSDana Myers static void 1008fc7923fSDana Myers acpi_pci_probe(void) 1018fc7923fSDana Myers { 1028fc7923fSDana Myers ACPI_HANDLE ah; 1038fc7923fSDana Myers dev_info_t *dip; 1048fc7923fSDana Myers int bus; 1058fc7923fSDana Myers 1068fc7923fSDana Myers if (acpi_resource_discovery == 0) 1078fc7923fSDana Myers return; 1088fc7923fSDana Myers 10947310cedSDana Myers for (bus = 0; bus <= pci_bios_maxbus; bus++) { 1108fc7923fSDana Myers /* if no dip or no ACPI handle, no resources to discover */ 1118fc7923fSDana Myers dip = pci_bus_res[bus].dip; 1128fc7923fSDana Myers if ((dip == NULL) || 1138fc7923fSDana Myers (ACPI_FAILURE(acpica_get_handle(dip, &ah)))) 1148fc7923fSDana Myers continue; 1158fc7923fSDana Myers 1168fc7923fSDana Myers (void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb, 1178fc7923fSDana Myers (void *)(uintptr_t)bus); 1188fc7923fSDana Myers } 1198fc7923fSDana Myers 120eaeab0c1SDana Myers if (acpi_cb_cnt > 0) { 1218fc7923fSDana Myers acpi_resource_discovery = 1; 122eaeab0c1SDana Myers acpi_trim_bus_ranges(); 123eaeab0c1SDana Myers } 124eaeab0c1SDana Myers } 125eaeab0c1SDana Myers 126eaeab0c1SDana Myers /* 127eaeab0c1SDana Myers * Trim overlapping bus ranges in acpi_bus_res[] 128eaeab0c1SDana Myers * Some BIOSes report root-bridges with bus ranges that 129eaeab0c1SDana Myers * overlap, for example:"0..255" and "8..255". Lower-numbered 130eaeab0c1SDana Myers * ranges are trimmed by upper-numbered ranges (so "0..255" would 131eaeab0c1SDana Myers * be trimmed to "0..7", in the example). 132eaeab0c1SDana Myers */ 133eaeab0c1SDana Myers static void 134eaeab0c1SDana Myers acpi_trim_bus_ranges() 135eaeab0c1SDana Myers { 136eaeab0c1SDana Myers struct memlist *ranges, *current; 137eaeab0c1SDana Myers int bus; 138eaeab0c1SDana Myers 139eaeab0c1SDana Myers ranges = NULL; 140eaeab0c1SDana Myers 141eaeab0c1SDana Myers /* 142eaeab0c1SDana Myers * Assumptions: 143eaeab0c1SDana Myers * - there exists at most 1 bus range entry for each bus number 144eaeab0c1SDana Myers * - there are no (broken) ranges that start at the same bus number 145eaeab0c1SDana Myers */ 146eaeab0c1SDana Myers for (bus = 0; bus < 256; bus++) { 147eaeab0c1SDana Myers struct memlist *prev, *orig, *new; 148eaeab0c1SDana Myers /* skip buses with no range entry */ 149eaeab0c1SDana Myers if ((orig = acpi_bus_res[bus]) == NULL) 150eaeab0c1SDana Myers continue; 151eaeab0c1SDana Myers 152eaeab0c1SDana Myers /* 153eaeab0c1SDana Myers * create copy of existing range and overload 154eaeab0c1SDana Myers * 'prev' pointer to link existing to new copy 155eaeab0c1SDana Myers */ 156eaeab0c1SDana Myers new = memlist_alloc(); 15756f33205SJonathan Adams new->ml_address = orig->ml_address; 15856f33205SJonathan Adams new->ml_size = orig->ml_size; 15956f33205SJonathan Adams new->ml_prev = orig; 160eaeab0c1SDana Myers 161eaeab0c1SDana Myers /* sorted insertion of 'new' into ranges list */ 162eaeab0c1SDana Myers for (current = ranges, prev = NULL; current != NULL; 16356f33205SJonathan Adams prev = current, current = current->ml_next) 16456f33205SJonathan Adams if (new->ml_address < current->ml_address) 165eaeab0c1SDana Myers break; 166eaeab0c1SDana Myers 167eaeab0c1SDana Myers if (prev == NULL) { 168eaeab0c1SDana Myers /* place at beginning of (possibly) empty list */ 16956f33205SJonathan Adams new->ml_next = ranges; 170eaeab0c1SDana Myers ranges = new; 171eaeab0c1SDana Myers } else { 172eaeab0c1SDana Myers /* place in list (possibly at end) */ 17356f33205SJonathan Adams new->ml_next = current; 17456f33205SJonathan Adams prev->ml_next = new; 175eaeab0c1SDana Myers } 176eaeab0c1SDana Myers } 177eaeab0c1SDana Myers 178eaeab0c1SDana Myers /* scan the list, perform trimming */ 179eaeab0c1SDana Myers current = ranges; 180eaeab0c1SDana Myers while (current != NULL) { 18156f33205SJonathan Adams struct memlist *next = current->ml_next; 182eaeab0c1SDana Myers 183eaeab0c1SDana Myers /* done when no range above current */ 184eaeab0c1SDana Myers if (next == NULL) 185eaeab0c1SDana Myers break; 186eaeab0c1SDana Myers 187eaeab0c1SDana Myers /* 188eaeab0c1SDana Myers * trim size in original range element 18956f33205SJonathan Adams * (current->ml_prev points to the original range) 190eaeab0c1SDana Myers */ 19156f33205SJonathan Adams if ((current->ml_address + current->ml_size) > next->ml_address) 19256f33205SJonathan Adams current->ml_prev->ml_size = 19356f33205SJonathan Adams next->ml_address - current->ml_address; 194eaeab0c1SDana Myers 195eaeab0c1SDana Myers current = next; 196eaeab0c1SDana Myers } 197eaeab0c1SDana Myers 198eaeab0c1SDana Myers /* discard the list */ 199eaeab0c1SDana Myers memlist_free_all(&ranges); /* OK if ranges == NULL */ 2008fc7923fSDana Myers } 2018fc7923fSDana Myers 2028fc7923fSDana Myers static int 2038fc7923fSDana Myers acpi_find_bus_res(int bus, int type, struct memlist **res) 2048fc7923fSDana Myers { 2058fc7923fSDana Myers 2068fc7923fSDana Myers switch (type) { 2078fc7923fSDana Myers case IO_TYPE: 2088fc7923fSDana Myers *res = acpi_io_res[bus]; 2098fc7923fSDana Myers break; 2108fc7923fSDana Myers case MEM_TYPE: 2118fc7923fSDana Myers *res = acpi_mem_res[bus]; 2128fc7923fSDana Myers break; 2138fc7923fSDana Myers case PREFETCH_TYPE: 2148fc7923fSDana Myers *res = acpi_pmem_res[bus]; 2158fc7923fSDana Myers break; 2168fc7923fSDana Myers case BUSRANGE_TYPE: 2178fc7923fSDana Myers *res = acpi_bus_res[bus]; 2188fc7923fSDana Myers break; 2198fc7923fSDana Myers default: 2208fc7923fSDana Myers *res = NULL; 2218fc7923fSDana Myers break; 2228fc7923fSDana Myers } 2238fc7923fSDana Myers 2248fc7923fSDana Myers /* memlist_count() treats NULL head as zero-length */ 2258fc7923fSDana Myers return (memlist_count(*res)); 2268fc7923fSDana Myers } 2278fc7923fSDana Myers 2288fc7923fSDana Myers void 2298fc7923fSDana Myers bus_res_fini(void) 2308fc7923fSDana Myers { 2318fc7923fSDana Myers int bus; 2328fc7923fSDana Myers 23347310cedSDana Myers for (bus = 0; bus <= pci_bios_maxbus; bus++) { 2348fc7923fSDana Myers memlist_free_all(&acpi_io_res[bus]); 2358fc7923fSDana Myers memlist_free_all(&acpi_mem_res[bus]); 2368fc7923fSDana Myers memlist_free_all(&acpi_pmem_res[bus]); 2378fc7923fSDana Myers memlist_free_all(&acpi_bus_res[bus]); 2388fc7923fSDana Myers } 2398fc7923fSDana Myers } 2408fc7923fSDana Myers 2418fc7923fSDana Myers 2428fc7923fSDana Myers struct memlist ** 2438fc7923fSDana Myers rlistpp(UINT8 t, UINT8 flags, int bus) 2448fc7923fSDana Myers { 2458fc7923fSDana Myers switch (t) { 2468fc7923fSDana Myers 2478fc7923fSDana Myers case ACPI_MEMORY_RANGE: 2488fc7923fSDana Myers /* is this really the best we've got? */ 2498fc7923fSDana Myers if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY) 2508fc7923fSDana Myers return (&acpi_pmem_res[bus]); 2518fc7923fSDana Myers else 2528fc7923fSDana Myers return (&acpi_mem_res[bus]); 2538fc7923fSDana Myers 2548fc7923fSDana Myers case ACPI_IO_RANGE: return &acpi_io_res[bus]; 2558fc7923fSDana Myers case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus]; 2568fc7923fSDana Myers } 2578fc7923fSDana Myers return ((struct memlist **)NULL); 2588fc7923fSDana Myers } 2598fc7923fSDana Myers 2608fc7923fSDana Myers 2618fc7923fSDana Myers ACPI_STATUS 2628fc7923fSDana Myers acpi_wr_cb(ACPI_RESOURCE *rp, void *context) 2638fc7923fSDana Myers { 2648fc7923fSDana Myers int bus = (intptr_t)context; 2658fc7923fSDana Myers 2668fc7923fSDana Myers /* ignore consumed resources */ 2678fc7923fSDana Myers if (rp->Data.Address.ProducerConsumer == 1) 2688fc7923fSDana Myers return (AE_OK); 2698fc7923fSDana Myers 2708fc7923fSDana Myers switch (rp->Type) { 2718fc7923fSDana Myers case ACPI_RESOURCE_TYPE_IRQ: 2728fc7923fSDana Myers /* never expect to see a PCI bus produce an Interrupt */ 2738fc7923fSDana Myers dprintf("%s\n", "IRQ"); 2748fc7923fSDana Myers break; 2758fc7923fSDana Myers 2768fc7923fSDana Myers case ACPI_RESOURCE_TYPE_DMA: 2778fc7923fSDana Myers /* never expect to see a PCI bus produce DMA */ 2788fc7923fSDana Myers dprintf("%s\n", "DMA"); 2798fc7923fSDana Myers break; 2808fc7923fSDana Myers 2818fc7923fSDana Myers case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2828fc7923fSDana Myers dprintf("%s\n", "START_DEPENDENT"); 2838fc7923fSDana Myers break; 2848fc7923fSDana Myers 2858fc7923fSDana Myers case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2868fc7923fSDana Myers dprintf("%s\n", "END_DEPENDENT"); 2878fc7923fSDana Myers break; 2888fc7923fSDana Myers 2898fc7923fSDana Myers case ACPI_RESOURCE_TYPE_IO: 2908fc7923fSDana Myers if (rp->Data.Io.AddressLength == 0) 2918fc7923fSDana Myers break; 2928fc7923fSDana Myers acpi_cb_cnt++; 2938fc7923fSDana Myers memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, 2948fc7923fSDana Myers rp->Data.Io.AddressLength); 2958fc7923fSDana Myers break; 2968fc7923fSDana Myers 2978fc7923fSDana Myers case ACPI_RESOURCE_TYPE_FIXED_IO: 2988fc7923fSDana Myers /* only expect to see this as a consumer */ 2998fc7923fSDana Myers dprintf("%s\n", "FIXED_IO"); 3008fc7923fSDana Myers break; 3018fc7923fSDana Myers 3028fc7923fSDana Myers case ACPI_RESOURCE_TYPE_VENDOR: 3038fc7923fSDana Myers dprintf("%s\n", "VENDOR"); 3048fc7923fSDana Myers break; 3058fc7923fSDana Myers 3068fc7923fSDana Myers case ACPI_RESOURCE_TYPE_END_TAG: 3078fc7923fSDana Myers dprintf("%s\n", "END_TAG"); 3088fc7923fSDana Myers break; 3098fc7923fSDana Myers 3108fc7923fSDana Myers case ACPI_RESOURCE_TYPE_MEMORY24: 3118fc7923fSDana Myers /* only expect to see this as a consumer */ 3128fc7923fSDana Myers dprintf("%s\n", "MEMORY24"); 3138fc7923fSDana Myers break; 3148fc7923fSDana Myers 3158fc7923fSDana Myers case ACPI_RESOURCE_TYPE_MEMORY32: 3168fc7923fSDana Myers /* only expect to see this as a consumer */ 3178fc7923fSDana Myers dprintf("%s\n", "MEMORY32"); 3188fc7923fSDana Myers break; 3198fc7923fSDana Myers 3208fc7923fSDana Myers case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 3218fc7923fSDana Myers /* only expect to see this as a consumer */ 3228fc7923fSDana Myers dprintf("%s\n", "FIXED_MEMORY32"); 3238fc7923fSDana Myers break; 3248fc7923fSDana Myers 3258fc7923fSDana Myers case ACPI_RESOURCE_TYPE_ADDRESS16: 326385cc6b4SJerry Jelinek if (rp->Data.Address16.Address.AddressLength == 0) 3278fc7923fSDana Myers break; 3288fc7923fSDana Myers acpi_cb_cnt++; 3298fc7923fSDana Myers memlist_insert(rlistpp(rp->Data.Address16.ResourceType, 3308fc7923fSDana Myers rp->Data.Address16.Info.TypeSpecific, bus), 331385cc6b4SJerry Jelinek rp->Data.Address16.Address.Minimum, 332385cc6b4SJerry Jelinek rp->Data.Address16.Address.AddressLength); 3338fc7923fSDana Myers break; 3348fc7923fSDana Myers 3358fc7923fSDana Myers case ACPI_RESOURCE_TYPE_ADDRESS32: 336385cc6b4SJerry Jelinek if (rp->Data.Address32.Address.AddressLength == 0) 3378fc7923fSDana Myers break; 3388fc7923fSDana Myers acpi_cb_cnt++; 3398fc7923fSDana Myers memlist_insert(rlistpp(rp->Data.Address32.ResourceType, 3408fc7923fSDana Myers rp->Data.Address32.Info.TypeSpecific, bus), 341385cc6b4SJerry Jelinek rp->Data.Address32.Address.Minimum, 342385cc6b4SJerry Jelinek rp->Data.Address32.Address.AddressLength); 3438fc7923fSDana Myers break; 3448fc7923fSDana Myers 3458fc7923fSDana Myers case ACPI_RESOURCE_TYPE_ADDRESS64: 3468d947747SGuoli Shu /* 3478d947747SGuoli Shu * We comment out this block because we currently cannot deal with 3488d947747SGuoli Shu * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO 3498d947747SGuoli Shu * support. 3508d947747SGuoli Shu */ 3518d947747SGuoli Shu #if 0 3528fc7923fSDana Myers if (rp->Data.Address64.AddressLength == 0) 3538fc7923fSDana Myers break; 3548fc7923fSDana Myers acpi_cb_cnt++; 3558fc7923fSDana Myers memlist_insert(rlistpp(rp->Data.Address64.ResourceType, 3568fc7923fSDana Myers rp->Data.Address64.Info.TypeSpecific, bus), 3578fc7923fSDana Myers rp->Data.Address64.Minimum, 3588fc7923fSDana Myers rp->Data.Address64.AddressLength); 3598d947747SGuoli Shu #endif 3608fc7923fSDana Myers break; 3618fc7923fSDana Myers 3628fc7923fSDana Myers case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 3638d947747SGuoli Shu #if 0 /* Will revisit this when we add PCI 64-bit MMIO support */ 3648fc7923fSDana Myers if (rp->Data.ExtAddress64.AddressLength == 0) 3658fc7923fSDana Myers break; 3668fc7923fSDana Myers acpi_cb_cnt++; 3678fc7923fSDana Myers memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType, 3688fc7923fSDana Myers rp->Data.ExtAddress64.Info.TypeSpecific, bus), 3698fc7923fSDana Myers rp->Data.ExtAddress64.Minimum, 3708fc7923fSDana Myers rp->Data.ExtAddress64.AddressLength); 3718d947747SGuoli Shu #endif 3728fc7923fSDana Myers break; 3738fc7923fSDana Myers 3748fc7923fSDana Myers case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 3758fc7923fSDana Myers /* never expect to see a PCI bus produce an Interrupt */ 3768fc7923fSDana Myers dprintf("%s\n", "EXTENDED_IRQ"); 3778fc7923fSDana Myers break; 3788fc7923fSDana Myers 3798fc7923fSDana Myers case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 3808fc7923fSDana Myers /* never expect to see a PCI bus produce an GAS */ 3818fc7923fSDana Myers dprintf("%s\n", "GENERIC_REGISTER"); 3828fc7923fSDana Myers break; 3838fc7923fSDana Myers } 3848fc7923fSDana Myers 3858fc7923fSDana Myers return (AE_OK); 3868fc7923fSDana Myers } 3878fc7923fSDana Myers 388ae115bc7Smrj static void 389ae115bc7Smrj mps_probe() 390ae115bc7Smrj { 391ae115bc7Smrj uchar_t *extp; 392ae115bc7Smrj struct mps_fps_hdr *fpp = NULL; 393ae115bc7Smrj struct mps_ct_hdr *ctp; 394ae115bc7Smrj uintptr_t ebda_start, base_end; 395ae115bc7Smrj ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg; 396ae115bc7Smrj 397ae115bc7Smrj base_size = *((ushort_t *)(0x413)); 398ae115bc7Smrj ebda_seg = *((ushort_t *)(0x40e)); 399ae115bc7Smrj ebda_start = ((uint32_t)ebda_seg) << 4; 400ae115bc7Smrj if (ebda_seg != 0) { 401ae115bc7Smrj fpp = (struct mps_fps_hdr *)find_sig( 402ae115bc7Smrj (uchar_t *)ebda_start, 1024, "_MP_"); 403ae115bc7Smrj } 404ae115bc7Smrj if (fpp == NULL) { 405ae115bc7Smrj base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0; 406ae115bc7Smrj if (base_end_seg != ebda_seg) { 407ae115bc7Smrj base_end = ((uintptr_t)base_end_seg) << 4; 408ae115bc7Smrj fpp = (struct mps_fps_hdr *)find_sig( 409ae115bc7Smrj (uchar_t *)base_end, 1024, "_MP_"); 410ae115bc7Smrj } 411ae115bc7Smrj } 412ae115bc7Smrj if (fpp == NULL) { 413ae115bc7Smrj fpp = (struct mps_fps_hdr *)find_sig( 414ae115bc7Smrj (uchar_t *)0xF0000, 0x10000, "_MP_"); 415ae115bc7Smrj } 416ae115bc7Smrj 417ae115bc7Smrj if (fpp == NULL) { 418ae115bc7Smrj dprintf("MP Spec table doesn't exist"); 419ae115bc7Smrj return; 420ae115bc7Smrj } else { 421ae115bc7Smrj dprintf("Found MP Floating Pointer Structure at %p\n", 422ae115bc7Smrj (void *)fpp); 423ae115bc7Smrj } 424ae115bc7Smrj 425ae115bc7Smrj if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) { 426ae115bc7Smrj dprintf("MP Floating Pointer Structure checksum error"); 427ae115bc7Smrj return; 428ae115bc7Smrj } 429ae115bc7Smrj 430ae115bc7Smrj ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr; 431ae115bc7Smrj if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */ 432ae115bc7Smrj dprintf("MP Configuration Table signature is wrong"); 433ae115bc7Smrj return; 434ae115bc7Smrj } 435ae115bc7Smrj 436ae115bc7Smrj base_len = ctp->ct_len; 437ae115bc7Smrj if (checksum((uchar_t *)ctp, base_len) != 0) { 438ae115bc7Smrj dprintf("MP Configuration Table checksum error"); 439ae115bc7Smrj return; 440ae115bc7Smrj } 441ae115bc7Smrj if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */ 442ae115bc7Smrj dprintf("MP Spec 1.1 found - extended table doesn't exist"); 443ae115bc7Smrj return; 444ae115bc7Smrj } 445ae115bc7Smrj if ((ext_len = ctp->ct_ext_tbl_len) == 0) { 446ae115bc7Smrj dprintf("MP Spec 1.4 found - extended table doesn't exist"); 447ae115bc7Smrj return; 448ae115bc7Smrj } 449ae115bc7Smrj extp = (uchar_t *)ctp + base_len; 450ae115bc7Smrj if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) { 451ae115bc7Smrj dprintf("MP Extended Table checksum error"); 452ae115bc7Smrj return; 453ae115bc7Smrj } 454ae115bc7Smrj mps_extp = extp; 455ae115bc7Smrj mps_ext_endp = mps_extp + ext_len; 456ae115bc7Smrj } 457ae115bc7Smrj 458ae115bc7Smrj 459ae115bc7Smrj static int 460ae115bc7Smrj mps_find_bus_res(int bus, int type, struct memlist **res) 461ae115bc7Smrj { 462ae115bc7Smrj struct sasm *sasmp; 463ae115bc7Smrj uchar_t *extp; 464ae115bc7Smrj int res_cnt; 465ae115bc7Smrj 466ae115bc7Smrj if (mps_extp == NULL) 467ae115bc7Smrj return (0); 468ae115bc7Smrj extp = mps_extp; 469ae115bc7Smrj res_cnt = 0; 470ae115bc7Smrj while (extp < mps_ext_endp) { 471ae115bc7Smrj switch (*extp) { 472ae115bc7Smrj case SYS_AS_MAPPING: 473ae115bc7Smrj sasmp = (struct sasm *)extp; 474ae115bc7Smrj if (((int)sasmp->sasm_as_type) == type && 475ae115bc7Smrj ((int)sasmp->sasm_bus_id) == bus) { 476*abe68f2cSRobert Mustacchi uint64_t base, len; 477*abe68f2cSRobert Mustacchi 478*abe68f2cSRobert Mustacchi base = (uint64_t)sasmp->sasm_as_base | 479*abe68f2cSRobert Mustacchi (uint64_t)sasmp->sasm_as_base_hi << 32; 480*abe68f2cSRobert Mustacchi len = (uint64_t)sasmp->sasm_as_len | 481*abe68f2cSRobert Mustacchi (uint64_t)sasmp->sasm_as_len_hi << 32; 482*abe68f2cSRobert Mustacchi memlist_insert(res, base, len); 483ae115bc7Smrj res_cnt++; 484ae115bc7Smrj } 485ae115bc7Smrj extp += SYS_AS_MAPPING_SIZE; 486ae115bc7Smrj break; 487ae115bc7Smrj case BUS_HIERARCHY_DESC: 488ae115bc7Smrj extp += BUS_HIERARCHY_DESC_SIZE; 489ae115bc7Smrj break; 490ae115bc7Smrj case COMP_BUS_AS_MODIFIER: 491ae115bc7Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 492ae115bc7Smrj break; 493ae115bc7Smrj default: 494ae115bc7Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 495ae115bc7Smrj " in BIOS Multiprocessor Spec table.", 496ae115bc7Smrj *extp); 497ae115bc7Smrj while (*res) { 498ae115bc7Smrj struct memlist *tmp = *res; 49956f33205SJonathan Adams *res = tmp->ml_next; 500ae115bc7Smrj memlist_free(tmp); 501ae115bc7Smrj } 502ae115bc7Smrj return (0); 503ae115bc7Smrj } 504ae115bc7Smrj } 505ae115bc7Smrj return (res_cnt); 506ae115bc7Smrj } 507ae115bc7Smrj 508ae115bc7Smrj static void 509ae115bc7Smrj hrt_probe() 510ae115bc7Smrj { 511ae115bc7Smrj struct hrt_hdr *hrtp; 512ae115bc7Smrj 513ae115bc7Smrj dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 514ae115bc7Smrj if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 515ae115bc7Smrj 0x10000, "$HRT")) == NULL) { 516ae115bc7Smrj dprintf("NO PCI Hot-Plug Resource Table"); 517ae115bc7Smrj return; 518ae115bc7Smrj } 519ae115bc7Smrj dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 520ae115bc7Smrj if (hrtp->hrt_ver != 1) { 521ae115bc7Smrj dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 522ae115bc7Smrj return; 523ae115bc7Smrj } 524ae115bc7Smrj hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; 525ae115bc7Smrj dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 526ae115bc7Smrj hrt_hpep = (struct php_entry *)(hrtp + 1); 527ae115bc7Smrj } 528ae115bc7Smrj 529ae115bc7Smrj static int 530ae115bc7Smrj hrt_find_bus_res(int bus, int type, struct memlist **res) 531ae115bc7Smrj { 532ae115bc7Smrj int res_cnt, i; 533ae115bc7Smrj struct php_entry *hpep; 534ae115bc7Smrj 535ae115bc7Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) 536ae115bc7Smrj return (0); 537ae115bc7Smrj hpep = hrt_hpep; 538ae115bc7Smrj res_cnt = 0; 539ae115bc7Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 540ae115bc7Smrj if (hpep->php_pri_bus != bus) 541ae115bc7Smrj continue; 542ae115bc7Smrj if (type == IO_TYPE) { 543ae115bc7Smrj if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 544ae115bc7Smrj continue; 545ae115bc7Smrj memlist_insert(res, (uint64_t)hpep->php_io_start, 546ae115bc7Smrj (uint64_t)hpep->php_io_size); 547ae115bc7Smrj res_cnt++; 548ae115bc7Smrj } else if (type == MEM_TYPE) { 549ae115bc7Smrj if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 550ae115bc7Smrj continue; 551ae115bc7Smrj memlist_insert(res, 552ae115bc7Smrj (uint64_t)(((int)hpep->php_mem_start) << 16), 553ae115bc7Smrj (uint64_t)(((int)hpep->php_mem_size) << 16)); 554ae115bc7Smrj res_cnt++; 555ae115bc7Smrj } else if (type == PREFETCH_TYPE) { 556ae115bc7Smrj if (hpep->php_pfmem_start == 0 || 557ae115bc7Smrj hpep->php_pfmem_size == 0) 558ae115bc7Smrj continue; 559ae115bc7Smrj memlist_insert(res, 560ae115bc7Smrj (uint64_t)(((int)hpep->php_pfmem_start) << 16), 561ae115bc7Smrj (uint64_t)(((int)hpep->php_pfmem_size) << 16)); 562ae115bc7Smrj res_cnt++; 563ae115bc7Smrj } 564ae115bc7Smrj } 565ae115bc7Smrj return (res_cnt); 566ae115bc7Smrj } 567ae115bc7Smrj 568ae115bc7Smrj static uchar_t * 569ae115bc7Smrj find_sig(uchar_t *cp, int len, char *sig) 570ae115bc7Smrj { 571ae115bc7Smrj long i; 572ae115bc7Smrj 573ae115bc7Smrj /* Search for the "_MP_" or "$HRT" signature */ 574ae115bc7Smrj for (i = 0; i < len; i += 16) { 575ae115bc7Smrj if (cp[0] == sig[0] && cp[1] == sig[1] && 576ae115bc7Smrj cp[2] == sig[2] && cp[3] == sig[3]) 577ae115bc7Smrj return (cp); 578ae115bc7Smrj cp += 16; 579ae115bc7Smrj } 580ae115bc7Smrj return (NULL); 581ae115bc7Smrj } 582ae115bc7Smrj 583ae115bc7Smrj static int 584ae115bc7Smrj checksum(unsigned char *cp, int len) 585ae115bc7Smrj { 586ae115bc7Smrj int i; 587ae115bc7Smrj unsigned int cksum; 588ae115bc7Smrj 589ae115bc7Smrj for (i = cksum = 0; i < len; i++) 590ae115bc7Smrj cksum += (unsigned int) *cp++; 591ae115bc7Smrj 592ae115bc7Smrj return ((int)(cksum & 0xFF)); 593ae115bc7Smrj } 594ae115bc7Smrj 595ae115bc7Smrj #ifdef UNUSED_BUS_HIERARY_INFO 596ae115bc7Smrj 597ae115bc7Smrj /* 598ae115bc7Smrj * At this point, the bus hierarchy entries do not appear to 599ae115bc7Smrj * provide anything we can't find out from PCI config space. 600ae115bc7Smrj * The only interesting bit is the ISA bus number, which we 601ae115bc7Smrj * don't care. 602ae115bc7Smrj */ 603ae115bc7Smrj int 604ae115bc7Smrj mps_find_parent_bus(int bus) 605ae115bc7Smrj { 606ae115bc7Smrj struct sasm *sasmp; 607ae115bc7Smrj uchar_t *extp; 608ae115bc7Smrj 609ae115bc7Smrj if (mps_extp == NULL) 610ae115bc7Smrj return (-1); 611ae115bc7Smrj 612ae115bc7Smrj extp = mps_extp; 613ae115bc7Smrj while (extp < mps_ext_endp) { 614ae115bc7Smrj bhdp = (struct bhd *)extp; 615ae115bc7Smrj switch (*extp) { 616ae115bc7Smrj case SYS_AS_MAPPING: 617ae115bc7Smrj extp += SYS_AS_MAPPING_SIZE; 618ae115bc7Smrj break; 619ae115bc7Smrj case BUS_HIERARCHY_DESC: 620ae115bc7Smrj if (bhdp->bhd_bus_id == bus) 621ae115bc7Smrj return (bhdp->bhd_parent); 622ae115bc7Smrj extp += BUS_HIERARCHY_DESC_SIZE; 623ae115bc7Smrj break; 624ae115bc7Smrj case COMP_BUS_AS_MODIFIER: 625ae115bc7Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 626ae115bc7Smrj break; 627ae115bc7Smrj default: 628ae115bc7Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 629ae115bc7Smrj " in BIOS Multiprocessor Spec table.", 630ae115bc7Smrj *extp); 631ae115bc7Smrj return (-1); 632ae115bc7Smrj } 633ae115bc7Smrj } 634ae115bc7Smrj return (-1); 635ae115bc7Smrj } 636ae115bc7Smrj 637ae115bc7Smrj int 638ae115bc7Smrj hrt_find_bus_range(int bus) 639ae115bc7Smrj { 640ae115bc7Smrj int i, max_bus, sub_bus; 641ae115bc7Smrj struct php_entry *hpep; 642ae115bc7Smrj 643ae115bc7Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) { 644ae115bc7Smrj return (-1); 645ae115bc7Smrj } 646ae115bc7Smrj hpep = hrt_hpep; 647ae115bc7Smrj max_bus = -1; 648ae115bc7Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 649ae115bc7Smrj if (hpep->php_pri_bus != bus) 650ae115bc7Smrj continue; 651ae115bc7Smrj sub_bus = (int)hpep->php_subord_bus; 652ae115bc7Smrj if (sub_bus > max_bus) 653ae115bc7Smrj max_bus = sub_bus; 654ae115bc7Smrj } 655ae115bc7Smrj return (max_bus); 656ae115bc7Smrj } 657ae115bc7Smrj 658ae115bc7Smrj #endif /* UNUSED_BUS_HIERARY_INFO */ 659