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*11474SJonathan.Adams@Sun.COM * Copyright 2010 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; 4010804SDana.Myers@Sun.COM extern int pci_bios_maxbus; 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); 609428SDana.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 10710804SDana.Myers@Sun.COM for (bus = 0; bus <= pci_bios_maxbus; 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 1189428SDana.Myers@Sun.COM if (acpi_cb_cnt > 0) { 1198420SDana.Myers@Sun.COM acpi_resource_discovery = 1; 1209428SDana.Myers@Sun.COM acpi_trim_bus_ranges(); 1219428SDana.Myers@Sun.COM } 1229428SDana.Myers@Sun.COM } 1239428SDana.Myers@Sun.COM 1249428SDana.Myers@Sun.COM /* 1259428SDana.Myers@Sun.COM * Trim overlapping bus ranges in acpi_bus_res[] 1269428SDana.Myers@Sun.COM * Some BIOSes report root-bridges with bus ranges that 1279428SDana.Myers@Sun.COM * overlap, for example:"0..255" and "8..255". Lower-numbered 1289428SDana.Myers@Sun.COM * ranges are trimmed by upper-numbered ranges (so "0..255" would 1299428SDana.Myers@Sun.COM * be trimmed to "0..7", in the example). 1309428SDana.Myers@Sun.COM */ 1319428SDana.Myers@Sun.COM static void 1329428SDana.Myers@Sun.COM acpi_trim_bus_ranges() 1339428SDana.Myers@Sun.COM { 1349428SDana.Myers@Sun.COM struct memlist *ranges, *current; 1359428SDana.Myers@Sun.COM int bus; 1369428SDana.Myers@Sun.COM 1379428SDana.Myers@Sun.COM ranges = NULL; 1389428SDana.Myers@Sun.COM 1399428SDana.Myers@Sun.COM /* 1409428SDana.Myers@Sun.COM * Assumptions: 1419428SDana.Myers@Sun.COM * - there exists at most 1 bus range entry for each bus number 1429428SDana.Myers@Sun.COM * - there are no (broken) ranges that start at the same bus number 1439428SDana.Myers@Sun.COM */ 1449428SDana.Myers@Sun.COM for (bus = 0; bus < 256; bus++) { 1459428SDana.Myers@Sun.COM struct memlist *prev, *orig, *new; 1469428SDana.Myers@Sun.COM /* skip buses with no range entry */ 1479428SDana.Myers@Sun.COM if ((orig = acpi_bus_res[bus]) == NULL) 1489428SDana.Myers@Sun.COM continue; 1499428SDana.Myers@Sun.COM 1509428SDana.Myers@Sun.COM /* 1519428SDana.Myers@Sun.COM * create copy of existing range and overload 1529428SDana.Myers@Sun.COM * 'prev' pointer to link existing to new copy 1539428SDana.Myers@Sun.COM */ 1549428SDana.Myers@Sun.COM new = memlist_alloc(); 155*11474SJonathan.Adams@Sun.COM new->ml_address = orig->ml_address; 156*11474SJonathan.Adams@Sun.COM new->ml_size = orig->ml_size; 157*11474SJonathan.Adams@Sun.COM new->ml_prev = orig; 1589428SDana.Myers@Sun.COM 1599428SDana.Myers@Sun.COM /* sorted insertion of 'new' into ranges list */ 1609428SDana.Myers@Sun.COM for (current = ranges, prev = NULL; current != NULL; 161*11474SJonathan.Adams@Sun.COM prev = current, current = current->ml_next) 162*11474SJonathan.Adams@Sun.COM if (new->ml_address < current->ml_address) 1639428SDana.Myers@Sun.COM break; 1649428SDana.Myers@Sun.COM 1659428SDana.Myers@Sun.COM if (prev == NULL) { 1669428SDana.Myers@Sun.COM /* place at beginning of (possibly) empty list */ 167*11474SJonathan.Adams@Sun.COM new->ml_next = ranges; 1689428SDana.Myers@Sun.COM ranges = new; 1699428SDana.Myers@Sun.COM } else { 1709428SDana.Myers@Sun.COM /* place in list (possibly at end) */ 171*11474SJonathan.Adams@Sun.COM new->ml_next = current; 172*11474SJonathan.Adams@Sun.COM prev->ml_next = new; 1739428SDana.Myers@Sun.COM } 1749428SDana.Myers@Sun.COM } 1759428SDana.Myers@Sun.COM 1769428SDana.Myers@Sun.COM /* scan the list, perform trimming */ 1779428SDana.Myers@Sun.COM current = ranges; 1789428SDana.Myers@Sun.COM while (current != NULL) { 179*11474SJonathan.Adams@Sun.COM struct memlist *next = current->ml_next; 1809428SDana.Myers@Sun.COM 1819428SDana.Myers@Sun.COM /* done when no range above current */ 1829428SDana.Myers@Sun.COM if (next == NULL) 1839428SDana.Myers@Sun.COM break; 1849428SDana.Myers@Sun.COM 1859428SDana.Myers@Sun.COM /* 1869428SDana.Myers@Sun.COM * trim size in original range element 187*11474SJonathan.Adams@Sun.COM * (current->ml_prev points to the original range) 1889428SDana.Myers@Sun.COM */ 189*11474SJonathan.Adams@Sun.COM if ((current->ml_address + current->ml_size) > next->ml_address) 190*11474SJonathan.Adams@Sun.COM current->ml_prev->ml_size = 191*11474SJonathan.Adams@Sun.COM next->ml_address - current->ml_address; 1929428SDana.Myers@Sun.COM 1939428SDana.Myers@Sun.COM current = next; 1949428SDana.Myers@Sun.COM } 1959428SDana.Myers@Sun.COM 1969428SDana.Myers@Sun.COM /* discard the list */ 1979428SDana.Myers@Sun.COM memlist_free_all(&ranges); /* OK if ranges == NULL */ 1988420SDana.Myers@Sun.COM } 1998420SDana.Myers@Sun.COM 2008420SDana.Myers@Sun.COM static int 2018420SDana.Myers@Sun.COM acpi_find_bus_res(int bus, int type, struct memlist **res) 2028420SDana.Myers@Sun.COM { 2038420SDana.Myers@Sun.COM 2048420SDana.Myers@Sun.COM switch (type) { 2058420SDana.Myers@Sun.COM case IO_TYPE: 2068420SDana.Myers@Sun.COM *res = acpi_io_res[bus]; 2078420SDana.Myers@Sun.COM break; 2088420SDana.Myers@Sun.COM case MEM_TYPE: 2098420SDana.Myers@Sun.COM *res = acpi_mem_res[bus]; 2108420SDana.Myers@Sun.COM break; 2118420SDana.Myers@Sun.COM case PREFETCH_TYPE: 2128420SDana.Myers@Sun.COM *res = acpi_pmem_res[bus]; 2138420SDana.Myers@Sun.COM break; 2148420SDana.Myers@Sun.COM case BUSRANGE_TYPE: 2158420SDana.Myers@Sun.COM *res = acpi_bus_res[bus]; 2168420SDana.Myers@Sun.COM break; 2178420SDana.Myers@Sun.COM default: 2188420SDana.Myers@Sun.COM *res = NULL; 2198420SDana.Myers@Sun.COM break; 2208420SDana.Myers@Sun.COM } 2218420SDana.Myers@Sun.COM 2228420SDana.Myers@Sun.COM /* memlist_count() treats NULL head as zero-length */ 2238420SDana.Myers@Sun.COM return (memlist_count(*res)); 2248420SDana.Myers@Sun.COM } 2258420SDana.Myers@Sun.COM 2268420SDana.Myers@Sun.COM void 2278420SDana.Myers@Sun.COM bus_res_fini(void) 2288420SDana.Myers@Sun.COM { 2298420SDana.Myers@Sun.COM int bus; 2308420SDana.Myers@Sun.COM 23110804SDana.Myers@Sun.COM for (bus = 0; bus <= pci_bios_maxbus; bus++) { 2328420SDana.Myers@Sun.COM memlist_free_all(&acpi_io_res[bus]); 2338420SDana.Myers@Sun.COM memlist_free_all(&acpi_mem_res[bus]); 2348420SDana.Myers@Sun.COM memlist_free_all(&acpi_pmem_res[bus]); 2358420SDana.Myers@Sun.COM memlist_free_all(&acpi_bus_res[bus]); 2368420SDana.Myers@Sun.COM } 2378420SDana.Myers@Sun.COM } 2388420SDana.Myers@Sun.COM 2398420SDana.Myers@Sun.COM 2408420SDana.Myers@Sun.COM struct memlist ** 2418420SDana.Myers@Sun.COM rlistpp(UINT8 t, UINT8 flags, int bus) 2428420SDana.Myers@Sun.COM { 2438420SDana.Myers@Sun.COM switch (t) { 2448420SDana.Myers@Sun.COM 2458420SDana.Myers@Sun.COM case ACPI_MEMORY_RANGE: 2468420SDana.Myers@Sun.COM /* is this really the best we've got? */ 2478420SDana.Myers@Sun.COM if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY) 2488420SDana.Myers@Sun.COM return (&acpi_pmem_res[bus]); 2498420SDana.Myers@Sun.COM else 2508420SDana.Myers@Sun.COM return (&acpi_mem_res[bus]); 2518420SDana.Myers@Sun.COM 2528420SDana.Myers@Sun.COM case ACPI_IO_RANGE: return &acpi_io_res[bus]; 2538420SDana.Myers@Sun.COM case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus]; 2548420SDana.Myers@Sun.COM } 2558420SDana.Myers@Sun.COM return ((struct memlist **)NULL); 2568420SDana.Myers@Sun.COM } 2578420SDana.Myers@Sun.COM 2588420SDana.Myers@Sun.COM 2598420SDana.Myers@Sun.COM ACPI_STATUS 2608420SDana.Myers@Sun.COM acpi_wr_cb(ACPI_RESOURCE *rp, void *context) 2618420SDana.Myers@Sun.COM { 2628420SDana.Myers@Sun.COM int bus = (intptr_t)context; 2638420SDana.Myers@Sun.COM 2648420SDana.Myers@Sun.COM /* ignore consumed resources */ 2658420SDana.Myers@Sun.COM if (rp->Data.Address.ProducerConsumer == 1) 2668420SDana.Myers@Sun.COM return (AE_OK); 2678420SDana.Myers@Sun.COM 2688420SDana.Myers@Sun.COM switch (rp->Type) { 2698420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_IRQ: 2708420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an Interrupt */ 2718420SDana.Myers@Sun.COM dprintf("%s\n", "IRQ"); 2728420SDana.Myers@Sun.COM break; 2738420SDana.Myers@Sun.COM 2748420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_DMA: 2758420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce DMA */ 2768420SDana.Myers@Sun.COM dprintf("%s\n", "DMA"); 2778420SDana.Myers@Sun.COM break; 2788420SDana.Myers@Sun.COM 2798420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2808420SDana.Myers@Sun.COM dprintf("%s\n", "START_DEPENDENT"); 2818420SDana.Myers@Sun.COM break; 2828420SDana.Myers@Sun.COM 2838420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2848420SDana.Myers@Sun.COM dprintf("%s\n", "END_DEPENDENT"); 2858420SDana.Myers@Sun.COM break; 2868420SDana.Myers@Sun.COM 2878420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_IO: 2888420SDana.Myers@Sun.COM if (rp->Data.Io.AddressLength == 0) 2898420SDana.Myers@Sun.COM break; 2908420SDana.Myers@Sun.COM acpi_cb_cnt++; 2918420SDana.Myers@Sun.COM memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, 2928420SDana.Myers@Sun.COM rp->Data.Io.AddressLength); 2938420SDana.Myers@Sun.COM break; 2948420SDana.Myers@Sun.COM 2958420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_FIXED_IO: 2968420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 2978420SDana.Myers@Sun.COM dprintf("%s\n", "FIXED_IO"); 2988420SDana.Myers@Sun.COM break; 2998420SDana.Myers@Sun.COM 3008420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_VENDOR: 3018420SDana.Myers@Sun.COM dprintf("%s\n", "VENDOR"); 3028420SDana.Myers@Sun.COM break; 3038420SDana.Myers@Sun.COM 3048420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_END_TAG: 3058420SDana.Myers@Sun.COM dprintf("%s\n", "END_TAG"); 3068420SDana.Myers@Sun.COM break; 3078420SDana.Myers@Sun.COM 3088420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_MEMORY24: 3098420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3108420SDana.Myers@Sun.COM dprintf("%s\n", "MEMORY24"); 3118420SDana.Myers@Sun.COM break; 3128420SDana.Myers@Sun.COM 3138420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_MEMORY32: 3148420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3158420SDana.Myers@Sun.COM dprintf("%s\n", "MEMORY32"); 3168420SDana.Myers@Sun.COM break; 3178420SDana.Myers@Sun.COM 3188420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 3198420SDana.Myers@Sun.COM /* only expect to see this as a consumer */ 3208420SDana.Myers@Sun.COM dprintf("%s\n", "FIXED_MEMORY32"); 3218420SDana.Myers@Sun.COM break; 3228420SDana.Myers@Sun.COM 3238420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS16: 3248420SDana.Myers@Sun.COM if (rp->Data.Address16.AddressLength == 0) 3258420SDana.Myers@Sun.COM break; 3268420SDana.Myers@Sun.COM acpi_cb_cnt++; 3278420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address16.ResourceType, 3288420SDana.Myers@Sun.COM rp->Data.Address16.Info.TypeSpecific, bus), 3298420SDana.Myers@Sun.COM rp->Data.Address16.Minimum, 3308420SDana.Myers@Sun.COM rp->Data.Address16.AddressLength); 3318420SDana.Myers@Sun.COM break; 3328420SDana.Myers@Sun.COM 3338420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS32: 3348420SDana.Myers@Sun.COM if (rp->Data.Address32.AddressLength == 0) 3358420SDana.Myers@Sun.COM break; 3368420SDana.Myers@Sun.COM acpi_cb_cnt++; 3378420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address32.ResourceType, 3388420SDana.Myers@Sun.COM rp->Data.Address32.Info.TypeSpecific, bus), 3398420SDana.Myers@Sun.COM rp->Data.Address32.Minimum, 3408420SDana.Myers@Sun.COM rp->Data.Address32.AddressLength); 3418420SDana.Myers@Sun.COM break; 3428420SDana.Myers@Sun.COM 3438420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_ADDRESS64: 34410576SKerry.Shu@Sun.COM /* 34510576SKerry.Shu@Sun.COM * We comment out this block because we currently cannot deal with 34610576SKerry.Shu@Sun.COM * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO 34710576SKerry.Shu@Sun.COM * support. 34810576SKerry.Shu@Sun.COM */ 34910576SKerry.Shu@Sun.COM #if 0 3508420SDana.Myers@Sun.COM if (rp->Data.Address64.AddressLength == 0) 3518420SDana.Myers@Sun.COM break; 3528420SDana.Myers@Sun.COM acpi_cb_cnt++; 3538420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.Address64.ResourceType, 3548420SDana.Myers@Sun.COM rp->Data.Address64.Info.TypeSpecific, bus), 3558420SDana.Myers@Sun.COM rp->Data.Address64.Minimum, 3568420SDana.Myers@Sun.COM rp->Data.Address64.AddressLength); 35710576SKerry.Shu@Sun.COM #endif 3588420SDana.Myers@Sun.COM break; 3598420SDana.Myers@Sun.COM 3608420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 36110576SKerry.Shu@Sun.COM #if 0 /* Will revisit this when we add PCI 64-bit MMIO support */ 3628420SDana.Myers@Sun.COM if (rp->Data.ExtAddress64.AddressLength == 0) 3638420SDana.Myers@Sun.COM break; 3648420SDana.Myers@Sun.COM acpi_cb_cnt++; 3658420SDana.Myers@Sun.COM memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType, 3668420SDana.Myers@Sun.COM rp->Data.ExtAddress64.Info.TypeSpecific, bus), 3678420SDana.Myers@Sun.COM rp->Data.ExtAddress64.Minimum, 3688420SDana.Myers@Sun.COM rp->Data.ExtAddress64.AddressLength); 36910576SKerry.Shu@Sun.COM #endif 3708420SDana.Myers@Sun.COM break; 3718420SDana.Myers@Sun.COM 3728420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 3738420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an Interrupt */ 3748420SDana.Myers@Sun.COM dprintf("%s\n", "EXTENDED_IRQ"); 3758420SDana.Myers@Sun.COM break; 3768420SDana.Myers@Sun.COM 3778420SDana.Myers@Sun.COM case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 3788420SDana.Myers@Sun.COM /* never expect to see a PCI bus produce an GAS */ 3798420SDana.Myers@Sun.COM dprintf("%s\n", "GENERIC_REGISTER"); 3808420SDana.Myers@Sun.COM break; 3818420SDana.Myers@Sun.COM } 3828420SDana.Myers@Sun.COM 3838420SDana.Myers@Sun.COM return (AE_OK); 3848420SDana.Myers@Sun.COM } 3858420SDana.Myers@Sun.COM 3863446Smrj static void 3873446Smrj mps_probe() 3883446Smrj { 3893446Smrj uchar_t *extp; 3903446Smrj struct mps_fps_hdr *fpp = NULL; 3913446Smrj struct mps_ct_hdr *ctp; 3923446Smrj uintptr_t ebda_start, base_end; 3933446Smrj ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg; 3943446Smrj 3953446Smrj base_size = *((ushort_t *)(0x413)); 3963446Smrj ebda_seg = *((ushort_t *)(0x40e)); 3973446Smrj ebda_start = ((uint32_t)ebda_seg) << 4; 3983446Smrj if (ebda_seg != 0) { 3993446Smrj fpp = (struct mps_fps_hdr *)find_sig( 4003446Smrj (uchar_t *)ebda_start, 1024, "_MP_"); 4013446Smrj } 4023446Smrj if (fpp == NULL) { 4033446Smrj base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0; 4043446Smrj if (base_end_seg != ebda_seg) { 4053446Smrj base_end = ((uintptr_t)base_end_seg) << 4; 4063446Smrj fpp = (struct mps_fps_hdr *)find_sig( 4078420SDana.Myers@Sun.COM (uchar_t *)base_end, 1024, "_MP_"); 4083446Smrj } 4093446Smrj } 4103446Smrj if (fpp == NULL) { 4113446Smrj fpp = (struct mps_fps_hdr *)find_sig( 4123446Smrj (uchar_t *)0xF0000, 0x10000, "_MP_"); 4133446Smrj } 4143446Smrj 4153446Smrj if (fpp == NULL) { 4163446Smrj dprintf("MP Spec table doesn't exist"); 4173446Smrj return; 4183446Smrj } else { 4193446Smrj dprintf("Found MP Floating Pointer Structure at %p\n", 4203446Smrj (void *)fpp); 4213446Smrj } 4223446Smrj 4233446Smrj if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) { 4243446Smrj dprintf("MP Floating Pointer Structure checksum error"); 4253446Smrj return; 4263446Smrj } 4273446Smrj 4283446Smrj ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr; 4293446Smrj if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */ 4303446Smrj dprintf("MP Configuration Table signature is wrong"); 4313446Smrj return; 4323446Smrj } 4333446Smrj 4343446Smrj base_len = ctp->ct_len; 4353446Smrj if (checksum((uchar_t *)ctp, base_len) != 0) { 4363446Smrj dprintf("MP Configuration Table checksum error"); 4373446Smrj return; 4383446Smrj } 4393446Smrj if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */ 4403446Smrj dprintf("MP Spec 1.1 found - extended table doesn't exist"); 4413446Smrj return; 4423446Smrj } 4433446Smrj if ((ext_len = ctp->ct_ext_tbl_len) == 0) { 4443446Smrj dprintf("MP Spec 1.4 found - extended table doesn't exist"); 4453446Smrj return; 4463446Smrj } 4473446Smrj extp = (uchar_t *)ctp + base_len; 4483446Smrj if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) { 4493446Smrj dprintf("MP Extended Table checksum error"); 4503446Smrj return; 4513446Smrj } 4523446Smrj mps_extp = extp; 4533446Smrj mps_ext_endp = mps_extp + ext_len; 4543446Smrj } 4553446Smrj 4563446Smrj 4573446Smrj static int 4583446Smrj mps_find_bus_res(int bus, int type, struct memlist **res) 4593446Smrj { 4603446Smrj struct sasm *sasmp; 4613446Smrj uchar_t *extp; 4623446Smrj int res_cnt; 4633446Smrj 4643446Smrj if (mps_extp == NULL) 4653446Smrj return (0); 4663446Smrj extp = mps_extp; 4673446Smrj res_cnt = 0; 4683446Smrj while (extp < mps_ext_endp) { 4693446Smrj switch (*extp) { 4703446Smrj case SYS_AS_MAPPING: 4713446Smrj sasmp = (struct sasm *)extp; 4723446Smrj if (((int)sasmp->sasm_as_type) == type && 4733446Smrj ((int)sasmp->sasm_bus_id) == bus) { 4743446Smrj if (sasmp->sasm_as_base_hi != 0 || 4758420SDana.Myers@Sun.COM sasmp->sasm_as_len_hi != 0) { 4763446Smrj printf("64 bits address space\n"); 4773446Smrj extp += SYS_AS_MAPPING_SIZE; 4783446Smrj break; 4793446Smrj } 4803446Smrj memlist_insert(res, 4813446Smrj (uint64_t)sasmp->sasm_as_base, 4823446Smrj sasmp->sasm_as_len); 4833446Smrj res_cnt++; 4843446Smrj } 4853446Smrj extp += SYS_AS_MAPPING_SIZE; 4863446Smrj break; 4873446Smrj case BUS_HIERARCHY_DESC: 4883446Smrj extp += BUS_HIERARCHY_DESC_SIZE; 4893446Smrj break; 4903446Smrj case COMP_BUS_AS_MODIFIER: 4913446Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 4923446Smrj break; 4933446Smrj default: 4943446Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 4953446Smrj " in BIOS Multiprocessor Spec table.", 4963446Smrj *extp); 4973446Smrj while (*res) { 4983446Smrj struct memlist *tmp = *res; 499*11474SJonathan.Adams@Sun.COM *res = tmp->ml_next; 5003446Smrj memlist_free(tmp); 5013446Smrj } 5023446Smrj return (0); 5033446Smrj } 5043446Smrj } 5053446Smrj return (res_cnt); 5063446Smrj } 5073446Smrj 5083446Smrj static void 5093446Smrj hrt_probe() 5103446Smrj { 5113446Smrj struct hrt_hdr *hrtp; 5123446Smrj 5133446Smrj dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n"); 5143446Smrj if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000, 5153446Smrj 0x10000, "$HRT")) == NULL) { 5163446Smrj dprintf("NO PCI Hot-Plug Resource Table"); 5173446Smrj return; 5183446Smrj } 5193446Smrj dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp); 5203446Smrj if (hrtp->hrt_ver != 1) { 5213446Smrj dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); 5223446Smrj return; 5233446Smrj } 5243446Smrj hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; 5253446Smrj dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); 5263446Smrj hrt_hpep = (struct php_entry *)(hrtp + 1); 5273446Smrj } 5283446Smrj 5293446Smrj static int 5303446Smrj hrt_find_bus_res(int bus, int type, struct memlist **res) 5313446Smrj { 5323446Smrj int res_cnt, i; 5333446Smrj struct php_entry *hpep; 5343446Smrj 5353446Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) 5363446Smrj return (0); 5373446Smrj hpep = hrt_hpep; 5383446Smrj res_cnt = 0; 5393446Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 5403446Smrj if (hpep->php_pri_bus != bus) 5413446Smrj continue; 5423446Smrj if (type == IO_TYPE) { 5433446Smrj if (hpep->php_io_start == 0 || hpep->php_io_size == 0) 5443446Smrj continue; 5453446Smrj memlist_insert(res, (uint64_t)hpep->php_io_start, 5463446Smrj (uint64_t)hpep->php_io_size); 5473446Smrj res_cnt++; 5483446Smrj } else if (type == MEM_TYPE) { 5493446Smrj if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) 5503446Smrj continue; 5513446Smrj memlist_insert(res, 5523446Smrj (uint64_t)(((int)hpep->php_mem_start) << 16), 5533446Smrj (uint64_t)(((int)hpep->php_mem_size) << 16)); 5543446Smrj res_cnt++; 5553446Smrj } else if (type == PREFETCH_TYPE) { 5563446Smrj if (hpep->php_pfmem_start == 0 || 5573446Smrj hpep->php_pfmem_size == 0) 5583446Smrj continue; 5593446Smrj memlist_insert(res, 5603446Smrj (uint64_t)(((int)hpep->php_pfmem_start) << 16), 5613446Smrj (uint64_t)(((int)hpep->php_pfmem_size) << 16)); 5623446Smrj res_cnt++; 5633446Smrj } 5643446Smrj } 5653446Smrj return (res_cnt); 5663446Smrj } 5673446Smrj 5683446Smrj static uchar_t * 5693446Smrj find_sig(uchar_t *cp, int len, char *sig) 5703446Smrj { 5713446Smrj long i; 5723446Smrj 5733446Smrj /* Search for the "_MP_" or "$HRT" signature */ 5743446Smrj for (i = 0; i < len; i += 16) { 5753446Smrj if (cp[0] == sig[0] && cp[1] == sig[1] && 5763446Smrj cp[2] == sig[2] && cp[3] == sig[3]) 5773446Smrj return (cp); 5783446Smrj cp += 16; 5793446Smrj } 5803446Smrj return (NULL); 5813446Smrj } 5823446Smrj 5833446Smrj static int 5843446Smrj checksum(unsigned char *cp, int len) 5853446Smrj { 5863446Smrj int i; 5873446Smrj unsigned int cksum; 5883446Smrj 5893446Smrj for (i = cksum = 0; i < len; i++) 5903446Smrj cksum += (unsigned int) *cp++; 5913446Smrj 5923446Smrj return ((int)(cksum & 0xFF)); 5933446Smrj } 5943446Smrj 5953446Smrj #ifdef UNUSED_BUS_HIERARY_INFO 5963446Smrj 5973446Smrj /* 5983446Smrj * At this point, the bus hierarchy entries do not appear to 5993446Smrj * provide anything we can't find out from PCI config space. 6003446Smrj * The only interesting bit is the ISA bus number, which we 6013446Smrj * don't care. 6023446Smrj */ 6033446Smrj int 6043446Smrj mps_find_parent_bus(int bus) 6053446Smrj { 6063446Smrj struct sasm *sasmp; 6073446Smrj uchar_t *extp; 6083446Smrj 6093446Smrj if (mps_extp == NULL) 6103446Smrj return (-1); 6113446Smrj 6123446Smrj extp = mps_extp; 6133446Smrj while (extp < mps_ext_endp) { 6143446Smrj bhdp = (struct bhd *)extp; 6153446Smrj switch (*extp) { 6163446Smrj case SYS_AS_MAPPING: 6173446Smrj extp += SYS_AS_MAPPING_SIZE; 6183446Smrj break; 6193446Smrj case BUS_HIERARCHY_DESC: 6203446Smrj if (bhdp->bhd_bus_id == bus) 6213446Smrj return (bhdp->bhd_parent); 6223446Smrj extp += BUS_HIERARCHY_DESC_SIZE; 6233446Smrj break; 6243446Smrj case COMP_BUS_AS_MODIFIER: 6253446Smrj extp += COMP_BUS_AS_MODIFIER_SIZE; 6263446Smrj break; 6273446Smrj default: 6283446Smrj cmn_err(CE_WARN, "Unknown descriptor type %d" 6293446Smrj " in BIOS Multiprocessor Spec table.", 6303446Smrj *extp); 6313446Smrj return (-1); 6323446Smrj } 6333446Smrj } 6343446Smrj return (-1); 6353446Smrj } 6363446Smrj 6373446Smrj int 6383446Smrj hrt_find_bus_range(int bus) 6393446Smrj { 6403446Smrj int i, max_bus, sub_bus; 6413446Smrj struct php_entry *hpep; 6423446Smrj 6433446Smrj if (hrt_hpep == NULL || hrt_entry_cnt == 0) { 6443446Smrj return (-1); 6453446Smrj } 6463446Smrj hpep = hrt_hpep; 6473446Smrj max_bus = -1; 6483446Smrj for (i = 0; i < hrt_entry_cnt; i++, hpep++) { 6493446Smrj if (hpep->php_pri_bus != bus) 6503446Smrj continue; 6513446Smrj sub_bus = (int)hpep->php_subord_bus; 6523446Smrj if (sub_bus > max_bus) 6533446Smrj max_bus = sub_bus; 6543446Smrj } 6553446Smrj return (max_bus); 6563446Smrj } 6573446Smrj 6583446Smrj #endif /* UNUSED_BUS_HIERARY_INFO */ 659