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