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