xref: /illumos-gate/usr/src/uts/i86pc/os/mp_implfuncs.c (revision 355b4669e025ff377602b6fc7caaf30dbc218371)
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, 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