1*3446Smrj /*
2*3446Smrj  * CDDL HEADER START
3*3446Smrj  *
4*3446Smrj  * The contents of this file are subject to the terms of the
5*3446Smrj  * Common Development and Distribution License, Version 1.0 only
6*3446Smrj  * (the "License").  You may not use this file except in compliance
7*3446Smrj  * with the License.
8*3446Smrj  *
9*3446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*3446Smrj  * or http://www.opensolaris.org/os/licensing.
11*3446Smrj  * See the License for the specific language governing permissions
12*3446Smrj  * and limitations under the License.
13*3446Smrj  *
14*3446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
15*3446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*3446Smrj  * If applicable, add the following below this CDDL HEADER, with the
17*3446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
18*3446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
19*3446Smrj  *
20*3446Smrj  * CDDL HEADER END
21*3446Smrj  */
22*3446Smrj /*
23*3446Smrj  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*3446Smrj  * Use is subject to license terms.
25*3446Smrj  *
26*3446Smrj  * pci_resource.c -- routines to retrieve available bus resources from
27*3446Smrj  *		 the MP Spec. Table and Hotplug Resource Table
28*3446Smrj  */
29*3446Smrj 
30*3446Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*3446Smrj 
32*3446Smrj #include <sys/types.h>
33*3446Smrj #include <sys/memlist.h>
34*3446Smrj #include <sys/pci_impl.h>
35*3446Smrj #include <sys/systm.h>
36*3446Smrj #include <sys/cmn_err.h>
37*3446Smrj #include "mps_table.h"
38*3446Smrj #include "pcihrt.h"
39*3446Smrj 
40*3446Smrj extern int pci_boot_debug;
41*3446Smrj #define	dprintf	if (pci_boot_debug) printf
42*3446Smrj 
43*3446Smrj static int tbl_init = 0;
44*3446Smrj static uchar_t *mps_extp = NULL;
45*3446Smrj static uchar_t *mps_ext_endp = NULL;
46*3446Smrj static struct php_entry *hrt_hpep;
47*3446Smrj static int hrt_entry_cnt = 0;
48*3446Smrj 
49*3446Smrj static void mps_probe(void);
50*3446Smrj static int mps_find_bus_res(int, int, struct memlist **);
51*3446Smrj static void hrt_probe(void);
52*3446Smrj static int hrt_find_bus_res(int, int, struct memlist **);
53*3446Smrj static uchar_t *find_sig(uchar_t *cp, int len, char *sig);
54*3446Smrj static int checksum(unsigned char *cp, int len);
55*3446Smrj 
56*3446Smrj struct memlist *
57*3446Smrj find_bus_res(int bus, int type)
58*3446Smrj {
59*3446Smrj 	struct memlist *res = NULL;
60*3446Smrj 
61*3446Smrj 	if (tbl_init == 0) {
62*3446Smrj 		tbl_init = 1;
63*3446Smrj 		hrt_probe();
64*3446Smrj 		mps_probe();
65*3446Smrj 	}
66*3446Smrj 
67*3446Smrj 	if (hrt_find_bus_res(bus, type, &res) > 0)
68*3446Smrj 		return (res);
69*3446Smrj 
70*3446Smrj 	(void) mps_find_bus_res(bus, type, &res);
71*3446Smrj 	return (res);
72*3446Smrj }
73*3446Smrj 
74*3446Smrj static void
75*3446Smrj mps_probe()
76*3446Smrj {
77*3446Smrj 	uchar_t *extp;
78*3446Smrj 	struct mps_fps_hdr *fpp = NULL;
79*3446Smrj 	struct mps_ct_hdr *ctp;
80*3446Smrj 	uintptr_t ebda_start, base_end;
81*3446Smrj 	ushort_t ebda_seg, base_size, ext_len, base_len, base_end_seg;
82*3446Smrj 
83*3446Smrj 	base_size = *((ushort_t *)(0x413));
84*3446Smrj 	ebda_seg = *((ushort_t *)(0x40e));
85*3446Smrj 	ebda_start = ((uint32_t)ebda_seg) << 4;
86*3446Smrj 	if (ebda_seg != 0) {
87*3446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
88*3446Smrj 		    (uchar_t *)ebda_start, 1024, "_MP_");
89*3446Smrj 	}
90*3446Smrj 	if (fpp == NULL) {
91*3446Smrj 		base_end_seg = (base_size > 512) ? 0x9FC0 : 0x7FC0;
92*3446Smrj 		if (base_end_seg != ebda_seg) {
93*3446Smrj 			base_end = ((uintptr_t)base_end_seg) << 4;
94*3446Smrj 			fpp = (struct mps_fps_hdr *)find_sig(
95*3446Smrj 				(uchar_t *)base_end, 1024, "_MP_");
96*3446Smrj 		}
97*3446Smrj 	}
98*3446Smrj 	if (fpp == NULL) {
99*3446Smrj 		fpp = (struct mps_fps_hdr *)find_sig(
100*3446Smrj 		    (uchar_t *)0xF0000, 0x10000, "_MP_");
101*3446Smrj 	}
102*3446Smrj 
103*3446Smrj 	if (fpp == NULL) {
104*3446Smrj 		dprintf("MP Spec table doesn't exist");
105*3446Smrj 		return;
106*3446Smrj 	} else {
107*3446Smrj 		dprintf("Found MP Floating Pointer Structure at %p\n",
108*3446Smrj 		    (void *)fpp);
109*3446Smrj 	}
110*3446Smrj 
111*3446Smrj 	if (checksum((uchar_t *)fpp, fpp->fps_len * 16) != 0) {
112*3446Smrj 		dprintf("MP Floating Pointer Structure checksum error");
113*3446Smrj 		return;
114*3446Smrj 	}
115*3446Smrj 
116*3446Smrj 	ctp = (struct mps_ct_hdr *)(uintptr_t)fpp->fps_mpct_paddr;
117*3446Smrj 	if (ctp->ct_sig != 0x504d4350) { /* check "PCMP" signature */
118*3446Smrj 		dprintf("MP Configuration Table signature is wrong");
119*3446Smrj 		return;
120*3446Smrj 	}
121*3446Smrj 
122*3446Smrj 	base_len = ctp->ct_len;
123*3446Smrj 	if (checksum((uchar_t *)ctp, base_len) != 0) {
124*3446Smrj 		dprintf("MP Configuration Table checksum error");
125*3446Smrj 		return;
126*3446Smrj 	}
127*3446Smrj 	if (ctp->ct_spec_rev != 4) { /* not MPSpec rev 1.4 */
128*3446Smrj 		dprintf("MP Spec 1.1 found - extended table doesn't exist");
129*3446Smrj 		return;
130*3446Smrj 	}
131*3446Smrj 	if ((ext_len = ctp->ct_ext_tbl_len) == 0) {
132*3446Smrj 		dprintf("MP Spec 1.4 found - extended table doesn't exist");
133*3446Smrj 		return;
134*3446Smrj 	}
135*3446Smrj 	extp = (uchar_t *)ctp + base_len;
136*3446Smrj 	if (((checksum(extp, ext_len) + ctp->ct_ext_cksum) & 0xFF) != 0) {
137*3446Smrj 		dprintf("MP Extended Table checksum error");
138*3446Smrj 		return;
139*3446Smrj 	}
140*3446Smrj 	mps_extp = extp;
141*3446Smrj 	mps_ext_endp = mps_extp + ext_len;
142*3446Smrj }
143*3446Smrj 
144*3446Smrj 
145*3446Smrj static int
146*3446Smrj mps_find_bus_res(int bus, int type, struct memlist **res)
147*3446Smrj {
148*3446Smrj 	struct sasm *sasmp;
149*3446Smrj 	uchar_t *extp;
150*3446Smrj 	int res_cnt;
151*3446Smrj 
152*3446Smrj 	if (mps_extp == NULL)
153*3446Smrj 		return (0);
154*3446Smrj 	extp = mps_extp;
155*3446Smrj 	res_cnt = 0;
156*3446Smrj 	while (extp < mps_ext_endp) {
157*3446Smrj 		switch (*extp) {
158*3446Smrj 		case SYS_AS_MAPPING:
159*3446Smrj 			sasmp = (struct sasm *)extp;
160*3446Smrj 			if (((int)sasmp->sasm_as_type) == type &&
161*3446Smrj 			    ((int)sasmp->sasm_bus_id) == bus) {
162*3446Smrj 				if (sasmp->sasm_as_base_hi != 0 ||
163*3446Smrj 					sasmp->sasm_as_len_hi != 0) {
164*3446Smrj 					printf("64 bits address space\n");
165*3446Smrj 					extp += SYS_AS_MAPPING_SIZE;
166*3446Smrj 					break;
167*3446Smrj 				}
168*3446Smrj 				memlist_insert(res,
169*3446Smrj 				    (uint64_t)sasmp->sasm_as_base,
170*3446Smrj 				    sasmp->sasm_as_len);
171*3446Smrj 				res_cnt++;
172*3446Smrj 			}
173*3446Smrj 			extp += SYS_AS_MAPPING_SIZE;
174*3446Smrj 			break;
175*3446Smrj 		case BUS_HIERARCHY_DESC:
176*3446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
177*3446Smrj 			break;
178*3446Smrj 		case COMP_BUS_AS_MODIFIER:
179*3446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
180*3446Smrj 			break;
181*3446Smrj 		default:
182*3446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
183*3446Smrj 			    " in BIOS Multiprocessor Spec table.",
184*3446Smrj 			    *extp);
185*3446Smrj 			while (*res) {
186*3446Smrj 				struct memlist *tmp = *res;
187*3446Smrj 				*res = tmp->next;
188*3446Smrj 				memlist_free(tmp);
189*3446Smrj 			}
190*3446Smrj 			return (0);
191*3446Smrj 		}
192*3446Smrj 	}
193*3446Smrj 	return (res_cnt);
194*3446Smrj }
195*3446Smrj 
196*3446Smrj static void
197*3446Smrj hrt_probe()
198*3446Smrj {
199*3446Smrj 	struct hrt_hdr *hrtp;
200*3446Smrj 
201*3446Smrj 	dprintf("search PCI Hot-Plug Resource Table starting at 0xF0000\n");
202*3446Smrj 	if ((hrtp = (struct hrt_hdr *)find_sig((uchar_t *)0xF0000,
203*3446Smrj 	    0x10000, "$HRT")) == NULL) {
204*3446Smrj 		dprintf("NO PCI Hot-Plug Resource Table");
205*3446Smrj 		return;
206*3446Smrj 	}
207*3446Smrj 	dprintf("Found PCI Hot-Plug Resource Table at %p\n", (void *)hrtp);
208*3446Smrj 	if (hrtp->hrt_ver != 1) {
209*3446Smrj 		dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
210*3446Smrj 		return;
211*3446Smrj 	}
212*3446Smrj 	hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
213*3446Smrj 	dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
214*3446Smrj 	hrt_hpep = (struct php_entry *)(hrtp + 1);
215*3446Smrj }
216*3446Smrj 
217*3446Smrj static int
218*3446Smrj hrt_find_bus_res(int bus, int type, struct memlist **res)
219*3446Smrj {
220*3446Smrj 	int res_cnt, i;
221*3446Smrj 	struct php_entry *hpep;
222*3446Smrj 
223*3446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0)
224*3446Smrj 		return (0);
225*3446Smrj 	hpep = hrt_hpep;
226*3446Smrj 	res_cnt = 0;
227*3446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
228*3446Smrj 		if (hpep->php_pri_bus != bus)
229*3446Smrj 			continue;
230*3446Smrj 		if (type == IO_TYPE) {
231*3446Smrj 			if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
232*3446Smrj 				continue;
233*3446Smrj 			memlist_insert(res, (uint64_t)hpep->php_io_start,
234*3446Smrj 			    (uint64_t)hpep->php_io_size);
235*3446Smrj 			res_cnt++;
236*3446Smrj 		} else if (type == MEM_TYPE) {
237*3446Smrj 			if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
238*3446Smrj 				continue;
239*3446Smrj 			memlist_insert(res,
240*3446Smrj 			    (uint64_t)(((int)hpep->php_mem_start) << 16),
241*3446Smrj 			    (uint64_t)(((int)hpep->php_mem_size) << 16));
242*3446Smrj 			res_cnt++;
243*3446Smrj 		} else if (type == PREFETCH_TYPE) {
244*3446Smrj 			if (hpep->php_pfmem_start == 0 ||
245*3446Smrj 			    hpep->php_pfmem_size == 0)
246*3446Smrj 				continue;
247*3446Smrj 			memlist_insert(res,
248*3446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_start) << 16),
249*3446Smrj 			    (uint64_t)(((int)hpep->php_pfmem_size) << 16));
250*3446Smrj 			res_cnt++;
251*3446Smrj 		}
252*3446Smrj 	}
253*3446Smrj 	return (res_cnt);
254*3446Smrj }
255*3446Smrj 
256*3446Smrj static uchar_t *
257*3446Smrj find_sig(uchar_t *cp, int len, char *sig)
258*3446Smrj {
259*3446Smrj 	long i;
260*3446Smrj 
261*3446Smrj 	/* Search for the "_MP_"  or "$HRT" signature */
262*3446Smrj 	for (i = 0; i < len; i += 16) {
263*3446Smrj 		if (cp[0] == sig[0] && cp[1] == sig[1] &&
264*3446Smrj 		    cp[2] == sig[2] && cp[3] == sig[3])
265*3446Smrj 			return (cp);
266*3446Smrj 		cp += 16;
267*3446Smrj 	}
268*3446Smrj 	return (NULL);
269*3446Smrj }
270*3446Smrj 
271*3446Smrj static int
272*3446Smrj checksum(unsigned char *cp, int len)
273*3446Smrj {
274*3446Smrj 	int i;
275*3446Smrj 	unsigned int cksum;
276*3446Smrj 
277*3446Smrj 	for (i = cksum = 0; i < len; i++)
278*3446Smrj 		cksum += (unsigned int) *cp++;
279*3446Smrj 
280*3446Smrj 	return ((int)(cksum & 0xFF));
281*3446Smrj }
282*3446Smrj 
283*3446Smrj #ifdef UNUSED_BUS_HIERARY_INFO
284*3446Smrj 
285*3446Smrj /*
286*3446Smrj  * At this point, the bus hierarchy entries do not appear to
287*3446Smrj  * provide anything we can't find out from PCI config space.
288*3446Smrj  * The only interesting bit is the ISA bus number, which we
289*3446Smrj  * don't care.
290*3446Smrj  */
291*3446Smrj int
292*3446Smrj mps_find_parent_bus(int bus)
293*3446Smrj {
294*3446Smrj 	struct sasm *sasmp;
295*3446Smrj 	uchar_t *extp;
296*3446Smrj 
297*3446Smrj 	if (mps_extp == NULL)
298*3446Smrj 		return (-1);
299*3446Smrj 
300*3446Smrj 	extp = mps_extp;
301*3446Smrj 	while (extp < mps_ext_endp) {
302*3446Smrj 		bhdp = (struct bhd *)extp;
303*3446Smrj 		switch (*extp) {
304*3446Smrj 		case SYS_AS_MAPPING:
305*3446Smrj 			extp += SYS_AS_MAPPING_SIZE;
306*3446Smrj 			break;
307*3446Smrj 		case BUS_HIERARCHY_DESC:
308*3446Smrj 			if (bhdp->bhd_bus_id == bus)
309*3446Smrj 				return (bhdp->bhd_parent);
310*3446Smrj 			extp += BUS_HIERARCHY_DESC_SIZE;
311*3446Smrj 			break;
312*3446Smrj 		case COMP_BUS_AS_MODIFIER:
313*3446Smrj 			extp += COMP_BUS_AS_MODIFIER_SIZE;
314*3446Smrj 			break;
315*3446Smrj 		default:
316*3446Smrj 			cmn_err(CE_WARN, "Unknown descriptor type %d"
317*3446Smrj 			    " in BIOS Multiprocessor Spec table.",
318*3446Smrj 			    *extp);
319*3446Smrj 			return (-1);
320*3446Smrj 		}
321*3446Smrj 	}
322*3446Smrj 	return (-1);
323*3446Smrj }
324*3446Smrj 
325*3446Smrj int
326*3446Smrj hrt_find_bus_range(int bus)
327*3446Smrj {
328*3446Smrj 	int i, max_bus, sub_bus;
329*3446Smrj 	struct php_entry *hpep;
330*3446Smrj 
331*3446Smrj 	if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
332*3446Smrj 		return (-1);
333*3446Smrj 	}
334*3446Smrj 	hpep = hrt_hpep;
335*3446Smrj 	max_bus = -1;
336*3446Smrj 	for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
337*3446Smrj 		if (hpep->php_pri_bus != bus)
338*3446Smrj 			continue;
339*3446Smrj 		sub_bus = (int)hpep->php_subord_bus;
340*3446Smrj 		if (sub_bus > max_bus)
341*3446Smrj 			max_bus = sub_bus;
342*3446Smrj 	}
343*3446Smrj 	return (max_bus);
344*3446Smrj }
345*3446Smrj 
346*3446Smrj #endif /* UNUSED_BUS_HIERARY_INFO */
347