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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <sys/modctl.h>
30 #include <vm/seg_kmem.h>
32 #include <sys/psm_modctl.h>
33 #include <sys/smp_impldefs.h>
34 #include <sys/reboot.h>
37 * External reference functions
39 extern void *get_next_mach(void *, char *);
40 extern void close_mach_list(void);
41 extern void open_mach_list(void);
44 * from startup.c - kernel VA range allocator for device mappings
46 extern void *device_arena_alloc(size_t size
, int vm_flag
);
47 extern void device_arena_free(void * vaddr
, size_t size
);
49 void psm_modloadonly(void);
50 void psm_install(void);
53 * Local Function Prototypes
55 static struct modlinkage
*psm_modlinkage_alloc(struct psm_info
*infop
);
56 static void psm_modlinkage_free(struct modlinkage
*mlinkp
);
58 static char *psm_get_impl_module(int first
);
60 static int mod_installpsm(struct modlpsm
*modl
, struct modlinkage
*modlp
);
61 static int mod_removepsm(struct modlpsm
*modl
, struct modlinkage
*modlp
);
62 static int mod_infopsm(struct modlpsm
*modl
, struct modlinkage
*modlp
, int *p0
);
63 struct mod_ops mod_psmops
= {
64 mod_installpsm
, mod_removepsm
, mod_infopsm
67 static struct psm_sw psm_swtab
= {
68 &psm_swtab
, &psm_swtab
, NULL
, 0
71 kmutex_t psmsw_lock
; /* lock accesses to psmsw */
72 struct psm_sw
*psmsw
= &psm_swtab
; /* start of all psm_sw */
74 static struct modlinkage
*
75 psm_modlinkage_alloc(struct psm_info
*infop
)
78 struct modlinkage
*mlinkp
;
79 struct modlpsm
*mlpsmp
;
82 memsz
= sizeof (struct modlinkage
) + sizeof (struct modlpsm
) +
83 sizeof (struct psm_sw
);
84 mlinkp
= kmem_zalloc(memsz
, KM_NOSLEEP
);
86 cmn_err(CE_WARN
, "!psm_mod_init: Cannot install %s",
87 infop
->p_mach_idstring
);
90 mlpsmp
= (struct modlpsm
*)(mlinkp
+ 1);
91 swp
= (struct psm_sw
*)(mlpsmp
+ 1);
93 mlinkp
->ml_rev
= MODREV_1
;
94 mlinkp
->ml_linkage
[0] = (void *)mlpsmp
;
95 mlinkp
->ml_linkage
[1] = NULL
;
97 mlpsmp
->psm_modops
= &mod_psmops
;
98 mlpsmp
->psm_linkinfo
= infop
->p_mach_desc
;
99 mlpsmp
->psm_swp
= swp
;
101 swp
->psw_infop
= infop
;
107 psm_modlinkage_free(struct modlinkage
*mlinkp
)
112 (void) kmem_free(mlinkp
, (sizeof (struct modlinkage
) +
113 sizeof (struct modlpsm
) + sizeof (struct psm_sw
)));
117 psm_mod_init(void **handlepp
, struct psm_info
*infop
)
119 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
121 struct modlinkage
*mlinkp
;
124 mlinkp
= psm_modlinkage_alloc(infop
);
130 status
= mod_install(mlinkp
);
132 psm_modlinkage_free(mlinkp
);
142 psm_mod_fini(void **handlepp
, struct psm_info
*infop
)
144 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
147 status
= mod_remove(*modlpp
);
149 psm_modlinkage_free(*modlpp
);
156 psm_mod_info(void **handlepp
, struct psm_info
*infop
, struct modinfo
*modinfop
)
158 struct modlinkage
**modlpp
= (struct modlinkage
**)handlepp
;
160 struct modlinkage
*mlinkp
;
163 mlinkp
= psm_modlinkage_alloc(infop
);
169 status
= mod_info(mlinkp
, modinfop
);
172 psm_modlinkage_free(mlinkp
);
181 psm_add_intr(int lvl
, avfunc xxintr
, char *name
, int vect
, caddr_t arg
)
183 return (add_avintr(NULL
, lvl
, xxintr
, name
, vect
,
184 arg
, NULL
, NULL
, NULL
));
188 psm_add_nmintr(int lvl
, avfunc xxintr
, char *name
, caddr_t arg
)
190 return (add_nmintr(lvl
, xxintr
, name
, arg
));
196 return (CPU
->cpu_id
);
200 psm_map_phys_new(paddr_t addr
, size_t len
, int prot
)
210 pgoffset
= addr
& MMU_PAGEOFFSET
;
212 npages
= mmu_btopr(len
+ pgoffset
);
213 cvaddr
= device_arena_alloc(ptob(npages
), VM_NOSLEEP
);
216 hat_devload(kas
.a_hat
, cvaddr
, mmu_ptob(npages
), mmu_btop(base
),
217 prot
, HAT_LOAD_LOCK
);
218 return (cvaddr
+ pgoffset
);
222 psm_unmap_phys(caddr_t addr
, size_t len
)
231 pgoffset
= (uintptr_t)addr
& MMU_PAGEOFFSET
;
232 base
= addr
- pgoffset
;
233 npages
= mmu_btopr(len
+ pgoffset
);
234 hat_unload(kas
.a_hat
, base
, ptob(npages
), HAT_UNLOAD_UNLOCK
);
235 device_arena_free(base
, ptob(npages
));
239 psm_map_new(paddr_t addr
, size_t len
, int prot
)
241 int phys_prot
= PROT_READ
;
243 ASSERT(prot
== (prot
& (PSM_PROT_WRITE
| PSM_PROT_READ
)));
244 if (prot
& PSM_PROT_WRITE
)
245 phys_prot
|= PROT_WRITE
;
247 return (psm_map_phys(addr
, len
, phys_prot
));
254 psm_map_phys(uint32_t addr
, size_t len
, int prot
)
256 return (psm_map_phys_new((paddr_t
)(addr
& 0xffffffff), len
, prot
));
260 psm_map(uint32_t addr
, size_t len
, int prot
)
262 return (psm_map_new((paddr_t
)(addr
& 0xffffffff), len
, prot
));
266 psm_unmap(caddr_t addr
, size_t len
)
275 pgoffset
= (uintptr_t)addr
& MMU_PAGEOFFSET
;
276 base
= addr
- pgoffset
;
277 npages
= mmu_btopr(len
+ pgoffset
);
278 hat_unload(kas
.a_hat
, base
, ptob(npages
), HAT_UNLOAD_UNLOCK
);
279 device_arena_free(base
, ptob(npages
));
284 mod_installpsm(struct modlpsm
*modl
, struct modlinkage
*modlp
)
289 mutex_enter(&psmsw_lock
);
290 psmsw
->psw_back
->psw_forw
= swp
;
291 swp
->psw_back
= psmsw
->psw_back
;
292 swp
->psw_forw
= psmsw
;
293 psmsw
->psw_back
= swp
;
294 swp
->psw_flag
|= PSM_MOD_INSTALL
;
295 mutex_exit(&psmsw_lock
);
301 mod_removepsm(struct modlpsm
*modl
, struct modlinkage
*modlp
)
306 mutex_enter(&psmsw_lock
);
307 if (swp
->psw_flag
& PSM_MOD_IDENTIFY
) {
308 mutex_exit(&psmsw_lock
);
311 if (!(swp
->psw_flag
& PSM_MOD_INSTALL
)) {
312 mutex_exit(&psmsw_lock
);
316 swp
->psw_back
->psw_forw
= swp
->psw_forw
;
317 swp
->psw_forw
->psw_back
= swp
->psw_back
;
318 mutex_exit(&psmsw_lock
);
324 mod_infopsm(struct modlpsm
*modl
, struct modlinkage
*modlp
, int *p0
)
326 *p0
= (int)modl
->psm_swp
->psw_infop
->p_owner
;
330 #define DEFAULT_PSM_MODULE "uppc"
333 psm_get_impl_module(int first
)
335 static char **pnamep
;
336 static char *psm_impl_module_list
[] = {
340 static void *mhdl
= NULL
;
341 static char machname
[MAXNAMELEN
];
344 pnamep
= psm_impl_module_list
;
349 mhdl
= get_next_mach(mhdl
, machname
);
360 mutex_init(&psmsw_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
363 for (this = psm_get_impl_module(1); this != NULL
;
364 this = psm_get_impl_module(0)) {
365 if (modload("mach", this) == -1)
366 cmn_err(CE_CONT
, "!Skipping psm: %s\n", this);
371 #define NOTSUP_MSG "This version of Solaris does not support this hardware"
376 struct psm_sw
*swp
, *cswp
;
377 struct psm_ops
*opsp
;
381 mutex_enter(&psmsw_lock
);
382 for (swp
= psmsw
->psw_forw
; swp
!= psmsw
; ) {
383 opsp
= swp
->psw_infop
->p_ops
;
384 if (opsp
->psm_probe
) {
385 if ((*opsp
->psm_probe
)() == PSM_SUCCESS
) {
387 swp
->psw_flag
|= PSM_MOD_IDENTIFY
;
392 /* remove the unsuccessful psm modules */
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
);
400 cmn_err(CE_WARN
, "!%s: mod_remove_by_name failed %d",
401 &machstring
[0], err
);
402 mutex_enter(&psmsw_lock
);
404 mutex_exit(&psmsw_lock
);
411 * Return 1 if kernel debugger is present, and 0 if not.
416 return ((boothowto
& RB_DEBUG
) != 0);