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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/psm.h> 29 #include <sys/vmem.h> 30 #include <vm/hat.h> 31 #include <sys/modctl.h> 32 #include <vm/seg_kmem.h> 33 #define PSMI_1_5 34 #include <sys/psm.h> 35 #include <sys/psm_modctl.h> 36 #include <sys/smp_impldefs.h> 37 #include <sys/reboot.h> 38 39 /* 40 * External reference functions 41 */ 42 extern void *get_next_mach(void *, char *); 43 extern void close_mach_list(void); 44 extern void open_mach_list(void); 45 46 /* 47 * from startup.c - kernel VA range allocator for device mappings 48 */ 49 extern void *device_arena_alloc(size_t size, int vm_flag); 50 extern void device_arena_free(void * vaddr, size_t size); 51 52 void psm_modloadonly(void); 53 void psm_install(void); 54 55 /* 56 * Local Function Prototypes 57 */ 58 static struct modlinkage *psm_modlinkage_alloc(struct psm_info *infop); 59 static void psm_modlinkage_free(struct modlinkage *mlinkp); 60 61 static char *psm_get_impl_module(int first); 62 63 static int mod_installpsm(struct modlpsm *modl, struct modlinkage *modlp); 64 static int mod_removepsm(struct modlpsm *modl, struct modlinkage *modlp); 65 static int mod_infopsm(struct modlpsm *modl, struct modlinkage *modlp, int *p0); 66 struct mod_ops mod_psmops = { 67 mod_installpsm, mod_removepsm, mod_infopsm 68 }; 69 70 static struct psm_sw psm_swtab = { 71 &psm_swtab, &psm_swtab, NULL, NULL 72 }; 73 74 kmutex_t psmsw_lock; /* lock accesses to psmsw */ 75 struct psm_sw *psmsw = &psm_swtab; /* start of all psm_sw */ 76 77 static struct modlinkage * 78 psm_modlinkage_alloc(struct psm_info *infop) 79 { 80 int memsz; 81 struct modlinkage *mlinkp; 82 struct modlpsm *mlpsmp; 83 struct psm_sw *swp; 84 85 memsz = sizeof (struct modlinkage) + sizeof (struct modlpsm) + 86 sizeof (struct psm_sw); 87 mlinkp = (struct modlinkage *)kmem_zalloc(memsz, KM_NOSLEEP); 88 if (!mlinkp) { 89 cmn_err(CE_WARN, "!psm_mod_init: Cannot install %s", 90 infop->p_mach_idstring); 91 return (NULL); 92 } 93 mlpsmp = (struct modlpsm *)(mlinkp + 1); 94 swp = (struct psm_sw *)(mlpsmp + 1); 95 96 mlinkp->ml_rev = MODREV_1; 97 mlinkp->ml_linkage[0] = (void *)mlpsmp; 98 mlinkp->ml_linkage[1] = (void *)NULL; 99 100 mlpsmp->psm_modops = &mod_psmops; 101 mlpsmp->psm_linkinfo = infop->p_mach_desc; 102 mlpsmp->psm_swp = swp; 103 104 swp->psw_infop = infop; 105 106 return (mlinkp); 107 } 108 109 static void 110 psm_modlinkage_free(struct modlinkage *mlinkp) 111 { 112 if (!mlinkp) 113 return; 114 115 (void) kmem_free(mlinkp, (sizeof (struct modlinkage) + 116 sizeof (struct modlpsm) + sizeof (struct psm_sw))); 117 } 118 119 int 120 psm_mod_init(void **handlepp, struct psm_info *infop) 121 { 122 struct modlinkage **modlpp = (struct modlinkage **)handlepp; 123 int status; 124 struct modlinkage *mlinkp; 125 126 if (!*modlpp) { 127 mlinkp = psm_modlinkage_alloc(infop); 128 if (!mlinkp) 129 return (ENOSPC); 130 } else 131 mlinkp = *modlpp; 132 133 status = mod_install(mlinkp); 134 if (status) { 135 psm_modlinkage_free(mlinkp); 136 *modlpp = NULL; 137 } else 138 *modlpp = mlinkp; 139 140 return (status); 141 } 142 143 /*ARGSUSED1*/ 144 int 145 psm_mod_fini(void **handlepp, struct psm_info *infop) 146 { 147 struct modlinkage **modlpp = (struct modlinkage **)handlepp; 148 int status; 149 150 status = mod_remove(*modlpp); 151 if (status == 0) { 152 psm_modlinkage_free(*modlpp); 153 *modlpp = NULL; 154 } 155 return (status); 156 } 157 158 int 159 psm_mod_info(void **handlepp, struct psm_info *infop, struct modinfo *modinfop) 160 { 161 struct modlinkage **modlpp = (struct modlinkage **)handlepp; 162 int status; 163 struct modlinkage *mlinkp; 164 165 if (!*modlpp) { 166 mlinkp = psm_modlinkage_alloc(infop); 167 if (!mlinkp) 168 return ((int)NULL); 169 } else 170 mlinkp = *modlpp; 171 172 status = mod_info(mlinkp, modinfop); 173 174 if (!status) { 175 psm_modlinkage_free(mlinkp); 176 *modlpp = NULL; 177 } else 178 *modlpp = mlinkp; 179 180 return (status); 181 } 182 183 int 184 psm_add_intr(int lvl, avfunc xxintr, char *name, int vect, caddr_t arg) 185 { 186 return (add_avintr((void *)NULL, lvl, xxintr, name, vect, 187 arg, NULL, NULL, NULL)); 188 } 189 190 int 191 psm_add_nmintr(int lvl, avfunc xxintr, char *name, caddr_t arg) 192 { 193 return (add_nmintr(lvl, xxintr, name, arg)); 194 } 195 196 processorid_t 197 psm_get_cpu_id(void) 198 { 199 return (CPU->cpu_id); 200 } 201 202 caddr_t 203 psm_map_phys_new(paddr_t addr, size_t len, int prot) 204 { 205 uint_t pgoffset; 206 paddr_t base; 207 pgcnt_t npages; 208 caddr_t cvaddr; 209 210 if (len == 0) 211 return (0); 212 213 pgoffset = addr & MMU_PAGEOFFSET; 214 base = addr; 215 npages = mmu_btopr(len + pgoffset); 216 cvaddr = device_arena_alloc(ptob(npages), VM_NOSLEEP); 217 if (cvaddr == NULL) 218 return (0); 219 hat_devload(kas.a_hat, cvaddr, mmu_ptob(npages), mmu_btop(base), 220 prot, HAT_LOAD_LOCK); 221 return (cvaddr + pgoffset); 222 } 223 224 void 225 psm_unmap_phys(caddr_t addr, size_t len) 226 { 227 uint_t pgoffset; 228 caddr_t base; 229 pgcnt_t npages; 230 231 if (len == 0) 232 return; 233 234 pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET; 235 base = addr - pgoffset; 236 npages = mmu_btopr(len + pgoffset); 237 hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK); 238 device_arena_free(base, ptob(npages)); 239 } 240 241 caddr_t 242 psm_map_new(paddr_t addr, size_t len, int prot) 243 { 244 int phys_prot = PROT_READ; 245 246 ASSERT(prot == (prot & (PSM_PROT_WRITE | PSM_PROT_READ))); 247 if (prot & PSM_PROT_WRITE) 248 phys_prot |= PROT_WRITE; 249 250 return (psm_map_phys(addr, len, phys_prot)); 251 } 252 253 #undef psm_map_phys 254 #undef psm_map 255 256 caddr_t 257 psm_map_phys(uint32_t addr, size_t len, int prot) 258 { 259 return (psm_map_phys_new((paddr_t)(addr & 0xffffffff), len, prot)); 260 } 261 262 caddr_t 263 psm_map(uint32_t addr, size_t len, int prot) 264 { 265 return (psm_map_new((paddr_t)(addr & 0xffffffff), len, prot)); 266 } 267 268 void 269 psm_unmap(caddr_t addr, size_t len) 270 { 271 uint_t pgoffset; 272 caddr_t base; 273 pgcnt_t npages; 274 275 if (len == 0) 276 return; 277 278 pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET; 279 base = addr - pgoffset; 280 npages = mmu_btopr(len + pgoffset); 281 hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK); 282 device_arena_free(base, ptob(npages)); 283 } 284 285 /*ARGSUSED1*/ 286 static int 287 mod_installpsm(struct modlpsm *modl, struct modlinkage *modlp) 288 { 289 struct psm_sw *swp; 290 291 swp = modl->psm_swp; 292 mutex_enter(&psmsw_lock); 293 psmsw->psw_back->psw_forw = swp; 294 swp->psw_back = psmsw->psw_back; 295 swp->psw_forw = psmsw; 296 psmsw->psw_back = swp; 297 swp->psw_flag |= PSM_MOD_INSTALL; 298 mutex_exit(&psmsw_lock); 299 return (0); 300 } 301 302 /*ARGSUSED1*/ 303 static int 304 mod_removepsm(struct modlpsm *modl, struct modlinkage *modlp) 305 { 306 struct psm_sw *swp; 307 308 swp = modl->psm_swp; 309 mutex_enter(&psmsw_lock); 310 if (swp->psw_flag & PSM_MOD_IDENTIFY) { 311 mutex_exit(&psmsw_lock); 312 return (EBUSY); 313 } 314 if (!(swp->psw_flag & PSM_MOD_INSTALL)) { 315 mutex_exit(&psmsw_lock); 316 return (0); 317 } 318 319 swp->psw_back->psw_forw = swp->psw_forw; 320 swp->psw_forw->psw_back = swp->psw_back; 321 mutex_exit(&psmsw_lock); 322 return (0); 323 } 324 325 /*ARGSUSED1*/ 326 static int 327 mod_infopsm(struct modlpsm *modl, struct modlinkage *modlp, int *p0) 328 { 329 *p0 = (int)modl->psm_swp->psw_infop->p_owner; 330 return (0); 331 } 332 333 #define DEFAULT_PSM_MODULE "uppc" 334 335 static char * 336 psm_get_impl_module(int first) 337 { 338 static char **pnamep; 339 static char *psm_impl_module_list[] = { 340 DEFAULT_PSM_MODULE, 341 (char *)0 342 }; 343 static void *mhdl = NULL; 344 static char machname[MAXNAMELEN]; 345 346 if (first) 347 pnamep = psm_impl_module_list; 348 349 if (*pnamep != (char *)0) 350 return (*pnamep++); 351 352 mhdl = get_next_mach(mhdl, machname); 353 if (mhdl) 354 return (machname); 355 return ((char *)0); 356 } 357 358 void 359 psm_modload(void) 360 { 361 char *this; 362 363 mutex_init(&psmsw_lock, NULL, MUTEX_DEFAULT, NULL); 364 open_mach_list(); 365 366 for (this = psm_get_impl_module(1); 367 this != (char *)NULL; 368 this = psm_get_impl_module(0)) { 369 if (modload("mach", this) == -1) 370 cmn_err(CE_WARN, "!Cannot load psm %s", this); 371 } 372 close_mach_list(); 373 } 374 375 void 376 psm_install(void) 377 { 378 struct psm_sw *swp, *cswp; 379 struct psm_ops *opsp; 380 char machstring[15]; 381 int err; 382 383 mutex_enter(&psmsw_lock); 384 for (swp = psmsw->psw_forw; swp != psmsw; ) { 385 opsp = swp->psw_infop->p_ops; 386 if (opsp->psm_probe) { 387 if ((*opsp->psm_probe)() == PSM_SUCCESS) { 388 swp->psw_flag |= PSM_MOD_IDENTIFY; 389 swp = swp->psw_forw; 390 continue; 391 } 392 } 393 /* remove the unsuccessful psm modules */ 394 cswp = swp; 395 swp = swp->psw_forw; 396 397 mutex_exit(&psmsw_lock); 398 (void) strcpy(&machstring[0], cswp->psw_infop->p_mach_idstring); 399 err = mod_remove_by_name(cswp->psw_infop->p_mach_idstring); 400 if (err) 401 cmn_err(CE_WARN, "%s: mod_remove_by_name failed %d", 402 &machstring[0], err); 403 mutex_enter(&psmsw_lock); 404 } 405 mutex_exit(&psmsw_lock); 406 (*psminitf)(); 407 } 408 409 /* 410 * Return 1 if kernel debugger is present, and 0 if not. 411 */ 412 int 413 psm_debugger(void) 414 { 415 return ((boothowto & RB_DEBUG) != 0); 416 } 417