13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
5*8420SDana.Myers@Sun.COM  * Common Development and Distribution License (the "License").
6*8420SDana.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*8420SDana.Myers@Sun.COM  * Copyright 2008 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>
34*8420SDana.Myers@Sun.COM #include <sys/acpi/acpi.h>
35*8420SDana.Myers@Sun.COM #include <sys/acpica.h>
363446Smrj #include "mps_table.h"
373446Smrj #include "pcihrt.h"
383446Smrj 
393446Smrj extern int pci_boot_debug;
40*8420SDana.Myers@Sun.COM extern int pci_bios_nbus;
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;
48*8420SDana.Myers@Sun.COM static int acpi_cb_cnt = 0;
493446Smrj 
503446Smrj static void mps_probe(void);
51*8420SDana.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 **);
55*8420SDana.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);
58*8420SDana.Myers@Sun.COM static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context);
59*8420SDana.Myers@Sun.COM void bus_res_fini(void);
60*8420SDana.Myers@Sun.COM 
61*8420SDana.Myers@Sun.COM struct memlist *acpi_io_res[256];
62*8420SDana.Myers@Sun.COM struct memlist *acpi_mem_res[256];
63*8420SDana.Myers@Sun.COM struct memlist *acpi_pmem_res[256];
64*8420SDana.Myers@Sun.COM struct memlist *acpi_bus_res[256];
65*8420SDana.Myers@Sun.COM 
66*8420SDana.Myers@Sun.COM /*
67*8420SDana.Myers@Sun.COM  * -1 = attempt ACPI resource discovery
68*8420SDana.Myers@Sun.COM  *  0 = don't attempt ACPI resource discovery
69*8420SDana.Myers@Sun.COM  *  1 = ACPI resource discovery successful
70*8420SDana.Myers@Sun.COM  */
71*8420SDana.Myers@Sun.COM volatile int acpi_resource_discovery = -1;
723446Smrj 
733446Smrj struct memlist *
743446Smrj find_bus_res(int bus, int type)
753446Smrj {
763446Smrj 	struct memlist *res = NULL;
773446Smrj 
783446Smrj 	if (tbl_init == 0) {
793446Smrj 		tbl_init = 1;
80*8420SDana.Myers@Sun.COM 		acpi_pci_probe();
813446Smrj 		hrt_probe();
823446Smrj 		mps_probe();
833446Smrj 	}
843446Smrj 
85*8420SDana.Myers@Sun.COM 	if (acpi_find_bus_res(bus, type, &res) > 0)
86*8420SDana.Myers@Sun.COM 		return (res);
87*8420SDana.Myers@Sun.COM 
883446Smrj 	if (hrt_find_bus_res(bus, type, &res) > 0)
893446Smrj 		return (res);
903446Smrj 
913446Smrj 	(void) mps_find_bus_res(bus, type, &res);
923446Smrj 	return (res);
933446Smrj }
943446Smrj 
95*8420SDana.Myers@Sun.COM 
96*8420SDana.Myers@Sun.COM static void
97*8420SDana.Myers@Sun.COM acpi_pci_probe(void)
98*8420SDana.Myers@Sun.COM {
99*8420SDana.Myers@Sun.COM 	ACPI_HANDLE ah;
100*8420SDana.Myers@Sun.COM 	dev_info_t *dip;
101*8420SDana.Myers@Sun.COM 	int bus;
102*8420SDana.Myers@Sun.COM 
103*8420SDana.Myers@Sun.COM 	if (acpi_resource_discovery == 0)
104*8420SDana.Myers@Sun.COM 		return;
105*8420SDana.Myers@Sun.COM 
106*8420SDana.Myers@Sun.COM 	for (bus = 0; bus < pci_bios_nbus; bus++) {
107*8420SDana.Myers@Sun.COM 		/* if no dip or no ACPI handle, no resources to discover */
108*8420SDana.Myers@Sun.COM 		dip = pci_bus_res[bus].dip;
109*8420SDana.Myers@Sun.COM 		if ((dip == NULL) ||
110*8420SDana.Myers@Sun.COM 		    (ACPI_FAILURE(acpica_get_handle(dip, &ah))))
111*8420SDana.Myers@Sun.COM 			continue;
112*8420SDana.Myers@Sun.COM 
113*8420SDana.Myers@Sun.COM 		(void) AcpiWalkResources(ah, "_CRS", acpi_wr_cb,
114*8420SDana.Myers@Sun.COM 		    (void *)(uintptr_t)bus);
115*8420SDana.Myers@Sun.COM 	}
116*8420SDana.Myers@Sun.COM 
117*8420SDana.Myers@Sun.COM 	if (acpi_cb_cnt > 0)
118*8420SDana.Myers@Sun.COM 		acpi_resource_discovery = 1;
119*8420SDana.Myers@Sun.COM }
120*8420SDana.Myers@Sun.COM 
121*8420SDana.Myers@Sun.COM static int
122*8420SDana.Myers@Sun.COM acpi_find_bus_res(int bus, int type, struct memlist **res)
123*8420SDana.Myers@Sun.COM {
124*8420SDana.Myers@Sun.COM 
125*8420SDana.Myers@Sun.COM 	switch (type) {
126*8420SDana.Myers@Sun.COM 	case IO_TYPE:
127*8420SDana.Myers@Sun.COM 		*res = acpi_io_res[bus];
128*8420SDana.Myers@Sun.COM 		break;
129*8420SDana.Myers@Sun.COM 	case MEM_TYPE:
130*8420SDana.Myers@Sun.COM 		*res = acpi_mem_res[bus];
131*8420SDana.Myers@Sun.COM 		break;
132*8420SDana.Myers@Sun.COM 	case PREFETCH_TYPE:
133*8420SDana.Myers@Sun.COM 		*res = acpi_pmem_res[bus];
134*8420SDana.Myers@Sun.COM 		break;
135*8420SDana.Myers@Sun.COM 	case BUSRANGE_TYPE:
136*8420SDana.Myers@Sun.COM 		*res = acpi_bus_res[bus];
137*8420SDana.Myers@Sun.COM 		break;
138*8420SDana.Myers@Sun.COM 	default:
139*8420SDana.Myers@Sun.COM 		*res = NULL;
140*8420SDana.Myers@Sun.COM 		break;
141*8420SDana.Myers@Sun.COM 	}
142*8420SDana.Myers@Sun.COM 
143*8420SDana.Myers@Sun.COM 	/* memlist_count() treats NULL head as zero-length */
144*8420SDana.Myers@Sun.COM 	return (memlist_count(*res));
145*8420SDana.Myers@Sun.COM }
146*8420SDana.Myers@Sun.COM 
147*8420SDana.Myers@Sun.COM void
148*8420SDana.Myers@Sun.COM bus_res_fini(void)
149*8420SDana.Myers@Sun.COM {
150*8420SDana.Myers@Sun.COM 	int bus;
151*8420SDana.Myers@Sun.COM 
152*8420SDana.Myers@Sun.COM 	for (bus = 0; bus < pci_bios_nbus; bus++) {
153*8420SDana.Myers@Sun.COM 		memlist_free_all(&acpi_io_res[bus]);
154*8420SDana.Myers@Sun.COM 		memlist_free_all(&acpi_mem_res[bus]);
155*8420SDana.Myers@Sun.COM 		memlist_free_all(&acpi_pmem_res[bus]);
156*8420SDana.Myers@Sun.COM 		memlist_free_all(&acpi_bus_res[bus]);
157*8420SDana.Myers@Sun.COM 	}
158*8420SDana.Myers@Sun.COM }
159*8420SDana.Myers@Sun.COM 
160*8420SDana.Myers@Sun.COM 
161*8420SDana.Myers@Sun.COM struct memlist **
162*8420SDana.Myers@Sun.COM rlistpp(UINT8 t, UINT8 flags, int bus)
163*8420SDana.Myers@Sun.COM {
164*8420SDana.Myers@Sun.COM 	switch (t) {
165*8420SDana.Myers@Sun.COM 
166*8420SDana.Myers@Sun.COM 		case ACPI_MEMORY_RANGE:
167*8420SDana.Myers@Sun.COM 			/* is this really the best we've got? */
168*8420SDana.Myers@Sun.COM 			if (((flags >> 1) & 0x3) == ACPI_PREFETCHABLE_MEMORY)
169*8420SDana.Myers@Sun.COM 				return (&acpi_pmem_res[bus]);
170*8420SDana.Myers@Sun.COM 			else
171*8420SDana.Myers@Sun.COM 				return (&acpi_mem_res[bus]);
172*8420SDana.Myers@Sun.COM 
173*8420SDana.Myers@Sun.COM 		case ACPI_IO_RANGE:	return &acpi_io_res[bus];
174*8420SDana.Myers@Sun.COM 		case ACPI_BUS_NUMBER_RANGE: return &acpi_bus_res[bus];
175*8420SDana.Myers@Sun.COM 	}
176*8420SDana.Myers@Sun.COM 	return ((struct memlist **)NULL);
177*8420SDana.Myers@Sun.COM }
178*8420SDana.Myers@Sun.COM 
179*8420SDana.Myers@Sun.COM 
180*8420SDana.Myers@Sun.COM ACPI_STATUS
181*8420SDana.Myers@Sun.COM acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
182*8420SDana.Myers@Sun.COM {
183*8420SDana.Myers@Sun.COM 	int bus = (intptr_t)context;
184*8420SDana.Myers@Sun.COM 
185*8420SDana.Myers@Sun.COM 	/* ignore consumed resources */
186*8420SDana.Myers@Sun.COM 	if (rp->Data.Address.ProducerConsumer == 1)
187*8420SDana.Myers@Sun.COM 		return (AE_OK);
188*8420SDana.Myers@Sun.COM 
189*8420SDana.Myers@Sun.COM 	switch (rp->Type) {
190*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_IRQ:
191*8420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce an Interrupt */
192*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "IRQ");
193*8420SDana.Myers@Sun.COM 		break;
194*8420SDana.Myers@Sun.COM 
195*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_DMA:
196*8420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce DMA */
197*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "DMA");
198*8420SDana.Myers@Sun.COM 		break;
199*8420SDana.Myers@Sun.COM 
200*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
201*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "START_DEPENDENT");
202*8420SDana.Myers@Sun.COM 		break;
203*8420SDana.Myers@Sun.COM 
204*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
205*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "END_DEPENDENT");
206*8420SDana.Myers@Sun.COM 		break;
207*8420SDana.Myers@Sun.COM 
208*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_IO:
209*8420SDana.Myers@Sun.COM 		if (rp->Data.Io.AddressLength == 0)
210*8420SDana.Myers@Sun.COM 			break;
211*8420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
212*8420SDana.Myers@Sun.COM 		memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum,
213*8420SDana.Myers@Sun.COM 		    rp->Data.Io.AddressLength);
214*8420SDana.Myers@Sun.COM 		break;
215*8420SDana.Myers@Sun.COM 
216*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_FIXED_IO:
217*8420SDana.Myers@Sun.COM 		/* only expect to see this as a consumer */
218*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "FIXED_IO");
219*8420SDana.Myers@Sun.COM 		break;
220*8420SDana.Myers@Sun.COM 
221*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_VENDOR:
222*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "VENDOR");
223*8420SDana.Myers@Sun.COM 		break;
224*8420SDana.Myers@Sun.COM 
225*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_END_TAG:
226*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "END_TAG");
227*8420SDana.Myers@Sun.COM 		break;
228*8420SDana.Myers@Sun.COM 
229*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_MEMORY24:
230*8420SDana.Myers@Sun.COM 		/* only expect to see this as a consumer */
231*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "MEMORY24");
232*8420SDana.Myers@Sun.COM 		break;
233*8420SDana.Myers@Sun.COM 
234*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_MEMORY32:
235*8420SDana.Myers@Sun.COM 		/* only expect to see this as a consumer */
236*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "MEMORY32");
237*8420SDana.Myers@Sun.COM 		break;
238*8420SDana.Myers@Sun.COM 
239*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
240*8420SDana.Myers@Sun.COM 		/* only expect to see this as a consumer */
241*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "FIXED_MEMORY32");
242*8420SDana.Myers@Sun.COM 		break;
243*8420SDana.Myers@Sun.COM 
244*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_ADDRESS16:
245*8420SDana.Myers@Sun.COM 		if (rp->Data.Address16.AddressLength == 0)
246*8420SDana.Myers@Sun.COM 			break;
247*8420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
248*8420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.Address16.ResourceType,
249*8420SDana.Myers@Sun.COM 		    rp->Data.Address16.Info.TypeSpecific, bus),
250*8420SDana.Myers@Sun.COM 		    rp->Data.Address16.Minimum,
251*8420SDana.Myers@Sun.COM 		    rp->Data.Address16.AddressLength);
252*8420SDana.Myers@Sun.COM 		break;
253*8420SDana.Myers@Sun.COM 
254*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_ADDRESS32:
255*8420SDana.Myers@Sun.COM 		if (rp->Data.Address32.AddressLength == 0)
256*8420SDana.Myers@Sun.COM 			break;
257*8420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
258*8420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.Address32.ResourceType,
259*8420SDana.Myers@Sun.COM 		    rp->Data.Address32.Info.TypeSpecific, bus),
260*8420SDana.Myers@Sun.COM 		    rp->Data.Address32.Minimum,
261*8420SDana.Myers@Sun.COM 		    rp->Data.Address32.AddressLength);
262*8420SDana.Myers@Sun.COM 		break;
263*8420SDana.Myers@Sun.COM 
264*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_ADDRESS64:
265*8420SDana.Myers@Sun.COM 		if (rp->Data.Address64.AddressLength == 0)
266*8420SDana.Myers@Sun.COM 			break;
267*8420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
268*8420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.Address64.ResourceType,
269*8420SDana.Myers@Sun.COM 		    rp->Data.Address64.Info.TypeSpecific, bus),
270*8420SDana.Myers@Sun.COM 		    rp->Data.Address64.Minimum,
271*8420SDana.Myers@Sun.COM 		    rp->Data.Address64.AddressLength);
272*8420SDana.Myers@Sun.COM 		break;
273*8420SDana.Myers@Sun.COM 
274*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
275*8420SDana.Myers@Sun.COM 		if (rp->Data.ExtAddress64.AddressLength == 0)
276*8420SDana.Myers@Sun.COM 			break;
277*8420SDana.Myers@Sun.COM 		acpi_cb_cnt++;
278*8420SDana.Myers@Sun.COM 		memlist_insert(rlistpp(rp->Data.ExtAddress64.ResourceType,
279*8420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.Info.TypeSpecific, bus),
280*8420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.Minimum,
281*8420SDana.Myers@Sun.COM 		    rp->Data.ExtAddress64.AddressLength);
282*8420SDana.Myers@Sun.COM 		break;
283*8420SDana.Myers@Sun.COM 
284*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
285*8420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce an Interrupt */
286*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "EXTENDED_IRQ");
287*8420SDana.Myers@Sun.COM 		break;
288*8420SDana.Myers@Sun.COM 
289*8420SDana.Myers@Sun.COM 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
290*8420SDana.Myers@Sun.COM 		/* never expect to see a PCI bus produce an GAS */
291*8420SDana.Myers@Sun.COM 		dprintf("%s\n", "GENERIC_REGISTER");
292*8420SDana.Myers@Sun.COM 		break;
293*8420SDana.Myers@Sun.COM 	}
294*8420SDana.Myers@Sun.COM 
295*8420SDana.Myers@Sun.COM 	return (AE_OK);
296*8420SDana.Myers@Sun.COM }
297*8420SDana.Myers@Sun.COM 
2983446Smrj static void
2993446Smrj mps_probe()
3003446Smrj {
3013446Smrj 	uchar_t *extp;
3023446Smrj 	struct mps_fps_hdr *fpp = NULL;
3033446Smrj 	struct mps_ct_hdr *ctp;
3043446Smrj 	uintptr_t ebda_start, base_end;
3053446Smrj 	ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
3063446Smrj 
3073446Smrj 	base_size = *((ushort_t *)(0x413));
3083446Smrj 	ebda_seg = *((ushort_t *)(0x40e));
3093446Smrj 	ebda_start = ((uint32_t)ebda_seg) << 4;
3103446Smrj 	if (ebda_seg != 0) {
3113446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
3123446Smrj 		    (uchar_t *)ebda_start, 1024, "_MP_");
3133446Smrj 	}
3143446Smrj 	if (fpp == NULL) {
3153446Smrj 		base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
3163446Smrj 		if (base_end_seg != ebda_seg) {
3173446Smrj 			base_end = ((uintptr_t)base_end_seg) << 4;
3183446Smrj 			fpp = (struct mps_fps_hdr *)find_sig(
319*8420SDana.Myers@Sun.COM 			    (uchar_t *)base_end, 1024, "_MP_");
3203446Smrj 		}
3213446Smrj 	}
3223446Smrj 	if (fpp == NULL) {
3233446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
3243446Smrj 		    (uchar_t *)0xF0000, 0x10000, "_MP_");
3253446Smrj 	}
3263446Smrj 
3273446Smrj 	if (fpp == NULL) {
3283446Smrj 		dprintf("MP Spec table doesn't exist");
3293446Smrj 		return;
3303446Smrj 	} else {
3313446Smrj 		dprintf("Found MP Floating Pointer Structure at %p\n",
3323446Smrj 		    (void *)fpp);
3333446Smrj 	}
3343446Smrj 
3353446Smrj 	if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
3363446Smrj 		dprintf("MP Floating Pointer Structure checksum error");
3373446Smrj 		return;
3383446Smrj 	}
3393446Smrj 
3403446Smrj 	ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
3413446Smrj 	if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
3423446Smrj 		dprintf("MP Configuration Table signature is wrong");
3433446Smrj 		return;
3443446Smrj 	}
3453446Smrj 
3463446Smrj 	base_len = ctp->ct_len;
3473446Smrj 	if (checksum((uchar_t *)ctp, base_len) != 0) {
3483446Smrj 		dprintf("MP Configuration Table checksum error");
3493446Smrj 		return;
3503446Smrj 	}
3513446Smrj 	if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
3523446Smrj 		dprintf("MP Spec 1.1 found - extended table doesn't exist");
3533446Smrj 		return;
3543446Smrj 	}
3553446Smrj 	if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
3563446Smrj 		dprintf("MP Spec 1.4 found - extended table doesn't exist");
3573446Smrj 		return;
3583446Smrj 	}
3593446Smrj 	extp = (uchar_t *)ctp + base_len;
3603446Smrj 	if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
3613446Smrj 		dprintf("MP Extended Table checksum error");
3623446Smrj 		return;
3633446Smrj 	}
3643446Smrj 	mps_extp = extp;
3653446Smrj 	mps_ext_endp = mps_extp + ext_len;
3663446Smrj }
3673446Smrj 
3683446Smrj 
3693446Smrj static int
3703446Smrj mps_find_bus_res(int bus, int type, struct memlist **res)
3713446Smrj {
3723446Smrj 	struct sasm *sasmp;
3733446Smrj 	uchar_t *extp;
3743446Smrj 	int res_cnt;
3753446Smrj 
3763446Smrj 	if (mps_extp == NULL)
3773446Smrj 		return (0);
3783446Smrj 	extp = mps_extp;
3793446Smrj 	res_cnt = 0;
3803446Smrj 	while (extp < mps_ext_endp) {
3813446Smrj 		switch (*extp) {
3823446Smrj 		case SYS_AS_MAPPING:
3833446Smrj 			sasmp = (struct sasm *)extp;
3843446Smrj 			if (((int)sasmp->sasm_as_type) == type &&
3853446Smrj 			    ((int)sasmp->sasm_bus_id) == bus) {
3863446Smrj 				if (sasmp->sasm_as_base_hi != 0 ||
387*8420SDana.Myers@Sun.COM 				    sasmp->sasm_as_len_hi != 0) {
3883446Smrj 					printf("64 bits address space\n");
3893446Smrj 					extp += SYS_AS_MAPPING_SIZE;
3903446Smrj 					break;
3913446Smrj 				}
3923446Smrj 				memlist_insert(res,
3933446Smrj 				    (uint64_t)sasmp->sasm_as_base,
3943446Smrj 				    sasmp->sasm_as_len);
3953446Smrj 				res_cnt++;
3963446Smrj 			}
3973446Smrj 			extp += SYS_AS_MAPPING_SIZE;
3983446Smrj 			break;
3993446Smrj 		case BUS_HIERARCHY_DESC:
4003446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
4013446Smrj 			break;
4023446Smrj 		case COMP_BUS_AS_MODIFIER:
4033446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
4043446Smrj 			break;
4053446Smrj 		default:
4063446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
4073446Smrj 			    " in BIOS Multiprocessor Spec table.",
4083446Smrj 			    *extp);
4093446Smrj 			while (*res) {
4103446Smrj 				struct memlist *tmp = *res;
4113446Smrj 				*res = tmp->next;
4123446Smrj 				memlist_free(tmp);
4133446Smrj 			}
4143446Smrj 			return (0);
4153446Smrj 		}
4163446Smrj 	}
4173446Smrj 	return (res_cnt);
4183446Smrj }
4193446Smrj 
4203446Smrj static void
4213446Smrj hrt_probe()
4223446Smrj {
4233446Smrj 	struct hrt_hdr *hrtp;
4243446Smrj 
4253446Smrj 	dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
4263446Smrj 	if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
4273446Smrj 	    0x10000, "$HRT")) == NULL) {
4283446Smrj 		dprintf("NO PCI Hot-Plug Resource Table");
4293446Smrj 		return;
4303446Smrj 	}
4313446Smrj 	dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
4323446Smrj 	if (hrtp->hrt_ver != 1) {
4333446Smrj 		dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
4343446Smrj 		return;
4353446Smrj 	}
4363446Smrj 	hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
4373446Smrj 	dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
4383446Smrj 	hrt_hpep = (struct php_entry *)(hrtp + 1);
4393446Smrj }
4403446Smrj 
4413446Smrj static int
4423446Smrj hrt_find_bus_res(int bus, int type, struct memlist **res)
4433446Smrj {
4443446Smrj 	int res_cnt, i;
4453446Smrj 	struct php_entry *hpep;
4463446Smrj 
4473446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0)
4483446Smrj 		return (0);
4493446Smrj 	hpep = hrt_hpep;
4503446Smrj 	res_cnt = 0;
4513446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
4523446Smrj 		if (hpep->php_pri_bus != bus)
4533446Smrj 			continue;
4543446Smrj 		if (type == IO_TYPE) {
4553446Smrj 			if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
4563446Smrj 				continue;
4573446Smrj 			memlist_insert(res, (uint64_t)hpep->php_io_start,
4583446Smrj 			    (uint64_t)hpep->php_io_size);
4593446Smrj 			res_cnt++;
4603446Smrj 		} else if (type == MEM_TYPE) {
4613446Smrj 			if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
4623446Smrj 				continue;
4633446Smrj 			memlist_insert(res,
4643446Smrj 			    (uint64_t)(((int)hpep->php_mem_start) << 16),
4653446Smrj 			    (uint64_t)(((int)hpep->php_mem_size) << 16));
4663446Smrj 			res_cnt++;
4673446Smrj 		} else if (type == PREFETCH_TYPE) {
4683446Smrj 			if (hpep->php_pfmem_start == 0 ||
4693446Smrj 			    hpep->php_pfmem_size == 0)
4703446Smrj 				continue;
4713446Smrj 			memlist_insert(res,
4723446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_start) << 16),
4733446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_size) << 16));
4743446Smrj 			res_cnt++;
4753446Smrj 		}
4763446Smrj 	}
4773446Smrj 	return (res_cnt);
4783446Smrj }
4793446Smrj 
4803446Smrj static uchar_t *
4813446Smrj find_sig(uchar_t *cp, int len, char *sig)
4823446Smrj {
4833446Smrj 	long i;
4843446Smrj 
4853446Smrj 	/* Search for the "_MP_"  or "$HRT" signature */
4863446Smrj 	for (i = 0; i < len; i += 16) {
4873446Smrj 		if (cp[0] == sig[0] && cp[1] == sig[1] &&
4883446Smrj 		    cp[2] == sig[2] && cp[3] == sig[3])
4893446Smrj 			return (cp);
4903446Smrj 		cp += 16;
4913446Smrj 	}
4923446Smrj 	return (NULL);
4933446Smrj }
4943446Smrj 
4953446Smrj static int
4963446Smrj checksum(unsigned char *cp, int len)
4973446Smrj {
4983446Smrj 	int i;
4993446Smrj 	unsigned int cksum;
5003446Smrj 
5013446Smrj 	for (i = cksum = 0; i < len; i++)
5023446Smrj 		cksum += (unsigned int) *cp++;
5033446Smrj 
5043446Smrj 	return ((int)(cksum & 0xFF));
5053446Smrj }
5063446Smrj 
5073446Smrj #ifdef UNUSED_BUS_HIERARY_INFO
5083446Smrj 
5093446Smrj /*
5103446Smrj  * At this point, the bus hierarchy entries do not appear to
5113446Smrj  * provide anything we can't find out from PCI config space.
5123446Smrj  * The only interesting bit is the ISA bus number, which we
5133446Smrj  * don't care.
5143446Smrj  */
5153446Smrj int
5163446Smrj mps_find_parent_bus(int bus)
5173446Smrj {
5183446Smrj 	struct sasm *sasmp;
5193446Smrj 	uchar_t *extp;
5203446Smrj 
5213446Smrj 	if (mps_extp == NULL)
5223446Smrj 		return (-1);
5233446Smrj 
5243446Smrj 	extp = mps_extp;
5253446Smrj 	while (extp < mps_ext_endp) {
5263446Smrj 		bhdp = (struct bhd *)extp;
5273446Smrj 		switch (*extp) {
5283446Smrj 		case SYS_AS_MAPPING:
5293446Smrj 			extp += SYS_AS_MAPPING_SIZE;
5303446Smrj 			break;
5313446Smrj 		case BUS_HIERARCHY_DESC:
5323446Smrj 			if (bhdp->bhd_bus_id == bus)
5333446Smrj 				return (bhdp->bhd_parent);
5343446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
5353446Smrj 			break;
5363446Smrj 		case COMP_BUS_AS_MODIFIER:
5373446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
5383446Smrj 			break;
5393446Smrj 		default:
5403446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
5413446Smrj 			    " in BIOS Multiprocessor Spec table.",
5423446Smrj 			    *extp);
5433446Smrj 			return (-1);
5443446Smrj 		}
5453446Smrj 	}
5463446Smrj 	return (-1);
5473446Smrj }
5483446Smrj 
5493446Smrj int
5503446Smrj hrt_find_bus_range(int bus)
5513446Smrj {
5523446Smrj 	int i, max_bus, sub_bus;
5533446Smrj 	struct php_entry *hpep;
5543446Smrj 
5553446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
5563446Smrj 		return (-1);
5573446Smrj 	}
5583446Smrj 	hpep = hrt_hpep;
5593446Smrj 	max_bus = -1;
5603446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
5613446Smrj 		if (hpep->php_pri_bus != bus)
5623446Smrj 			continue;
5633446Smrj 		sub_bus = (int)hpep->php_subord_bus;
5643446Smrj 		if (sub_bus > max_bus)
5653446Smrj 			max_bus = sub_bus;
5663446Smrj 	}
5673446Smrj 	return (max_bus);
5683446Smrj }
5693446Smrj 
5703446Smrj #endif /* UNUSED_BUS_HIERARY_INFO */
571