xref: /onnv-gate/usr/src/uts/intel/io/pci/pci_resource.c (revision 11474:857f9db4ef05)
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