13446Smrj /* 23446Smrj * CDDL HEADER START 33446Smrj * 43446Smrj * The contents of this file are subject to the terms of the 58420SDana.Myers@Sun.COM * Common Development and Distribution License (the "License"). 68420SDana.Myers@Sun.COM * You may not use this file except in compliance with the License. 73446Smrj * 83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93446Smrj * or http://www.opensolaris.org/os/licensing. 103446Smrj * See the License for the specific language governing permissions 113446Smrj * and limitations under the License. 123446Smrj * 133446Smrj * When distributing Covered Code, include this CDDL HEADER in each 143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153446Smrj * If applicable, add the following below this CDDL HEADER, with the 163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 183446Smrj * 193446Smrj * CDDL HEADER END 203446Smrj */ 213446Smrj /* 22*9428SDana.Myers@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233446Smrj * Use is subject to license terms. 243446Smrj * 253446Smrj * pci_resource.c -- routines to retrieve available bus resources from 263446Smrj * the MP Spec. Table and Hotplug Resource Table 273446Smrj */ 283446Smrj 293446Smrj #include <sys/types.h> 303446Smrj #include <sys/memlist.h> 313446Smrj #include <sys/pci_impl.h> 323446Smrj #include <sys/systm.h> 333446Smrj #include <sys/cmn_err.h> 348420SDana.Myers@Sun.COM #include <sys/acpi/acpi.h> 358420SDana.Myers@Sun.COM #include <sys/acpica.h> 363446Smrj #include "mps_table.h" 373446Smrj #include "pcihrt.h" 383446Smrj 393446Smrj extern int pci_boot_debug; 408420SDana.Myers@Sun.COM extern int pci_bios_nbus; 413446Smrj #define dprintf if (pci_boot_debug) printf 423446Smrj 433446Smrj static int tbl_init = 0; 443446Smrj static uchar_t *mps_extp = NULL; 453446Smrj static uchar_t *mps_ext_endp = NULL; 463446Smrj static struct php_entry *hrt_hpep; 473446Smrj static int hrt_entry_cnt = 0; 488420SDana.Myers@Sun.COM static int acpi_cb_cnt = 0; 493446Smrj 503446Smrj static void mps_probe(void); 518420SDana.Myers@Sun.COM static void acpi_pci_probe(void); 523446Smrj static int mps_find_bus_res(int, int, struct memlist **); 533446Smrj static void hrt_probe(void); 543446Smrj static int hrt_find_bus_res(int, int, struct memlist **); 558420SDana.Myers@Sun.COM static int acpi_find_bus_res(int, int, struct memlist **); 563446Smrj static uchar_t *find_sig(uchar_t *cp, int len, char *sig); 573446Smrj static int checksum(unsigned char *cp, int len); 588420SDana.Myers@Sun.COM static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context); 598420SDana.Myers@Sun.COM void bus_res_fini(void); 60*9428SDana.Myers@Sun.COM static void acpi_trim_bus_ranges(void); 618420SDana.Myers@Sun.COM 628420SDana.Myers@Sun.COM struct memlist *acpi_io_res[256]; 638420SDana.Myers@Sun.COM struct memlist *acpi_mem_res[256]; 648420SDana.Myers@Sun.COM struct memlist *acpi_pmem_res[256]; 658420SDana.Myers@Sun.COM struct memlist *acpi_bus_res[256]; 668420SDana.Myers@Sun.COM 678420SDana.Myers@Sun.COM /* 688420SDana.Myers@Sun.COM * -1 = attempt ACPI resource discovery 698420SDana.Myers@Sun.COM * 0 = don't attempt ACPI resource discovery 708420SDana.Myers@Sun.COM * 1 = ACPI resource discovery successful 718420SDana.Myers@Sun.COM */ 728420SDana.Myers@Sun.COM volatile int acpi_resource_discovery = -1; 733446Smrj 743446Smrj struct memlist * 753446Smrj find_bus_res(int bus, int type) 763446Smrj { 773446Smrj struct memlist *res = NULL; 783446Smrj 793446Smrj if (tbl_init == 0) { 803446Smrj tbl_init = 1; 818420SDana.Myers@Sun.COM acpi_pci_probe(); 823446Smrj hrt_probe(); 833446Smrj mps_probe(); 843446Smrj } 853446Smrj 868420SDana.Myers@Sun.COM if (acpi_find_bus_res(bus, type, &res) > 0) 878420SDana.Myers@Sun.COM return (res); 888420SDana.Myers@Sun.COM 893446Smrj if (hrt_find_bus_res(bus, type, &res) > 0) 903446Smrj return (res); 913446Smrj 923446Smrj (void) mps_find_bus_res(bus, type, &res); 933446Smrj return (res); 943446Smrj } 953446Smrj 968420SDana.Myers@Sun.COM 978420SDana.Myers@Sun.COM static void 988420SDana.Myers@Sun.COM acpi_pci_probe(void) 998420SDana.Myers@Sun.COM { 1008420SDana.Myers@Sun.COM ACPI_HANDLE ah; 1018420SDana.Myers@Sun.COM dev_info_t *dip; 1028420SDana.Myers@Sun.COM int bus; 1038420SDana.Myers@Sun.COM 1048420SDana.Myers@Sun.COM if (acpi_resource_discovery == 0) 1058420SDana.Myers@Sun.COM return; 1068420SDana.Myers@Sun.COM 1078420SDana.Myers@Sun.COM for (bus = 0; bus < pci_bios_nbus; bus++) { 1088420SDana.Myers@Sun.COM /* if no dip or no ACPI handle, no resources to discover */ 1098420SDana.Myers@Sun.COM dip = pci_bus_res[bus].dip; 1108420SDana.Myers@Sun.COM if ((dip == NULL) || 1118420SDana.Myers@Sun.COM (ACPI_FAILURE(acpica_get_handle(dip, &ah)))) 1128420SDana.Myers@Sun.COM continue; 1138420SDana.Myers@Sun.COM 1148420SDana.Myers@Sun.COM (void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb, 1158420SDana.Myers@Sun.COM (void *)(uintptr_t)bus); 1168420SDana.Myers@Sun.COM } 1178420SDana.Myers@Sun.COM 118*9428SDana.Myers@Sun.COM if (acpi_cb_cnt > 0) { 1198420SDana.Myers@Sun.COM acpi_resource_discovery = 1; 120*9428SDana.Myers@Sun.COM acpi_trim_bus_ranges(); 121*9428SDana.Myers@Sun.COM } 122*9428SDana.Myers@Sun.COM } 123*9428SDana.Myers@Sun.COM 124*9428SDana.Myers@Sun.COM /* 125*9428SDana.Myers@Sun.COM * Trim overlapping bus ranges in acpi_bus_res[] 126*9428SDana.Myers@Sun.COM * Some BIOSes report root-bridges with bus ranges that 127*9428SDana.Myers@Sun.COM * overlap, for example:"0..255" and "8..255". Lower-numbered 128*9428SDana.Myers@Sun.COM * ranges are trimmed by upper-numbered ranges (so "0..255" would 129*9428SDana.Myers@Sun.COM * be trimmed to "0..7", in the example). 130*9428SDana.Myers@Sun.COM */ 131*9428SDana.Myers@Sun.COM static void 132*9428SDana.Myers@Sun.COM acpi_trim_bus_ranges() 133*9428SDana.Myers@Sun.COM { 134*9428SDana.Myers@Sun.COM struct memlist *ranges, *current; 135*9428SDana.Myers@Sun.COM int bus; 136*9428SDana.Myers@Sun.COM 137*9428SDana.Myers@Sun.COM ranges = NULL; 138*9428SDana.Myers@Sun.COM 139*9428SDana.Myers@Sun.COM /* 140*9428SDana.Myers@Sun.COM * Assumptions: 141*9428SDana.Myers@Sun.COM * - there exists at most 1 bus range entry for each bus number 142*9428SDana.Myers@Sun.COM * - there are no (broken) ranges that start at the same bus number 143*9428SDana.Myers@Sun.COM */ 144*9428SDana.Myers@Sun.COM for (bus = 0; bus < 256; bus++) { 145*9428SDana.Myers@Sun.COM struct memlist *prev, *orig, *new; 146*9428SDana.Myers@Sun.COM /* skip buses with no range entry */ 147*9428SDana.Myers@Sun.COM if ((orig = acpi_bus_res[bus]) == NULL) 148*9428SDana.Myers@Sun.COM continue; 149*9428SDana.Myers@Sun.COM 150*9428SDana.Myers@Sun.COM /* 151*9428SDana.Myers@Sun.COM * create copy of existing range and overload 152*9428SDana.Myers@Sun.COM * 'prev' pointer to link existing to new copy 153*9428SDana.Myers@Sun.COM */ 154*9428SDana.Myers@Sun.COM new = memlist_alloc(); 155*9428SDana.Myers@Sun.COM new->address = orig->address; 156*9428SDana.Myers@Sun.COM new->size = orig->size; 157*9428SDana.Myers@Sun.COM new->prev = orig; 158*9428SDana.Myers@Sun.COM 159*9428SDana.Myers@Sun.COM /* sorted insertion of 'new' into ranges list */ 160*9428SDana.Myers@Sun.COM for (current = ranges, prev = NULL; current != NULL; 161*9428SDana.Myers@Sun.COM prev = current, current = current->next) 162*9428SDana.Myers@Sun.COM if (new->address < current->address) 163*9428SDana.Myers@Sun.COM break; 164*9428SDana.Myers@Sun.COM 165*9428SDana.Myers@Sun.COM if (prev == NULL) { 166*9428SDana.Myers@Sun.COM /* place at beginning of (possibly) empty list */ 167*9428SDana.Myers@Sun.COM new->next = ranges; 168*9428SDana.Myers@Sun.COM ranges = new; 169*9428SDana.Myers@Sun.COM } else { 170*9428SDana.Myers@Sun.COM /* place in list (possibly at end) */ 171*9428SDana.Myers@Sun.COM new->next = current; 172*9428SDana.Myers@Sun.COM prev->next = new; 173*9428SDana.Myers@Sun.COM } 174*9428SDana.Myers@Sun.COM } 175*9428SDana.Myers@Sun.COM 176*9428SDana.Myers@Sun.COM /* scan the list, perform trimming */ 177*9428SDana.Myers@Sun.COM current = ranges; 178*9428SDana.Myers@Sun.COM while (current != NULL) { 179*9428SDana.Myers@Sun.COM struct memlist *next = current->next; 180*9428SDana.Myers@Sun.COM 181*9428SDana.Myers@Sun.COM /* done when no range above current */ 182*9428SDana.Myers@Sun.COM if (next == NULL) 183*9428SDana.Myers@Sun.COM break; 184*9428SDana.Myers@Sun.COM 185*9428SDana.Myers@Sun.COM /* 186*9428SDana.Myers@Sun.COM * trim size in original range element 187*9428SDana.Myers@Sun.COM * (current->prev points to the original range) 188*9428SDana.Myers@Sun.COM */ 189*9428SDana.Myers@Sun.COM if ((current->address + current->size) > next->address) 190*9428SDana.Myers@Sun.COM current->prev->size = next->address - current->address; 191*9428SDana.Myers@Sun.COM 192*9428SDana.Myers@Sun.COM current = next; 193*9428SDana.Myers@Sun.COM } 194*9428SDana.Myers@Sun.COM 195*9428SDana.Myers@Sun.COM /* discard the list */ 196*9428SDana.Myers@Sun.COM memlist_free_all(&ranges); /* OK if ranges == NULL */ 1978420SDana.Myers@Sun.COM } 1988420SDana.Myers@Sun.COM 1998420SDana.Myers@Sun.COM static int 2008420SDana.Myers@Sun.COM acpi_find_bus_res(int bus, int type, struct memlist **res) 2018420SDana.Myers@Sun.COM { 2028420SDana.Myers@Sun.COM 2038420SDana.Myers@Sun.COM switch (type) { 2048420SDana.Myers@Sun.COM case IO_TYPE: 2058420SDana.Myers@Sun.COM *res = acpi_io_res[bus]; 2068420SDana.Myers@Sun.COM break; 2078420SDana.Myers@Sun.COM case MEM_TYPE: 2088420SDana.Myers@Sun.COM *res = acpi_mem_res[bus]; 2098420SDana.Myers@Sun.COM break; 2108420SDana.Myers@Sun.COM case PREFETCH_TYPE: 2118420SDana.Myers@Sun.COM *res = acpi_pmem_res[bus]; 2128420SDana.Myers@Sun.COM break; 2138420SDana.Myers@Sun.COM case BUSRANGE_TYPE: 2148420SDana.Myers@Sun.COM *res = acpi_bus_res[bus]; 2158420SDana.Myers@Sun.COM break; 2168420SDana.Myers@Sun.COM default: 2178420SDana.Myers@Sun.COM *res = NULL; 2188420SDana.Myers@Sun.COM break; 2198420SDana.Myers@Sun.COM } 2208420SDana.Myers@Sun.COM 2218420SDana.Myers@Sun.COM /* memlist_count() treats NULL head as zero-length */ 2228420SDana.Myers@Sun.COM return (memlist_count(*res)); 2238420SDana.Myers@Sun.COM } 2248420SDana.Myers@Sun.COM 2258420SDana.Myers@Sun.COM void 2268420SDana.Myers@Sun.COM bus_res_fini(void) 2278420SDana.Myers@Sun.COM { 2288420SDana.Myers@Sun.COM int bus; 2298420SDana.Myers@Sun.COM 2308420SDana.Myers@Sun.COM for (bus = 0; bus < pci_bios_nbus; bus++) { 2318420SDana.Myers@Sun.COM memlist_free_all(&acpi_io_res[bus]); 2328420SDana.Myers@Sun.COM memlist_free_all(&acpi_mem_res[bus]); 2338420SDana.Myers@Sun.COM memlist_free_all(&acpi_pmem_res[bus]); 2348420SDana.Myers@Sun.COM memlist_free_all(&acpi_bus_res[bus]); 2358420SDana.Myers@Sun.COM } 2368420SDana.Myers@Sun.COM } 2378420SDana.Myers@Sun.COM 2388420SDana.Myers@Sun.COM 2398420SDana.Myers@Sun.COM struct memlist ** 2408420SDana.Myers@Sun.COM rlistpp(UINT8 t, UINT8 flags, int bus) 2418420SDana.Myers@Sun.COM { 2428420SDana.Myers@Sun.COM switch (t) { 2438420SDana.Myers@Sun.COM 2448420SDana.Myers@Sun.COM case ACPI_MEMORY_RANGE: 2458420SDana.Myers@Sun.COM /* is this really the best we've got? */ 2468420SDana.Myers@Sun.COM if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY) 2478420SDana.Myers@Sun.COM return (&acpi_pmem_res[bus]); 2488420SDana.Myers@Sun.COM else 2498420SDana.Myers@Sun.COM return (&acpi_mem_res[bus]); 2508420SDana.Myers@Sun.COM 2518420SDana.Myers@Sun.COM case ACPI_IO_RANGE: return &acpi_io_res[bus]; 2528420SDana.Myers@Sun.COM case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus]; 2538420SDana.Myers@Sun.COM } 2548420SDana.Myers@Sun.COM return ((struct memlist **)NULL); 2558420SDana.Myers@Sun.COM } 2568420SDana.Myers@Sun.COM 2578420SDana.Myers@Sun.COM 2588420SDana.Myers@Sun.COM ACPI_STATUS 2598420SDana.Myers@Sun.COM acpi_wr_cb(ACPI_RESOURCE *rp, void *context) 2608420SDana.Myers@Sun.COM { 2618420SDana.Myers@Sun.COM int bus = (intptr_t)context; 2628420SDana.Myers@Sun.COM 2638420SDana.Myers@Sun.COM /* ignore consumed resources */ 2648420SDana.Myers@Sun.COM if (rp->Data.Address.ProducerConsumer == 1) 2658420SDana.Myers@Sun.COM return (AE_OK); 2668420SDana.Myers@Sun.COM 2678420SDana.Myers@Sun.COM switch (rp->Type) { 2688420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_IRQ: 2698420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an Interrupt */ 2708420SDana.Myers@Sun.COM dprintf("%s\n", "IRQ"); 2718420SDana.Myers@Sun.COM break; 2728420SDana.Myers@Sun.COM 2738420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_DMA: 2748420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce DMA */ 2758420SDana.Myers@Sun.COM dprintf("%s\n", "DMA"); 2768420SDana.Myers@Sun.COM break; 2778420SDana.Myers@Sun.COM 2788420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2798420SDana.Myers@Sun.COM dprintf("%s\n", "START_DEPENDENT"); 2808420SDana.Myers@Sun.COM break; 2818420SDana.Myers@Sun.COM 2828420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2838420SDana.Myers@Sun.COM dprintf("%s\n", "END_DEPENDENT"); 2848420SDana.Myers@Sun.COM break; 2858420SDana.Myers@Sun.COM 2868420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_IO: 2878420SDana.Myers@Sun.COM if (rp->Data.Io.AddressLength == 0) 2888420SDana.Myers@Sun.COM break; 2898420SDana.Myers@Sun.COM acpi_cb_cnt++; 2908420SDana.Myers@Sun.COM memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, 2918420SDana.Myers@Sun.COM rp->Data.Io.AddressLength); 2928420SDana.Myers@Sun.COM break; 2938420SDana.Myers@Sun.COM 2948420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_FIXED_IO: 2958420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 2968420SDana.Myers@Sun.COM dprintf("%s\n", "FIXED_IO"); 2978420SDana.Myers@Sun.COM break; 2988420SDana.Myers@Sun.COM 2998420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_VENDOR: 3008420SDana.Myers@Sun.COM dprintf("%s\n", "VENDOR"); 3018420SDana.Myers@Sun.COM break; 3028420SDana.Myers@Sun.COM 3038420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_END_TAG: 3048420SDana.Myers@Sun.COM dprintf("%s\n", "END_TAG"); 3058420SDana.Myers@Sun.COM break; 3068420SDana.Myers@Sun.COM 3078420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_MEMORY24: 3088420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3098420SDana.Myers@Sun.COM dprintf("%s\n", "MEMORY24"); 3108420SDana.Myers@Sun.COM break; 3118420SDana.Myers@Sun.COM 3128420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_MEMORY32: 3138420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3148420SDana.Myers@Sun.COM dprintf("%s\n", "MEMORY32"); 3158420SDana.Myers@Sun.COM break; 3168420SDana.Myers@Sun.COM 3178420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 3188420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3198420SDana.Myers@Sun.COM dprintf("%s\n", "FIXED_MEMORY32"); 3208420SDana.Myers@Sun.COM break; 3218420SDana.Myers@Sun.COM 3228420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS16: 3238420SDana.Myers@Sun.COM if (rp->Data.Address16.AddressLength == 0) 3248420SDana.Myers@Sun.COM break; 3258420SDana.Myers@Sun.COM acpi_cb_cnt++; 3268420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address16.ResourceType, 3278420SDana.Myers@Sun.COM rp->Data.Address16.Info.TypeSpecific, bus), 3288420SDana.Myers@Sun.COM rp->Data.Address16.Minimum, 3298420SDana.Myers@Sun.COM rp->Data.Address16.AddressLength); 3308420SDana.Myers@Sun.COM break; 3318420SDana.Myers@Sun.COM 3328420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS32: 3338420SDana.Myers@Sun.COM if (rp->Data.Address32.AddressLength == 0) 3348420SDana.Myers@Sun.COM break; 3358420SDana.Myers@Sun.COM acpi_cb_cnt++; 3368420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address32.ResourceType, 3378420SDana.Myers@Sun.COM rp->Data.Address32.Info.TypeSpecific, bus), 3388420SDana.Myers@Sun.COM rp->Data.Address32.Minimum, 3398420SDana.Myers@Sun.COM rp->Data.Address32.AddressLength); 3408420SDana.Myers@Sun.COM break; 3418420SDana.Myers@Sun.COM 3428420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS64: 3438420SDana.Myers@Sun.COM if (rp->Data.Address64.AddressLength == 0) 3448420SDana.Myers@Sun.COM break; 3458420SDana.Myers@Sun.COM acpi_cb_cnt++; 3468420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address64.ResourceType, 3478420SDana.Myers@Sun.COM rp->Data.Address64.Info.TypeSpecific, bus), 3488420SDana.Myers@Sun.COM rp->Data.Address64.Minimum, 3498420SDana.Myers@Sun.COM rp->Data.Address64.AddressLength); 3508420SDana.Myers@Sun.COM break; 3518420SDana.Myers@Sun.COM 3528420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 3538420SDana.Myers@Sun.COM if (rp->Data.ExtAddress64.AddressLength == 0) 3548420SDana.Myers@Sun.COM break; 3558420SDana.Myers@Sun.COM acpi_cb_cnt++; 3568420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType, 3578420SDana.Myers@Sun.COM rp->Data.ExtAddress64.Info.TypeSpecific, bus), 3588420SDana.Myers@Sun.COM rp->Data.ExtAddress64.Minimum, 3598420SDana.Myers@Sun.COM rp->Data.ExtAddress64.AddressLength); 3608420SDana.Myers@Sun.COM break; 3618420SDana.Myers@Sun.COM 3628420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 3638420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an Interrupt */ 3648420SDana.Myers@Sun.COM dprintf("%s\n", "EXTENDED_IRQ"); 3658420SDana.Myers@Sun.COM break; 3668420SDana.Myers@Sun.COM 3678420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 3688420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an GAS */ 3698420SDana.Myers@Sun.COM dprintf("%s\n", "GENERIC_REGISTER"); 3708420SDana.Myers@Sun.COM break; 3718420SDana.Myers@Sun.COM } 3728420SDana.Myers@Sun.COM 3738420SDana.Myers@Sun.COM return (AE_OK); 3748420SDana.Myers@Sun.COM } 3758420SDana.Myers@Sun.COM 3763446Smrj static void 3773446Smrj mps_probe() 3783446Smrj { 3793446Smrj uchar_t *extp; 3803446Smrj struct mps_fps_hdr *fpp = NULL; 3813446Smrj struct mps_ct_hdr *ctp; 3823446Smrj uintptr_t ebda_start, base_end; 3833446Smrj ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg; 3843446Smrj 3853446Smrj base_size = *((ushort_t *)(0x413)); 3863446Smrj ebda_seg = *((ushort_t *)(0x40e)); 3873446Smrj ebda_start = ((uint32_t)ebda_seg) << 4; 3883446Smrj if (ebda_seg != 0) { 3893446Smrj fpp = (struct mps_fps_hdr *)find_sig( 3903446Smrj (uchar_t *)ebda_start, 1024, "_MP_"); 3913446Smrj } 3923446Smrj if (fpp == NULL) { 3933446Smrj base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0; 3943446Smrj if (base_end_seg != ebda_seg) { 3953446Smrj base_end = ((uintptr_t)base_end_seg) << 4; 3963446Smrj fpp = (struct mps_fps_hdr *)find_sig( 3978420SDana.Myers@Sun.COM (uchar_t *)base_end, 1024, "_MP_"); 3983446Smrj } 3993446Smrj } 4003446Smrj if (fpp == NULL) { 4013446Smrj fpp = (struct mps_fps_hdr *)find_sig( 4023446Smrj (uchar_t *)0xF0000, 0x10000, "_MP_"); 4033446Smrj } 4043446Smrj 4053446Smrj if (fpp == NULL) { 4063446Smrj dprintf("MP Spec table doesn't exist"); 4073446Smrj return; 4083446Smrj } else { 4093446Smrj dprintf("Found MP Floating Pointer Structure at %p\n", 4103446Smrj (void *)fpp); 4113446Smrj } 4123446Smrj 4133446Smrj if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) { 4143446Smrj dprintf("MP Floating Pointer Structure checksum error"); 4153446Smrj return; 4163446Smrj } 4173446Smrj 4183446Smrj ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr; 4193446Smrj if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */ 4203446Smrj dprintf("MP Configuration Table signature is wrong"); 4213446Smrj return; 4223446Smrj } 4233446Smrj 4243446Smrj base_len = ctp->ct_len; 4253446Smrj if (checksum((uchar_t *)ctp, base_len) != 0) { 4263446Smrj dprintf("MP Configuration Table checksum error"); 4273446Smrj return; 4283446Smrj } 4293446Smrj if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */ 4303446Smrj dprintf("MP Spec 1.1 found - extended table doesn't exist"); 4313446Smrj return; 4323446Smrj } 4333446Smrj if ((ext_len = ctp->ct_ext_tbl_len) == 0) { 4343446Smrj dprintf("MP Spec 1.4 found - extended table doesn't exist"); 4353446Smrj return; 4363446Smrj } 4373446Smrj extp = (uchar_t *)ctp + base_len; 4383446Smrj if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) { 4393446Smrj dprintf("MP Extended Table checksum error"); 4403446Smrj return; 4413446Smrj } 4423446Smrj mps_extp = extp; 4433446Smrj mps_ext_endp = mps_extp + ext_len; 4443446Smrj } 4453446Smrj 4463446Smrj 4473446Smrj static int 4483446Smrj mps_find_bus_res(int bus, int type, struct memlist **res) 4493446Smrj { 4503446Smrj struct sasm *sasmp; 4513446Smrj uchar_t *extp; 4523446Smrj int res_cnt; 4533446Smrj 4543446Smrj if (mps_extp == NULL) 4553446Smrj return (0); 4563446Smrj extp = mps_extp; 4573446Smrj res_cnt = 0; 4583446Smrj while (extp < mps_ext_endp) { 4593446Smrj switch (*extp) { 4603446Smrj case SYS_AS_MAPPING: 4613446Smrj sasmp = (struct sasm *)extp; 4623446Smrj if (((int)sasmp->sasm_as_type) == type && 4633446Smrj ((int)sasmp->sasm_bus_id) == bus) { 4643446Smrj if (sasmp->sasm_as_base_hi != 0 || 4658420SDana.Myers@Sun.COM sasmp->sasm_as_len_hi != 0) { 4663446Smrj printf("64 bits address space\n"); 4673446Smrj extp += SYS_AS_MAPPING_SIZE; 4683446Smrj break; 4693446Smrj } 4703446Smrj memlist_insert(res, 4713446Smrj (uint64_t)sasmp->sasm_as_base, 4723446Smrj sasmp->sasm_as_len); 4733446Smrj res_cnt++; 4743446Smrj } 4753446Smrj extp += SYS_AS_MAPPING_SIZE; 4763446Smrj break; 4773446Smrj case BUS_HIERARCHY_DESC: 4783446Smrj extp += BUS_HIERARCHY_DESC_SIZE; 4793446Smrj break; 4803446Smrj case COMP_BUS_AS_MODIFIER: 4813446Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 4823446Smrj break; 4833446Smrj default: 4843446Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 4853446Smrj " in BIOS Multiprocessor Spec table.", 4863446Smrj *extp); 4873446Smrj while (*res) { 4883446Smrj struct memlist *tmp = *res; 4893446Smrj *res = tmp->next; 4903446Smrj memlist_free(tmp); 4913446Smrj } 4923446Smrj return (0); 4933446Smrj } 4943446Smrj } 4953446Smrj return (res_cnt); 4963446Smrj } 4973446Smrj 4983446Smrj static void 4993446Smrj hrt_probe() 5003446Smrj { 5013446Smrj struct hrt_hdr *hrtp; 5023446Smrj 5033446Smrj dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 5043446Smrj if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 5053446Smrj 0x10000, "$HRT")) == NULL) { 5063446Smrj dprintf("NO PCI Hot-Plug Resource Table"); 5073446Smrj return; 5083446Smrj } 5093446Smrj dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 5103446Smrj if (hrtp->hrt_ver != 1) { 5113446Smrj dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 5123446Smrj return; 5133446Smrj } 5143446Smrj hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; 5153446Smrj dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 5163446Smrj hrt_hpep = (struct php_entry *)(hrtp + 1); 5173446Smrj } 5183446Smrj 5193446Smrj static int 5203446Smrj hrt_find_bus_res(int bus, int type, struct memlist **res) 5213446Smrj { 5223446Smrj int res_cnt, i; 5233446Smrj struct php_entry *hpep; 5243446Smrj 5253446Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) 5263446Smrj return (0); 5273446Smrj hpep = hrt_hpep; 5283446Smrj res_cnt = 0; 5293446Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 5303446Smrj if (hpep->php_pri_bus != bus) 5313446Smrj continue; 5323446Smrj if (type == IO_TYPE) { 5333446Smrj if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 5343446Smrj continue; 5353446Smrj memlist_insert(res, (uint64_t)hpep->php_io_start, 5363446Smrj (uint64_t)hpep->php_io_size); 5373446Smrj res_cnt++; 5383446Smrj } else if (type == MEM_TYPE) { 5393446Smrj if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 5403446Smrj continue; 5413446Smrj memlist_insert(res, 5423446Smrj (uint64_t)(((int)hpep->php_mem_start) << 16), 5433446Smrj (uint64_t)(((int)hpep->php_mem_size) << 16)); 5443446Smrj res_cnt++; 5453446Smrj } else if (type == PREFETCH_TYPE) { 5463446Smrj if (hpep->php_pfmem_start == 0 || 5473446Smrj hpep->php_pfmem_size == 0) 5483446Smrj continue; 5493446Smrj memlist_insert(res, 5503446Smrj (uint64_t)(((int)hpep->php_pfmem_start) << 16), 5513446Smrj (uint64_t)(((int)hpep->php_pfmem_size) << 16)); 5523446Smrj res_cnt++; 5533446Smrj } 5543446Smrj } 5553446Smrj return (res_cnt); 5563446Smrj } 5573446Smrj 5583446Smrj static uchar_t * 5593446Smrj find_sig(uchar_t *cp, int len, char *sig) 5603446Smrj { 5613446Smrj long i; 5623446Smrj 5633446Smrj /* Search for the "_MP_" or "$HRT" signature */ 5643446Smrj for (i = 0; i < len; i += 16) { 5653446Smrj if (cp[0] == sig[0] && cp[1] == sig[1] && 5663446Smrj cp[2] == sig[2] && cp[3] == sig[3]) 5673446Smrj return (cp); 5683446Smrj cp += 16; 5693446Smrj } 5703446Smrj return (NULL); 5713446Smrj } 5723446Smrj 5733446Smrj static int 5743446Smrj checksum(unsigned char *cp, int len) 5753446Smrj { 5763446Smrj int i; 5773446Smrj unsigned int cksum; 5783446Smrj 5793446Smrj for (i = cksum = 0; i < len; i++) 5803446Smrj cksum += (unsigned int) *cp++; 5813446Smrj 5823446Smrj return ((int)(cksum & 0xFF)); 5833446Smrj } 5843446Smrj 5853446Smrj #ifdef UNUSED_BUS_HIERARY_INFO 5863446Smrj 5873446Smrj /* 5883446Smrj * At this point, the bus hierarchy entries do not appear to 5893446Smrj * provide anything we can't find out from PCI config space. 5903446Smrj * The only interesting bit is the ISA bus number, which we 5913446Smrj * don't care. 5923446Smrj */ 5933446Smrj int 5943446Smrj mps_find_parent_bus(int bus) 5953446Smrj { 5963446Smrj struct sasm *sasmp; 5973446Smrj uchar_t *extp; 5983446Smrj 5993446Smrj if (mps_extp == NULL) 6003446Smrj return (-1); 6013446Smrj 6023446Smrj extp = mps_extp; 6033446Smrj while (extp < mps_ext_endp) { 6043446Smrj bhdp = (struct bhd *)extp; 6053446Smrj switch (*extp) { 6063446Smrj case SYS_AS_MAPPING: 6073446Smrj extp += SYS_AS_MAPPING_SIZE; 6083446Smrj break; 6093446Smrj case BUS_HIERARCHY_DESC: 6103446Smrj if (bhdp->bhd_bus_id == bus) 6113446Smrj return (bhdp->bhd_parent); 6123446Smrj extp += BUS_HIERARCHY_DESC_SIZE; 6133446Smrj break; 6143446Smrj case COMP_BUS_AS_MODIFIER: 6153446Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 6163446Smrj break; 6173446Smrj default: 6183446Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 6193446Smrj " in BIOS Multiprocessor Spec table.", 6203446Smrj *extp); 6213446Smrj return (-1); 6223446Smrj } 6233446Smrj } 6243446Smrj return (-1); 6253446Smrj } 6263446Smrj 6273446Smrj int 6283446Smrj hrt_find_bus_range(int bus) 6293446Smrj { 6303446Smrj int i, max_bus, sub_bus; 6313446Smrj struct php_entry *hpep; 6323446Smrj 6333446Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) { 6343446Smrj return (-1); 6353446Smrj } 6363446Smrj hpep = hrt_hpep; 6373446Smrj max_bus = -1; 6383446Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 6393446Smrj if (hpep->php_pri_bus != bus) 6403446Smrj continue; 6413446Smrj sub_bus = (int)hpep->php_subord_bus; 6423446Smrj if (sub_bus > max_bus) 6433446Smrj max_bus = sub_bus; 6443446Smrj } 6453446Smrj return (max_bus); 6463446Smrj } 6473446Smrj 6483446Smrj #endif /* UNUSED_BUS_HIERARY_INFO */ 649