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 *
find_bus_res(int bus,int type)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
acpi_pci_probe(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
acpi_trim_bus_ranges()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
acpi_find_bus_res(int bus,int type,struct memlist ** res)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
bus_res_fini(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 **
rlistpp(UINT8 t,UINT8 flags,int bus)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
acpi_wr_cb(ACPI_RESOURCE * rp,void * context)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
mps_probe()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
mps_find_bus_res(int bus,int type,struct memlist ** res)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
hrt_probe()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
hrt_find_bus_res(int bus,int type,struct memlist ** res)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 *
find_sig(uchar_t * cp,int len,char * sig)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
checksum(unsigned char * cp,int len)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
mps_find_parent_bus(int bus)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
hrt_find_bus_range(int bus)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