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