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