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