xref: /titanic_41/usr/src/uts/intel/io/pci/pci_resource.c (revision 265a3f1d64f26bd7637bd62d476fc0fb08785666)
1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
58fc7923fSDana Myers  * Common Development and Distribution License (the "License").
68fc7923fSDana Myers  * You may not use this file except in compliance with the License.
7ae115bc7Smrj  *
8ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj  * See the License for the specific language governing permissions
11ae115bc7Smrj  * and limitations under the License.
12ae115bc7Smrj  *
13ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj  *
19ae115bc7Smrj  * CDDL HEADER END
20ae115bc7Smrj  */
21ae115bc7Smrj /*
2256f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23ae115bc7Smrj  * Use is subject to license terms.
24ae115bc7Smrj  *
25de5d74c2SJerry Jelinek  * Copyright 2016 Joyent, Inc.
26de5d74c2SJerry Jelinek  *
27ae115bc7Smrj  * pci_resource.c -- routines to retrieve available bus resources from
28ae115bc7Smrj  *		 the MP Spec. Table and Hotplug Resource Table
29ae115bc7Smrj  */
30ae115bc7Smrj 
31ae115bc7Smrj #include <sys/types.h>
32ae115bc7Smrj #include <sys/memlist.h>
33ae115bc7Smrj #include <sys/pci_impl.h>
34ae115bc7Smrj #include <sys/systm.h>
35ae115bc7Smrj #include <sys/cmn_err.h>
368fc7923fSDana Myers #include <sys/acpi/acpi.h>
378fc7923fSDana Myers #include <sys/acpica.h>
38ae115bc7Smrj #include "mps_table.h"
39ae115bc7Smrj #include "pcihrt.h"
40ae115bc7Smrj 
41ae115bc7Smrj extern int pci_boot_debug;
4247310cedSDana Myers extern int pci_bios_maxbus;
43ae115bc7Smrj #define	dprintf	if (pci_boot_debug) printf
44ae115bc7Smrj 
45ae115bc7Smrj static int tbl_init = 0;
46ae115bc7Smrj static uchar_t *mps_extp = NULL;
47ae115bc7Smrj static uchar_t *mps_ext_endp = NULL;
48ae115bc7Smrj static struct php_entry *hrt_hpep;
49ae115bc7Smrj static int hrt_entry_cnt = 0;
508fc7923fSDana Myers static int acpi_cb_cnt = 0;
51ae115bc7Smrj 
52ae115bc7Smrj static void mps_probe(void);
538fc7923fSDana Myers static void acpi_pci_probe(void);
54ae115bc7Smrj static int mps_find_bus_res(int, int, struct memlist **);
55ae115bc7Smrj static void hrt_probe(void);
56ae115bc7Smrj static int hrt_find_bus_res(int, int, struct memlist **);
578fc7923fSDana Myers static int acpi_find_bus_res(int, int, struct memlist **);
58ae115bc7Smrj static uchar_t *find_sig(uchar_t *cp, int len, char *sig);
59ae115bc7Smrj static int checksum(unsigned char *cp, int len);
608fc7923fSDana Myers static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context);
618fc7923fSDana Myers void bus_res_fini(void);
62eaeab0c1SDana Myers static void acpi_trim_bus_ranges(void);
638fc7923fSDana Myers 
648fc7923fSDana Myers struct memlist *acpi_io_res[256];
658fc7923fSDana Myers struct memlist *acpi_mem_res[256];
668fc7923fSDana Myers struct memlist *acpi_pmem_res[256];
678fc7923fSDana Myers struct memlist *acpi_bus_res[256];
688fc7923fSDana Myers 
698fc7923fSDana Myers /*
708fc7923fSDana Myers  * -1 = attempt ACPI resource discovery
718fc7923fSDana Myers  *  0 = don't attempt ACPI resource discovery
728fc7923fSDana Myers  *  1 = ACPI resource discovery successful
738fc7923fSDana Myers  */
748fc7923fSDana Myers volatile int acpi_resource_discovery = -1;
75ae115bc7Smrj 
76ae115bc7Smrj struct memlist *
find_bus_res(int bus,int type)77ae115bc7Smrj find_bus_res(int bus, int type)
78ae115bc7Smrj {
79ae115bc7Smrj 	struct memlist *res = NULL;
80ae115bc7Smrj 
81ae115bc7Smrj 	if (tbl_init == 0) {
82ae115bc7Smrj 		tbl_init = 1;
838fc7923fSDana Myers 		acpi_pci_probe();
84ae115bc7Smrj 		hrt_probe();
85ae115bc7Smrj 		mps_probe();
86ae115bc7Smrj 	}
87ae115bc7Smrj 
888fc7923fSDana Myers 	if (acpi_find_bus_res(bus, type, &res) > 0)
898fc7923fSDana Myers 		return (res);
908fc7923fSDana Myers 
91ae115bc7Smrj 	if (hrt_find_bus_res(bus, type, &res) > 0)
92ae115bc7Smrj 		return (res);
93ae115bc7Smrj 
94ae115bc7Smrj 	(void) mps_find_bus_res(bus, type, &res);
95ae115bc7Smrj 	return (res);
96ae115bc7Smrj }
97ae115bc7Smrj 
988fc7923fSDana Myers 
998fc7923fSDana Myers static void
acpi_pci_probe(void)1008fc7923fSDana Myers acpi_pci_probe(void)
1018fc7923fSDana Myers {
1028fc7923fSDana Myers 	ACPI_HANDLE ah;
1038fc7923fSDana Myers 	dev_info_t *dip;
1048fc7923fSDana Myers 	int bus;
1058fc7923fSDana Myers 
1068fc7923fSDana Myers 	if (acpi_resource_discovery == 0)
1078fc7923fSDana Myers 		return;
1088fc7923fSDana Myers 
10947310cedSDana Myers 	for (bus = 0; bus <= pci_bios_maxbus; bus++) {
1108fc7923fSDana Myers 		/* if no dip or no ACPI handle, no resources to discover */
1118fc7923fSDana Myers 		dip = pci_bus_res[bus].dip;
1128fc7923fSDana Myers 		if ((dip == NULL) ||
1138fc7923fSDana Myers 		    (ACPI_FAILURE(acpica_get_handle(dip, &ah))))
1148fc7923fSDana Myers 			continue;
1158fc7923fSDana Myers 
1168fc7923fSDana Myers 		(void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb,
1178fc7923fSDana Myers 		    (void *)(uintptr_t)bus);
1188fc7923fSDana Myers 	}
1198fc7923fSDana Myers 
120eaeab0c1SDana Myers 	if (acpi_cb_cnt > 0) {
1218fc7923fSDana Myers 		acpi_resource_discovery = 1;
122eaeab0c1SDana Myers 		acpi_trim_bus_ranges();
123eaeab0c1SDana Myers 	}
124eaeab0c1SDana Myers }
125eaeab0c1SDana Myers 
126eaeab0c1SDana Myers /*
127eaeab0c1SDana Myers  * Trim overlapping bus ranges in acpi_bus_res[]
128eaeab0c1SDana Myers  * Some BIOSes report root-bridges with bus ranges that
129eaeab0c1SDana Myers  * overlap, for example:"0..255" and "8..255". Lower-numbered
130eaeab0c1SDana Myers  * ranges are trimmed by upper-numbered ranges (so "0..255" would
131eaeab0c1SDana Myers  * be trimmed to "0..7", in the example).
132eaeab0c1SDana Myers  */
133eaeab0c1SDana Myers static void
acpi_trim_bus_ranges()134eaeab0c1SDana Myers acpi_trim_bus_ranges()
135eaeab0c1SDana Myers {
136eaeab0c1SDana Myers 	struct memlist *ranges, *current;
137eaeab0c1SDana Myers 	int bus;
138eaeab0c1SDana Myers 
139eaeab0c1SDana Myers 	ranges = NULL;
140eaeab0c1SDana Myers 
141eaeab0c1SDana Myers 	/*
142eaeab0c1SDana Myers 	 * Assumptions:
143eaeab0c1SDana Myers 	 *  - there exists at most 1 bus range entry for each bus number
144eaeab0c1SDana Myers 	 *  - there are no (broken) ranges that start at the same bus number
145eaeab0c1SDana Myers 	 */
146eaeab0c1SDana Myers 	for (bus = 0; bus < 256; bus++) {
147eaeab0c1SDana Myers 		struct memlist *prev, *orig, *new;
148eaeab0c1SDana Myers 		/* skip buses with no range entry */
149eaeab0c1SDana Myers 		if ((orig = acpi_bus_res[bus]) == NULL)
150eaeab0c1SDana Myers 			continue;
151eaeab0c1SDana Myers 
152eaeab0c1SDana Myers 		/*
153eaeab0c1SDana Myers 		 * create copy of existing range and overload
154eaeab0c1SDana Myers 		 * 'prev' pointer to link existing to new copy
155eaeab0c1SDana Myers 		 */
156eaeab0c1SDana Myers 		new = memlist_alloc();
15756f33205SJonathan Adams 		new->ml_address = orig->ml_address;
15856f33205SJonathan Adams 		new->ml_size = orig->ml_size;
15956f33205SJonathan Adams 		new->ml_prev = orig;
160eaeab0c1SDana Myers 
161eaeab0c1SDana Myers 		/* sorted insertion of 'new' into ranges list */
162eaeab0c1SDana Myers 		for (current = ranges, prev = NULL; current != NULL;
16356f33205SJonathan Adams 		    prev = current, current = current->ml_next)
16456f33205SJonathan Adams 			if (new->ml_address < current->ml_address)
165eaeab0c1SDana Myers 				break;
166eaeab0c1SDana Myers 
167eaeab0c1SDana Myers 		if (prev == NULL) {
168eaeab0c1SDana Myers 			/* place at beginning of (possibly) empty list */
16956f33205SJonathan Adams 			new->ml_next = ranges;
170eaeab0c1SDana Myers 			ranges = new;
171eaeab0c1SDana Myers 		} else {
172eaeab0c1SDana Myers 			/* place in list (possibly at end) */
17356f33205SJonathan Adams 			new->ml_next = current;
17456f33205SJonathan Adams 			prev->ml_next = new;
175eaeab0c1SDana Myers 		}
176eaeab0c1SDana Myers 	}
177eaeab0c1SDana Myers 
178eaeab0c1SDana Myers 	/* scan the list, perform trimming */
179eaeab0c1SDana Myers 	current = ranges;
180eaeab0c1SDana Myers 	while (current != NULL) {
18156f33205SJonathan Adams 		struct memlist *next = current->ml_next;
182eaeab0c1SDana Myers 
183eaeab0c1SDana Myers 		/* done when no range above current */
184eaeab0c1SDana Myers 		if (next == NULL)
185eaeab0c1SDana Myers 			break;
186eaeab0c1SDana Myers 
187eaeab0c1SDana Myers 		/*
188eaeab0c1SDana Myers 		 * trim size in original range element
18956f33205SJonathan Adams 		 * (current->ml_prev points to the original range)
190eaeab0c1SDana Myers 		 */
19156f33205SJonathan Adams 		if ((current->ml_address + current->ml_size) > next->ml_address)
19256f33205SJonathan Adams 			current->ml_prev->ml_size =
19356f33205SJonathan Adams 			    next->ml_address - current->ml_address;
194eaeab0c1SDana Myers 
195eaeab0c1SDana Myers 		current = next;
196eaeab0c1SDana Myers 	}
197eaeab0c1SDana Myers 
198eaeab0c1SDana Myers 	/* discard the list */
199eaeab0c1SDana Myers 	memlist_free_all(&ranges);	/* OK if ranges == NULL */
2008fc7923fSDana Myers }
2018fc7923fSDana Myers 
2028fc7923fSDana Myers static int
acpi_find_bus_res(int bus,int type,struct memlist ** res)2038fc7923fSDana Myers acpi_find_bus_res(int bus, int type, struct memlist **res)
2048fc7923fSDana Myers {
2058fc7923fSDana Myers 
2068fc7923fSDana Myers 	switch (type) {
2078fc7923fSDana Myers 	case IO_TYPE:
2088fc7923fSDana Myers 		*res = acpi_io_res[bus];
2098fc7923fSDana Myers 		break;
2108fc7923fSDana Myers 	case MEM_TYPE:
2118fc7923fSDana Myers 		*res = acpi_mem_res[bus];
2128fc7923fSDana Myers 		break;
2138fc7923fSDana Myers 	case PREFETCH_TYPE:
2148fc7923fSDana Myers 		*res = acpi_pmem_res[bus];
2158fc7923fSDana Myers 		break;
2168fc7923fSDana Myers 	case BUSRANGE_TYPE:
2178fc7923fSDana Myers 		*res = acpi_bus_res[bus];
2188fc7923fSDana Myers 		break;
2198fc7923fSDana Myers 	default:
2208fc7923fSDana Myers 		*res = NULL;
2218fc7923fSDana Myers 		break;
2228fc7923fSDana Myers 	}
2238fc7923fSDana Myers 
2248fc7923fSDana Myers 	/* memlist_count() treats NULL head as zero-length */
2258fc7923fSDana Myers 	return (memlist_count(*res));
2268fc7923fSDana Myers }
2278fc7923fSDana Myers 
2288fc7923fSDana Myers void
bus_res_fini(void)2298fc7923fSDana Myers bus_res_fini(void)
2308fc7923fSDana Myers {
2318fc7923fSDana Myers 	int bus;
2328fc7923fSDana Myers 
23347310cedSDana Myers 	for (bus = 0; bus <= pci_bios_maxbus; bus++) {
2348fc7923fSDana Myers 		memlist_free_all(&acpi_io_res[bus]);
2358fc7923fSDana Myers 		memlist_free_all(&acpi_mem_res[bus]);
2368fc7923fSDana Myers 		memlist_free_all(&acpi_pmem_res[bus]);
2378fc7923fSDana Myers 		memlist_free_all(&acpi_bus_res[bus]);
2388fc7923fSDana Myers 	}
2398fc7923fSDana Myers }
2408fc7923fSDana Myers 
2418fc7923fSDana Myers 
2428fc7923fSDana Myers struct memlist **
rlistpp(UINT8 t,UINT8 flags,int bus)2438fc7923fSDana Myers rlistpp(UINT8 t, UINT8 flags, int bus)
2448fc7923fSDana Myers {
2458fc7923fSDana Myers 	switch (t) {
2468fc7923fSDana Myers 
2478fc7923fSDana Myers 		case ACPI_MEMORY_RANGE:
2488fc7923fSDana Myers 			/* is this really the best we've got? */
2498fc7923fSDana Myers 			if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY)
2508fc7923fSDana Myers 				return (&acpi_pmem_res[bus]);
2518fc7923fSDana Myers 			else
2528fc7923fSDana Myers 				return (&acpi_mem_res[bus]);
2538fc7923fSDana Myers 
2548fc7923fSDana Myers 		case ACPI_IO_RANGE:	return &acpi_io_res[bus];
2558fc7923fSDana Myers 		case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus];
2568fc7923fSDana Myers 	}
2578fc7923fSDana Myers 	return ((struct memlist **)NULL);
2588fc7923fSDana Myers }
2598fc7923fSDana Myers 
2608fc7923fSDana Myers 
2618fc7923fSDana Myers ACPI_STATUS
acpi_wr_cb(ACPI_RESOURCE * rp,void * context)2628fc7923fSDana Myers acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
2638fc7923fSDana Myers {
2648fc7923fSDana Myers 	int bus = (intptr_t)context;
2658fc7923fSDana Myers 
2668fc7923fSDana Myers 	/* ignore consumed resources */
2678fc7923fSDana Myers 	if (rp->Data.Address.ProducerConsumer == 1)
2688fc7923fSDana Myers 		return (AE_OK);
2698fc7923fSDana Myers 
2708fc7923fSDana Myers 	switch (rp->Type) {
2718fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_IRQ:
2728fc7923fSDana Myers 		/* never expect to see a PCI bus produce an Interrupt */
2738fc7923fSDana Myers 		dprintf("%s\n", "IRQ");
2748fc7923fSDana Myers 		break;
2758fc7923fSDana Myers 
2768fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_DMA:
2778fc7923fSDana Myers 		/* never expect to see a PCI bus produce DMA */
2788fc7923fSDana Myers 		dprintf("%s\n", "DMA");
2798fc7923fSDana Myers 		break;
2808fc7923fSDana Myers 
2818fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2828fc7923fSDana Myers 		dprintf("%s\n", "START_DEPENDENT");
2838fc7923fSDana Myers 		break;
2848fc7923fSDana Myers 
2858fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2868fc7923fSDana Myers 		dprintf("%s\n", "END_DEPENDENT");
2878fc7923fSDana Myers 		break;
2888fc7923fSDana Myers 
2898fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_IO:
2908fc7923fSDana Myers 		if (rp->Data.Io.AddressLength == 0)
2918fc7923fSDana Myers 			break;
2928fc7923fSDana Myers 		acpi_cb_cnt++;
2938fc7923fSDana Myers 		memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum,
2948fc7923fSDana Myers 		    rp->Data.Io.AddressLength);
2958fc7923fSDana Myers 		break;
2968fc7923fSDana Myers 
2978fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_FIXED_IO:
2988fc7923fSDana Myers 		/* only expect to see this as a consumer */
2998fc7923fSDana Myers 		dprintf("%s\n", "FIXED_IO");
3008fc7923fSDana Myers 		break;
3018fc7923fSDana Myers 
3028fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_VENDOR:
3038fc7923fSDana Myers 		dprintf("%s\n", "VENDOR");
3048fc7923fSDana Myers 		break;
3058fc7923fSDana Myers 
3068fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_END_TAG:
3078fc7923fSDana Myers 		dprintf("%s\n", "END_TAG");
3088fc7923fSDana Myers 		break;
3098fc7923fSDana Myers 
3108fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_MEMORY24:
3118fc7923fSDana Myers 		/* only expect to see this as a consumer */
3128fc7923fSDana Myers 		dprintf("%s\n", "MEMORY24");
3138fc7923fSDana Myers 		break;
3148fc7923fSDana Myers 
3158fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_MEMORY32:
3168fc7923fSDana Myers 		/* only expect to see this as a consumer */
3178fc7923fSDana Myers 		dprintf("%s\n", "MEMORY32");
3188fc7923fSDana Myers 		break;
3198fc7923fSDana Myers 
3208fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
3218fc7923fSDana Myers 		/* only expect to see this as a consumer */
3228fc7923fSDana Myers 		dprintf("%s\n", "FIXED_MEMORY32");
3238fc7923fSDana Myers 		break;
3248fc7923fSDana Myers 
3258fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_ADDRESS16:
326de5d74c2SJerry Jelinek 		if (rp->Data.Address16.Address.AddressLength == 0)
3278fc7923fSDana Myers 			break;
3288fc7923fSDana Myers 		acpi_cb_cnt++;
3298fc7923fSDana Myers 		memlist_insert(rlistpp(rp->Data.Address16.ResourceType,
3308fc7923fSDana Myers 		    rp->Data.Address16.Info.TypeSpecific, bus),
331de5d74c2SJerry Jelinek 		    rp->Data.Address16.Address.Minimum,
332de5d74c2SJerry Jelinek 		    rp->Data.Address16.Address.AddressLength);
3338fc7923fSDana Myers 		break;
3348fc7923fSDana Myers 
3358fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_ADDRESS32:
336de5d74c2SJerry Jelinek 		if (rp->Data.Address32.Address.AddressLength == 0)
3378fc7923fSDana Myers 			break;
3388fc7923fSDana Myers 		acpi_cb_cnt++;
3398fc7923fSDana Myers 		memlist_insert(rlistpp(rp->Data.Address32.ResourceType,
3408fc7923fSDana Myers 		    rp->Data.Address32.Info.TypeSpecific, bus),
341de5d74c2SJerry Jelinek 		    rp->Data.Address32.Address.Minimum,
342de5d74c2SJerry Jelinek 		    rp->Data.Address32.Address.AddressLength);
3438fc7923fSDana Myers 		break;
3448fc7923fSDana Myers 
3458fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_ADDRESS64:
3468d947747SGuoli Shu 	/*
3478d947747SGuoli Shu 	 * We comment out this block because we currently cannot deal with
3488d947747SGuoli Shu 	 * PCI 64-bit addresses. Will revisit this when we add PCI 64-bit MMIO
3498d947747SGuoli Shu 	 * support.
3508d947747SGuoli Shu 	 */
3518d947747SGuoli Shu #if 0
3528fc7923fSDana Myers 		if (rp->Data.Address64.AddressLength == 0)
3538fc7923fSDana Myers 			break;
3548fc7923fSDana Myers 		acpi_cb_cnt++;
3558fc7923fSDana Myers 		memlist_insert(rlistpp(rp->Data.Address64.ResourceType,
3568fc7923fSDana Myers 		    rp->Data.Address64.Info.TypeSpecific, bus),
3578fc7923fSDana Myers 		    rp->Data.Address64.Minimum,
3588fc7923fSDana Myers 		    rp->Data.Address64.AddressLength);
3598d947747SGuoli Shu #endif
3608fc7923fSDana Myers 		break;
3618fc7923fSDana Myers 
3628fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
3638d947747SGuoli Shu #if 0	/* Will revisit this when we add PCI 64-bit MMIO support */
3648fc7923fSDana Myers 		if (rp->Data.ExtAddress64.AddressLength == 0)
3658fc7923fSDana Myers 			break;
3668fc7923fSDana Myers 		acpi_cb_cnt++;
3678fc7923fSDana Myers 		memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType,
3688fc7923fSDana Myers 		    rp->Data.ExtAddress64.Info.TypeSpecific, bus),
3698fc7923fSDana Myers 		    rp->Data.ExtAddress64.Minimum,
3708fc7923fSDana Myers 		    rp->Data.ExtAddress64.AddressLength);
3718d947747SGuoli Shu #endif
3728fc7923fSDana Myers 		break;
3738fc7923fSDana Myers 
3748fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
3758fc7923fSDana Myers 		/* never expect to see a PCI bus produce an Interrupt */
3768fc7923fSDana Myers 		dprintf("%s\n", "EXTENDED_IRQ");
3778fc7923fSDana Myers 		break;
3788fc7923fSDana Myers 
3798fc7923fSDana Myers 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
3808fc7923fSDana Myers 		/* never expect to see a PCI bus produce an GAS */
3818fc7923fSDana Myers 		dprintf("%s\n", "GENERIC_REGISTER");
3828fc7923fSDana Myers 		break;
3838fc7923fSDana Myers 	}
3848fc7923fSDana Myers 
3858fc7923fSDana Myers 	return (AE_OK);
3868fc7923fSDana Myers }
3878fc7923fSDana Myers 
388ae115bc7Smrj static void
mps_probe()389ae115bc7Smrj mps_probe()
390ae115bc7Smrj {
391ae115bc7Smrj 	uchar_t *extp;
392ae115bc7Smrj 	struct mps_fps_hdr *fpp = NULL;
393ae115bc7Smrj 	struct mps_ct_hdr *ctp;
394ae115bc7Smrj 	uintptr_t ebda_start, base_end;
395ae115bc7Smrj 	ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
396ae115bc7Smrj 
397ae115bc7Smrj 	base_size = *((ushort_t *)(0x413));
398ae115bc7Smrj 	ebda_seg = *((ushort_t *)(0x40e));
399ae115bc7Smrj 	ebda_start = ((uint32_t)ebda_seg) << 4;
400ae115bc7Smrj 	if (ebda_seg != 0) {
401ae115bc7Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
402ae115bc7Smrj 		    (uchar_t *)ebda_start, 1024, "_MP_");
403ae115bc7Smrj 	}
404ae115bc7Smrj 	if (fpp == NULL) {
405ae115bc7Smrj 		base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
406ae115bc7Smrj 		if (base_end_seg != ebda_seg) {
407ae115bc7Smrj 			base_end = ((uintptr_t)base_end_seg) << 4;
408ae115bc7Smrj 			fpp = (struct mps_fps_hdr *)find_sig(
409ae115bc7Smrj 			    (uchar_t *)base_end, 1024, "_MP_");
410ae115bc7Smrj 		}
411ae115bc7Smrj 	}
412ae115bc7Smrj 	if (fpp == NULL) {
413ae115bc7Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
414ae115bc7Smrj 		    (uchar_t *)0xF0000, 0x10000, "_MP_");
415ae115bc7Smrj 	}
416ae115bc7Smrj 
417ae115bc7Smrj 	if (fpp == NULL) {
418ae115bc7Smrj 		dprintf("MP Spec table doesn't exist");
419ae115bc7Smrj 		return;
420ae115bc7Smrj 	} else {
421ae115bc7Smrj 		dprintf("Found MP Floating Pointer Structure at %p\n",
422ae115bc7Smrj 		    (void *)fpp);
423ae115bc7Smrj 	}
424ae115bc7Smrj 
425ae115bc7Smrj 	if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
426ae115bc7Smrj 		dprintf("MP Floating Pointer Structure checksum error");
427ae115bc7Smrj 		return;
428ae115bc7Smrj 	}
429ae115bc7Smrj 
430ae115bc7Smrj 	ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
431ae115bc7Smrj 	if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
432ae115bc7Smrj 		dprintf("MP Configuration Table signature is wrong");
433ae115bc7Smrj 		return;
434ae115bc7Smrj 	}
435ae115bc7Smrj 
436ae115bc7Smrj 	base_len = ctp->ct_len;
437ae115bc7Smrj 	if (checksum((uchar_t *)ctp, base_len) != 0) {
438ae115bc7Smrj 		dprintf("MP Configuration Table checksum error");
439ae115bc7Smrj 		return;
440ae115bc7Smrj 	}
441ae115bc7Smrj 	if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
442ae115bc7Smrj 		dprintf("MP Spec 1.1 found - extended table doesn't exist");
443ae115bc7Smrj 		return;
444ae115bc7Smrj 	}
445ae115bc7Smrj 	if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
446ae115bc7Smrj 		dprintf("MP Spec 1.4 found - extended table doesn't exist");
447ae115bc7Smrj 		return;
448ae115bc7Smrj 	}
449ae115bc7Smrj 	extp = (uchar_t *)ctp + base_len;
450ae115bc7Smrj 	if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
451ae115bc7Smrj 		dprintf("MP Extended Table checksum error");
452ae115bc7Smrj 		return;
453ae115bc7Smrj 	}
454ae115bc7Smrj 	mps_extp = extp;
455ae115bc7Smrj 	mps_ext_endp = mps_extp + ext_len;
456ae115bc7Smrj }
457ae115bc7Smrj 
458ae115bc7Smrj 
459ae115bc7Smrj static int
mps_find_bus_res(int bus,int type,struct memlist ** res)460ae115bc7Smrj mps_find_bus_res(int bus, int type, struct memlist **res)
461ae115bc7Smrj {
462ae115bc7Smrj 	struct sasm *sasmp;
463ae115bc7Smrj 	uchar_t *extp;
464ae115bc7Smrj 	int res_cnt;
465ae115bc7Smrj 
466ae115bc7Smrj 	if (mps_extp == NULL)
467ae115bc7Smrj 		return (0);
468ae115bc7Smrj 	extp = mps_extp;
469ae115bc7Smrj 	res_cnt = 0;
470ae115bc7Smrj 	while (extp < mps_ext_endp) {
471ae115bc7Smrj 		switch (*extp) {
472ae115bc7Smrj 		case SYS_AS_MAPPING:
473ae115bc7Smrj 			sasmp = (struct sasm *)extp;
474ae115bc7Smrj 			if (((int)sasmp->sasm_as_type) == type &&
475ae115bc7Smrj 			    ((int)sasmp->sasm_bus_id) == bus) {
476*265a3f1dSRobert Mustacchi 				uint64_t base, len;
477*265a3f1dSRobert Mustacchi 
478*265a3f1dSRobert Mustacchi 				base = (uint64_t)sasmp->sasm_as_base |
479*265a3f1dSRobert Mustacchi 				    (uint64_t)sasmp->sasm_as_base_hi << 32;
480*265a3f1dSRobert Mustacchi 				len = (uint64_t)sasmp->sasm_as_len |
481*265a3f1dSRobert Mustacchi 				    (uint64_t)sasmp->sasm_as_len_hi << 32;
482*265a3f1dSRobert Mustacchi 				memlist_insert(res, base, len);
483ae115bc7Smrj 				res_cnt++;
484ae115bc7Smrj 			}
485ae115bc7Smrj 			extp += SYS_AS_MAPPING_SIZE;
486ae115bc7Smrj 			break;
487ae115bc7Smrj 		case BUS_HIERARCHY_DESC:
488ae115bc7Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
489ae115bc7Smrj 			break;
490ae115bc7Smrj 		case COMP_BUS_AS_MODIFIER:
491ae115bc7Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
492ae115bc7Smrj 			break;
493ae115bc7Smrj 		default:
494ae115bc7Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
495ae115bc7Smrj 			    " in BIOS Multiprocessor Spec table.",
496ae115bc7Smrj 			    *extp);
497ae115bc7Smrj 			while (*res) {
498ae115bc7Smrj 				struct memlist *tmp = *res;
49956f33205SJonathan Adams 				*res = tmp->ml_next;
500ae115bc7Smrj 				memlist_free(tmp);
501ae115bc7Smrj 			}
502ae115bc7Smrj 			return (0);
503ae115bc7Smrj 		}
504ae115bc7Smrj 	}
505ae115bc7Smrj 	return (res_cnt);
506ae115bc7Smrj }
507ae115bc7Smrj 
508ae115bc7Smrj static void
hrt_probe()509ae115bc7Smrj hrt_probe()
510ae115bc7Smrj {
511ae115bc7Smrj 	struct hrt_hdr *hrtp;
512ae115bc7Smrj 
513ae115bc7Smrj 	dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
514ae115bc7Smrj 	if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
515ae115bc7Smrj 	    0x10000, "$HRT")) == NULL) {
516ae115bc7Smrj 		dprintf("NO PCI Hot-Plug Resource Table");
517ae115bc7Smrj 		return;
518ae115bc7Smrj 	}
519ae115bc7Smrj 	dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
520ae115bc7Smrj 	if (hrtp->hrt_ver != 1) {
521ae115bc7Smrj 		dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
522ae115bc7Smrj 		return;
523ae115bc7Smrj 	}
524ae115bc7Smrj 	hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
525ae115bc7Smrj 	dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
526ae115bc7Smrj 	hrt_hpep = (struct php_entry *)(hrtp + 1);
527ae115bc7Smrj }
528ae115bc7Smrj 
529ae115bc7Smrj static int
hrt_find_bus_res(int bus,int type,struct memlist ** res)530ae115bc7Smrj hrt_find_bus_res(int bus, int type, struct memlist **res)
531ae115bc7Smrj {
532ae115bc7Smrj 	int res_cnt, i;
533ae115bc7Smrj 	struct php_entry *hpep;
534ae115bc7Smrj 
535ae115bc7Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0)
536ae115bc7Smrj 		return (0);
537ae115bc7Smrj 	hpep = hrt_hpep;
538ae115bc7Smrj 	res_cnt = 0;
539ae115bc7Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
540ae115bc7Smrj 		if (hpep->php_pri_bus != bus)
541ae115bc7Smrj 			continue;
542ae115bc7Smrj 		if (type == IO_TYPE) {
543ae115bc7Smrj 			if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
544ae115bc7Smrj 				continue;
545ae115bc7Smrj 			memlist_insert(res, (uint64_t)hpep->php_io_start,
546ae115bc7Smrj 			    (uint64_t)hpep->php_io_size);
547ae115bc7Smrj 			res_cnt++;
548ae115bc7Smrj 		} else if (type == MEM_TYPE) {
549ae115bc7Smrj 			if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
550ae115bc7Smrj 				continue;
551ae115bc7Smrj 			memlist_insert(res,
552ae115bc7Smrj 			    (uint64_t)(((int)hpep->php_mem_start) << 16),
553ae115bc7Smrj 			    (uint64_t)(((int)hpep->php_mem_size) << 16));
554ae115bc7Smrj 			res_cnt++;
555ae115bc7Smrj 		} else if (type == PREFETCH_TYPE) {
556ae115bc7Smrj 			if (hpep->php_pfmem_start == 0 ||
557ae115bc7Smrj 			    hpep->php_pfmem_size == 0)
558ae115bc7Smrj 				continue;
559ae115bc7Smrj 			memlist_insert(res,
560ae115bc7Smrj 			    (uint64_t)(((int)hpep->php_pfmem_start) << 16),
561ae115bc7Smrj 			    (uint64_t)(((int)hpep->php_pfmem_size) << 16));
562ae115bc7Smrj 			res_cnt++;
563ae115bc7Smrj 		}
564ae115bc7Smrj 	}
565ae115bc7Smrj 	return (res_cnt);
566ae115bc7Smrj }
567ae115bc7Smrj 
568ae115bc7Smrj static uchar_t *
find_sig(uchar_t * cp,int len,char * sig)569ae115bc7Smrj find_sig(uchar_t *cp, int len, char *sig)
570ae115bc7Smrj {
571ae115bc7Smrj 	long i;
572ae115bc7Smrj 
573ae115bc7Smrj 	/* Search for the "_MP_"  or "$HRT" signature */
574ae115bc7Smrj 	for (i = 0; i < len; i += 16) {
575ae115bc7Smrj 		if (cp[0] == sig[0] && cp[1] == sig[1] &&
576ae115bc7Smrj 		    cp[2] == sig[2] && cp[3] == sig[3])
577ae115bc7Smrj 			return (cp);
578ae115bc7Smrj 		cp += 16;
579ae115bc7Smrj 	}
580ae115bc7Smrj 	return (NULL);
581ae115bc7Smrj }
582ae115bc7Smrj 
583ae115bc7Smrj static int
checksum(unsigned char * cp,int len)584ae115bc7Smrj checksum(unsigned char *cp, int len)
585ae115bc7Smrj {
586ae115bc7Smrj 	int i;
587ae115bc7Smrj 	unsigned int cksum;
588ae115bc7Smrj 
589ae115bc7Smrj 	for (i = cksum = 0; i < len; i++)
590ae115bc7Smrj 		cksum += (unsigned int) *cp++;
591ae115bc7Smrj 
592ae115bc7Smrj 	return ((int)(cksum & 0xFF));
593ae115bc7Smrj }
594ae115bc7Smrj 
595ae115bc7Smrj #ifdef UNUSED_BUS_HIERARY_INFO
596ae115bc7Smrj 
597ae115bc7Smrj /*
598ae115bc7Smrj  * At this point, the bus hierarchy entries do not appear to
599ae115bc7Smrj  * provide anything we can't find out from PCI config space.
600ae115bc7Smrj  * The only interesting bit is the ISA bus number, which we
601ae115bc7Smrj  * don't care.
602ae115bc7Smrj  */
603ae115bc7Smrj int
mps_find_parent_bus(int bus)604ae115bc7Smrj mps_find_parent_bus(int bus)
605ae115bc7Smrj {
606ae115bc7Smrj 	struct sasm *sasmp;
607ae115bc7Smrj 	uchar_t *extp;
608ae115bc7Smrj 
609ae115bc7Smrj 	if (mps_extp == NULL)
610ae115bc7Smrj 		return (-1);
611ae115bc7Smrj 
612ae115bc7Smrj 	extp = mps_extp;
613ae115bc7Smrj 	while (extp < mps_ext_endp) {
614ae115bc7Smrj 		bhdp = (struct bhd *)extp;
615ae115bc7Smrj 		switch (*extp) {
616ae115bc7Smrj 		case SYS_AS_MAPPING:
617ae115bc7Smrj 			extp += SYS_AS_MAPPING_SIZE;
618ae115bc7Smrj 			break;
619ae115bc7Smrj 		case BUS_HIERARCHY_DESC:
620ae115bc7Smrj 			if (bhdp->bhd_bus_id == bus)
621ae115bc7Smrj 				return (bhdp->bhd_parent);
622ae115bc7Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
623ae115bc7Smrj 			break;
624ae115bc7Smrj 		case COMP_BUS_AS_MODIFIER:
625ae115bc7Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
626ae115bc7Smrj 			break;
627ae115bc7Smrj 		default:
628ae115bc7Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
629ae115bc7Smrj 			    " in BIOS Multiprocessor Spec table.",
630ae115bc7Smrj 			    *extp);
631ae115bc7Smrj 			return (-1);
632ae115bc7Smrj 		}
633ae115bc7Smrj 	}
634ae115bc7Smrj 	return (-1);
635ae115bc7Smrj }
636ae115bc7Smrj 
637ae115bc7Smrj int
hrt_find_bus_range(int bus)638ae115bc7Smrj hrt_find_bus_range(int bus)
639ae115bc7Smrj {
640ae115bc7Smrj 	int i, max_bus, sub_bus;
641ae115bc7Smrj 	struct php_entry *hpep;
642ae115bc7Smrj 
643ae115bc7Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
644ae115bc7Smrj 		return (-1);
645ae115bc7Smrj 	}
646ae115bc7Smrj 	hpep = hrt_hpep;
647ae115bc7Smrj 	max_bus = -1;
648ae115bc7Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
649ae115bc7Smrj 		if (hpep->php_pri_bus != bus)
650ae115bc7Smrj 			continue;
651ae115bc7Smrj 		sub_bus = (int)hpep->php_subord_bus;
652ae115bc7Smrj 		if (sub_bus > max_bus)
653ae115bc7Smrj 			max_bus = sub_bus;
654ae115bc7Smrj 	}
655ae115bc7Smrj 	return (max_bus);
656ae115bc7Smrj }
657ae115bc7Smrj 
658ae115bc7Smrj #endif /* UNUSED_BUS_HIERARY_INFO */
659