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 /*
229428SDana.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;
40*10804SDana.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 
107*10804SDana.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();
1559428SDana.Myers@Sun.COM 		new->address = orig->address;
1569428SDana.Myers@Sun.COM 		new->size = orig->size;
1579428SDana.Myers@Sun.COM 		new->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;
1619428SDana.Myers@Sun.COM 		    prev = current, current = current->next)
1629428SDana.Myers@Sun.COM 			if (new->address < current->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 */
1679428SDana.Myers@Sun.COM 			new->next = ranges;
1689428SDana.Myers@Sun.COM 			ranges = new;
1699428SDana.Myers@Sun.COM 		} else {
1709428SDana.Myers@Sun.COM 			/* place in list (possibly at end) */
1719428SDana.Myers@Sun.COM 			new->next = current;
1729428SDana.Myers@Sun.COM 			prev->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) {
1799428SDana.Myers@Sun.COM 		struct memlist *next = current->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
1879428SDana.Myers@Sun.COM 		 * (current->prev points to the original range)
1889428SDana.Myers@Sun.COM 		 */
1899428SDana.Myers@Sun.COM 		if ((current->address + current->size) > next->address)
1909428SDana.Myers@Sun.COM 			current->prev->size = next->address - current->address;
1919428SDana.Myers@Sun.COM 
1929428SDana.Myers@Sun.COM 		current = next;
1939428SDana.Myers@Sun.COM 	}
1949428SDana.Myers@Sun.COM 
1959428SDana.Myers@Sun.COM 	/* discard the list */
1969428SDana.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 
230*10804SDana.Myers@Sun.COM 	for (bus = 0; bus <= pci_bios_maxbus; 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:
34310576SKerry.Shu@Sun.COM 	/*
34410576SKerry.Shu@Sun.COM 	 * We comment out this block because we currently cannot deal with
34510576SKerry.Shu@Sun.COM 	 * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO
34610576SKerry.Shu@Sun.COM 	 * support.
34710576SKerry.Shu@Sun.COM 	 */
34810576SKerry.Shu@Sun.COM #if 0
3498420SDana.Myers@Sun.COM 		if (rp->Data.Address64.AddressLength == 0)
3508420SDana.Myers@Sun.COM 			break;
3518420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
3528420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.Address64.ResourceType,
3538420SDana.Myers@Sun.COM 		    rp->Data.Address64.Info.TypeSpecific, bus),
3548420SDana.Myers@Sun.COM 		    rp->Data.Address64.Minimum,
3558420SDana.Myers@Sun.COM 		    rp->Data.Address64.AddressLength);
35610576SKerry.Shu@Sun.COM #endif
3578420SDana.Myers@Sun.COM 		break;
3588420SDana.Myers@Sun.COM 
3598420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
36010576SKerry.Shu@Sun.COM #if 0	/* Will revisit this when we add PCI 64-bit MMIO support */
3618420SDana.Myers@Sun.COM 		if (rp->Data.ExtAddress64.AddressLength == 0)
3628420SDana.Myers@Sun.COM 			break;
3638420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
3648420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType,
3658420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.Info.TypeSpecific, bus),
3668420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.Minimum,
3678420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.AddressLength);
36810576SKerry.Shu@Sun.COM #endif
3698420SDana.Myers@Sun.COM 		break;
3708420SDana.Myers@Sun.COM 
3718420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
3728420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce an Interrupt */
3738420SDana.Myers@Sun.COM 		dprintf("%s\n", "EXTENDED_IRQ");
3748420SDana.Myers@Sun.COM 		break;
3758420SDana.Myers@Sun.COM 
3768420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
3778420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce an GAS */
3788420SDana.Myers@Sun.COM 		dprintf("%s\n", "GENERIC_REGISTER");
3798420SDana.Myers@Sun.COM 		break;
3808420SDana.Myers@Sun.COM 	}
3818420SDana.Myers@Sun.COM 
3828420SDana.Myers@Sun.COM 	return (AE_OK);
3838420SDana.Myers@Sun.COM }
3848420SDana.Myers@Sun.COM 
3853446Smrj static void
3863446Smrj mps_probe()
3873446Smrj {
3883446Smrj 	uchar_t *extp;
3893446Smrj 	struct mps_fps_hdr *fpp = NULL;
3903446Smrj 	struct mps_ct_hdr *ctp;
3913446Smrj 	uintptr_t ebda_start, base_end;
3923446Smrj 	ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
3933446Smrj 
3943446Smrj 	base_size = *((ushort_t *)(0x413));
3953446Smrj 	ebda_seg = *((ushort_t *)(0x40e));
3963446Smrj 	ebda_start = ((uint32_t)ebda_seg) << 4;
3973446Smrj 	if (ebda_seg != 0) {
3983446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
3993446Smrj 		    (uchar_t *)ebda_start, 1024, "_MP_");
4003446Smrj 	}
4013446Smrj 	if (fpp == NULL) {
4023446Smrj 		base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
4033446Smrj 		if (base_end_seg != ebda_seg) {
4043446Smrj 			base_end = ((uintptr_t)base_end_seg) << 4;
4053446Smrj 			fpp = (struct mps_fps_hdr *)find_sig(
4068420SDana.Myers@Sun.COM 			    (uchar_t *)base_end, 1024, "_MP_");
4073446Smrj 		}
4083446Smrj 	}
4093446Smrj 	if (fpp == NULL) {
4103446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
4113446Smrj 		    (uchar_t *)0xF0000, 0x10000, "_MP_");
4123446Smrj 	}
4133446Smrj 
4143446Smrj 	if (fpp == NULL) {
4153446Smrj 		dprintf("MP Spec table doesn't exist");
4163446Smrj 		return;
4173446Smrj 	} else {
4183446Smrj 		dprintf("Found MP Floating Pointer Structure at %p\n",
4193446Smrj 		    (void *)fpp);
4203446Smrj 	}
4213446Smrj 
4223446Smrj 	if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
4233446Smrj 		dprintf("MP Floating Pointer Structure checksum error");
4243446Smrj 		return;
4253446Smrj 	}
4263446Smrj 
4273446Smrj 	ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
4283446Smrj 	if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
4293446Smrj 		dprintf("MP Configuration Table signature is wrong");
4303446Smrj 		return;
4313446Smrj 	}
4323446Smrj 
4333446Smrj 	base_len = ctp->ct_len;
4343446Smrj 	if (checksum((uchar_t *)ctp, base_len) != 0) {
4353446Smrj 		dprintf("MP Configuration Table checksum error");
4363446Smrj 		return;
4373446Smrj 	}
4383446Smrj 	if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
4393446Smrj 		dprintf("MP Spec 1.1 found - extended table doesn't exist");
4403446Smrj 		return;
4413446Smrj 	}
4423446Smrj 	if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
4433446Smrj 		dprintf("MP Spec 1.4 found - extended table doesn't exist");
4443446Smrj 		return;
4453446Smrj 	}
4463446Smrj 	extp = (uchar_t *)ctp + base_len;
4473446Smrj 	if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
4483446Smrj 		dprintf("MP Extended Table checksum error");
4493446Smrj 		return;
4503446Smrj 	}
4513446Smrj 	mps_extp = extp;
4523446Smrj 	mps_ext_endp = mps_extp + ext_len;
4533446Smrj }
4543446Smrj 
4553446Smrj 
4563446Smrj static int
4573446Smrj mps_find_bus_res(int bus, int type, struct memlist **res)
4583446Smrj {
4593446Smrj 	struct sasm *sasmp;
4603446Smrj 	uchar_t *extp;
4613446Smrj 	int res_cnt;
4623446Smrj 
4633446Smrj 	if (mps_extp == NULL)
4643446Smrj 		return (0);
4653446Smrj 	extp = mps_extp;
4663446Smrj 	res_cnt = 0;
4673446Smrj 	while (extp < mps_ext_endp) {
4683446Smrj 		switch (*extp) {
4693446Smrj 		case SYS_AS_MAPPING:
4703446Smrj 			sasmp = (struct sasm *)extp;
4713446Smrj 			if (((int)sasmp->sasm_as_type) == type &&
4723446Smrj 			    ((int)sasmp->sasm_bus_id) == bus) {
4733446Smrj 				if (sasmp->sasm_as_base_hi != 0 ||
4748420SDana.Myers@Sun.COM 				    sasmp->sasm_as_len_hi != 0) {
4753446Smrj 					printf("64 bits address space\n");
4763446Smrj 					extp += SYS_AS_MAPPING_SIZE;
4773446Smrj 					break;
4783446Smrj 				}
4793446Smrj 				memlist_insert(res,
4803446Smrj 				    (uint64_t)sasmp->sasm_as_base,
4813446Smrj 				    sasmp->sasm_as_len);
4823446Smrj 				res_cnt++;
4833446Smrj 			}
4843446Smrj 			extp += SYS_AS_MAPPING_SIZE;
4853446Smrj 			break;
4863446Smrj 		case BUS_HIERARCHY_DESC:
4873446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
4883446Smrj 			break;
4893446Smrj 		case COMP_BUS_AS_MODIFIER:
4903446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
4913446Smrj 			break;
4923446Smrj 		default:
4933446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
4943446Smrj 			    " in BIOS Multiprocessor Spec table.",
4953446Smrj 			    *extp);
4963446Smrj 			while (*res) {
4973446Smrj 				struct memlist *tmp = *res;
4983446Smrj 				*res = tmp->next;
4993446Smrj 				memlist_free(tmp);
5003446Smrj 			}
5013446Smrj 			return (0);
5023446Smrj 		}
5033446Smrj 	}
5043446Smrj 	return (res_cnt);
5053446Smrj }
5063446Smrj 
5073446Smrj static void
5083446Smrj hrt_probe()
5093446Smrj {
5103446Smrj 	struct hrt_hdr *hrtp;
5113446Smrj 
5123446Smrj 	dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
5133446Smrj 	if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
5143446Smrj 	    0x10000, "$HRT")) == NULL) {
5153446Smrj 		dprintf("NO PCI Hot-Plug Resource Table");
5163446Smrj 		return;
5173446Smrj 	}
5183446Smrj 	dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
5193446Smrj 	if (hrtp->hrt_ver != 1) {
5203446Smrj 		dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
5213446Smrj 		return;
5223446Smrj 	}
5233446Smrj 	hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
5243446Smrj 	dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
5253446Smrj 	hrt_hpep = (struct php_entry *)(hrtp + 1);
5263446Smrj }
5273446Smrj 
5283446Smrj static int
5293446Smrj hrt_find_bus_res(int bus, int type, struct memlist **res)
5303446Smrj {
5313446Smrj 	int res_cnt, i;
5323446Smrj 	struct php_entry *hpep;
5333446Smrj 
5343446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0)
5353446Smrj 		return (0);
5363446Smrj 	hpep = hrt_hpep;
5373446Smrj 	res_cnt = 0;
5383446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
5393446Smrj 		if (hpep->php_pri_bus != bus)
5403446Smrj 			continue;
5413446Smrj 		if (type == IO_TYPE) {
5423446Smrj 			if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
5433446Smrj 				continue;
5443446Smrj 			memlist_insert(res, (uint64_t)hpep->php_io_start,
5453446Smrj 			    (uint64_t)hpep->php_io_size);
5463446Smrj 			res_cnt++;
5473446Smrj 		} else if (type == MEM_TYPE) {
5483446Smrj 			if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
5493446Smrj 				continue;
5503446Smrj 			memlist_insert(res,
5513446Smrj 			    (uint64_t)(((int)hpep->php_mem_start) << 16),
5523446Smrj 			    (uint64_t)(((int)hpep->php_mem_size) << 16));
5533446Smrj 			res_cnt++;
5543446Smrj 		} else if (type == PREFETCH_TYPE) {
5553446Smrj 			if (hpep->php_pfmem_start == 0 ||
5563446Smrj 			    hpep->php_pfmem_size == 0)
5573446Smrj 				continue;
5583446Smrj 			memlist_insert(res,
5593446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_start) << 16),
5603446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_size) << 16));
5613446Smrj 			res_cnt++;
5623446Smrj 		}
5633446Smrj 	}
5643446Smrj 	return (res_cnt);
5653446Smrj }
5663446Smrj 
5673446Smrj static uchar_t *
5683446Smrj find_sig(uchar_t *cp, int len, char *sig)
5693446Smrj {
5703446Smrj 	long i;
5713446Smrj 
5723446Smrj 	/* Search for the "_MP_"  or "$HRT" signature */
5733446Smrj 	for (i = 0; i < len; i += 16) {
5743446Smrj 		if (cp[0] == sig[0] && cp[1] == sig[1] &&
5753446Smrj 		    cp[2] == sig[2] && cp[3] == sig[3])
5763446Smrj 			return (cp);
5773446Smrj 		cp += 16;
5783446Smrj 	}
5793446Smrj 	return (NULL);
5803446Smrj }
5813446Smrj 
5823446Smrj static int
5833446Smrj checksum(unsigned char *cp, int len)
5843446Smrj {
5853446Smrj 	int i;
5863446Smrj 	unsigned int cksum;
5873446Smrj 
5883446Smrj 	for (i = cksum = 0; i < len; i++)
5893446Smrj 		cksum += (unsigned int) *cp++;
5903446Smrj 
5913446Smrj 	return ((int)(cksum & 0xFF));
5923446Smrj }
5933446Smrj 
5943446Smrj #ifdef UNUSED_BUS_HIERARY_INFO
5953446Smrj 
5963446Smrj /*
5973446Smrj  * At this point, the bus hierarchy entries do not appear to
5983446Smrj  * provide anything we can't find out from PCI config space.
5993446Smrj  * The only interesting bit is the ISA bus number, which we
6003446Smrj  * don't care.
6013446Smrj  */
6023446Smrj int
6033446Smrj mps_find_parent_bus(int bus)
6043446Smrj {
6053446Smrj 	struct sasm *sasmp;
6063446Smrj 	uchar_t *extp;
6073446Smrj 
6083446Smrj 	if (mps_extp == NULL)
6093446Smrj 		return (-1);
6103446Smrj 
6113446Smrj 	extp = mps_extp;
6123446Smrj 	while (extp < mps_ext_endp) {
6133446Smrj 		bhdp = (struct bhd *)extp;
6143446Smrj 		switch (*extp) {
6153446Smrj 		case SYS_AS_MAPPING:
6163446Smrj 			extp += SYS_AS_MAPPING_SIZE;
6173446Smrj 			break;
6183446Smrj 		case BUS_HIERARCHY_DESC:
6193446Smrj 			if (bhdp->bhd_bus_id == bus)
6203446Smrj 				return (bhdp->bhd_parent);
6213446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
6223446Smrj 			break;
6233446Smrj 		case COMP_BUS_AS_MODIFIER:
6243446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
6253446Smrj 			break;
6263446Smrj 		default:
6273446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
6283446Smrj 			    " in BIOS Multiprocessor Spec table.",
6293446Smrj 			    *extp);
6303446Smrj 			return (-1);
6313446Smrj 		}
6323446Smrj 	}
6333446Smrj 	return (-1);
6343446Smrj }
6353446Smrj 
6363446Smrj int
6373446Smrj hrt_find_bus_range(int bus)
6383446Smrj {
6393446Smrj 	int i, max_bus, sub_bus;
6403446Smrj 	struct php_entry *hpep;
6413446Smrj 
6423446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
6433446Smrj 		return (-1);
6443446Smrj 	}
6453446Smrj 	hpep = hrt_hpep;
6463446Smrj 	max_bus = -1;
6473446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
6483446Smrj 		if (hpep->php_pri_bus != bus)
6493446Smrj 			continue;
6503446Smrj 		sub_bus = (int)hpep->php_subord_bus;
6513446Smrj 		if (sub_bus > max_bus)
6523446Smrj 			max_bus = sub_bus;
6533446Smrj 	}
6543446Smrj 	return (max_bus);
6553446Smrj }
6563446Smrj 
6573446Smrj #endif /* UNUSED_BUS_HIERARY_INFO */
658