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