xref: /titanic_50/usr/src/uts/common/avs/ns/solaris/nsc_ddi.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 
26 /*
27  *	This file contains interface code to make the kernel look it has
28  *      an svr4.2 ddi/ddk. It also adds a little other system dependent
29  *      functionality that is useful for drivers lower than nsctl.
30  */
31 
32 #include <sys/types.h>
33 #ifndef DS_DDICT
34 #include <sys/time.h>		/* only DDI compliant as of 5.9 */
35 #endif
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/kmem.h>
39 #include <sys/ksynch.h>
40 #include <sys/cmn_err.h>
41 #include <sys/uio.h>
42 #include <sys/conf.h>
43 #include <sys/modctl.h>
44 #ifndef DS_DDICT
45 #include <sys/vnode.h>
46 #endif
47 #include <sys/open.h>
48 #include <sys/ddi.h>
49 
50 #include "nsc_thread.h"
51 
52 #ifdef DS_DDICT
53 #include <sys/nsctl/contract.h>
54 #endif
55 
56 #include <sys/nsctl/nsctl.h>
57 #include <sys/nsctl/nsvers.h>
58 #include "nskernd.h"
59 #include "nsc_list.h"
60 
61 kmutex_t _nskern_lock;
62 
63 void _nsc_stop_proc(void);
64 void _nsc_start_proc(void);
65 
66 
67 /*
68  * Solaris specific driver module interface code.
69  */
70 
71 static struct cb_ops nskern_cb_ops = {
72 	nulldev,	/* open */
73 	nulldev,	/* close */
74 	nodev,		/* strategy */
75 	nodev,		/* print */
76 	nodev,		/* dump */
77 	nodev,		/* read */
78 	nodev,		/* write */
79 	nodev,		/* ioctl */
80 	nodev,		/* devmap routine */
81 	nodev,		/* mmap routine */
82 	nodev,		/* segmap */
83 	nochpoll,	/* chpoll */
84 	ddi_prop_op,
85 	0,		/* not a STREAMS driver, no cb_str routine */
86 	D_NEW | D_MP | D_64BIT,	/* safe for multi-thread/multi-processor */
87 	CB_REV,
88 	nodev,		/* aread */
89 	nodev,		/* awrite */
90 };
91 
92 static int _nskern_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
93 static int _nskern_attach(dev_info_t *, ddi_attach_cmd_t);
94 static int _nskern_detach(dev_info_t *, ddi_detach_cmd_t);
95 
96 static struct dev_ops nskern_ops = {
97 	DEVO_REV,			/* Driver build version */
98 	0,				/* device reference count */
99 	_nskern_getinfo,
100 	nulldev,			/* identify */
101 	nulldev,			/* probe */
102 	_nskern_attach,
103 	_nskern_detach,
104 	nodev,				/* reset */
105 	&nskern_cb_ops,
106 	(struct bus_ops *)NULL
107 };
108 
109 static struct modldrv nskern_ldrv = {
110 	&mod_driverops,
111 	"nws:Kernel Interface:" ISS_VERSION_STR,
112 	&nskern_ops
113 };
114 
115 static dev_info_t *nskern_dip;
116 
117 static struct modlinkage nskern_modlinkage = {
118 	MODREV_1,
119 	&nskern_ldrv,
120 	NULL
121 };
122 
123 /*
124  * Solaris module load time code
125  */
126 
127 int
_init(void)128 _init(void)
129 {
130 	void nskern_init();
131 	int err;
132 
133 	mutex_init(&_nskern_lock, NULL, MUTEX_DRIVER, NULL);
134 
135 	err = mod_install(&nskern_modlinkage);
136 	if (err) {
137 		mutex_destroy(&_nskern_lock);
138 		cmn_err(CE_WARN, "nskern_init: mod_install err %d", err);
139 		return (err);
140 	}
141 
142 	nskern_init();
143 
144 	return (DDI_SUCCESS);
145 }
146 
147 /*
148  * Solaris module unload time code
149  */
150 
151 int
_fini(void)152 _fini(void)
153 {
154 	int err;
155 
156 	if ((err = mod_remove(&nskern_modlinkage)) == 0) {
157 		nskernd_stop();
158 		_nsc_stop_proc();
159 		nskernd_deinit();
160 
161 		mutex_destroy(&_nskern_lock);
162 	}
163 
164 	return (err);
165 }
166 
167 int
_info(struct modinfo * modinfop)168 _info(struct modinfo *modinfop)
169 {
170 	return (mod_info(&nskern_modlinkage, modinfop));
171 }
172 
173 /*
174  * Attach an instance of the device. This happens before an open
175  * can succeed.
176  */
177 
178 static int
_nskern_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)179 _nskern_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
180 {
181 	if (cmd == DDI_ATTACH) {
182 		nskern_dip = dip;
183 		return (DDI_SUCCESS);
184 	} else {
185 		return (DDI_FAILURE);
186 	}
187 }
188 
189 /* ARGSUSED */
190 
191 static int
_nskern_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)192 _nskern_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
193 {
194 	if (cmd == DDI_DETACH) {
195 		nskern_dip = NULL;
196 		return (DDI_SUCCESS);
197 	} else {
198 		return (DDI_FAILURE);
199 	}
200 }
201 
202 /* ARGSUSED */
203 static int
_nskern_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)204 _nskern_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
205 {
206 	int rc = DDI_FAILURE;
207 
208 	switch (cmd) {
209 	case DDI_INFO_DEVT2DEVINFO:
210 		*result = nskern_dip;
211 		rc = DDI_SUCCESS;
212 		break;
213 
214 	case DDI_INFO_DEVT2INSTANCE:
215 		/* single instance */
216 		*result = 0;
217 		rc = DDI_SUCCESS;
218 		break;
219 	}
220 
221 	return (rc);
222 }
223 
224 /* ARGSUSED */
225 
226 int
_nskern_print(dev_t dev,char * s)227 _nskern_print(dev_t dev, char *s)
228 {
229 	cmn_err(CE_WARN, "nskern:%s", s);
230 	return (0);
231 }
232 
233 /*
234  * nskern_init - initialize the nskern layer at module load time.
235  */
236 
237 void
nskern_init(void)238 nskern_init(void)
239 {
240 	_nsc_start_proc();
241 	nskernd_init();
242 
243 	(void) nst_startup();
244 }
245 
246 
247 #if (defined(DS_DDICT))
248 static clock_t
nskern_lbolt(void)249 nskern_lbolt(void)
250 {
251 #ifdef _SunOS_5_6
252 	clock_t lbolt;
253 
254 	if (drv_getparm(LBOLT, &lbolt) == 0)
255 		return (lbolt);
256 
257 	return (0);
258 #else
259 	return (ddi_get_lbolt());
260 #endif
261 }
262 #endif	/* ddict */
263 
264 
265 /*
266  * nsc_usec()
267  *	- return the value of the "microsecond timer emulation".
268  *
269  * Pre-SunOS 5.9:
270  * Actually this is a fake free running counter based on the lbolt value.
271  *
272  * SunOS 5.9+
273  * This is based on the gethrtime(9f) DDI facility.
274  */
275 
276 #if (defined(DS_DDICT))
277 /* these two #defines need to match! */
278 #define	USEC_SHIFT	16
279 #define	INCR_TYPE	uint16_t
280 #endif /* ! _SunOS_5_9+ */
281 
282 clock_t
nsc_usec(void)283 nsc_usec(void)
284 {
285 	/* avoid divide by zero */
286 	return (gethrtime() / 1000);
287 }
288 
289 
290 /*
291  * nsc_yield - yield the cpu.
292  */
293 void
nsc_yield(void)294 nsc_yield(void)
295 {
296 	/* can't call yield() unless there is an lwp context */
297 	/* do this for now */
298 
299 	delay(2);
300 }
301 
302 
303 /*
304  * void
305  * ls_ins_before(ls_elt_t *, ls_elt_t *)
306  *	Link new into list before old.
307  *
308  * Calling/Exit State:
309  *	None.
310  */
311 #ifdef lint
312 void
nsc_ddi_ls_ins_before(ls_elt_t * old,ls_elt_t * new)313 nsc_ddi_ls_ins_before(ls_elt_t *old, ls_elt_t *new)
314 #else
315 void
316 ls_ins_before(ls_elt_t *old, ls_elt_t *new)
317 #endif
318 {
319 	new->ls_prev = old->ls_prev;
320 	new->ls_next = old;
321 	new->ls_prev->ls_next = new;
322 	new->ls_next->ls_prev = new;
323 }
324 
325 /*
326  * void
327  * ls_ins_after(ls_elt_t *, ls_elt_t *)
328  *	Link new into list after old.
329  *
330  * Calling/Exit State:
331  *	None.
332  */
333 #ifdef lint
334 void
nsc_ddi_ls_ins_after(ls_elt_t * old,ls_elt_t * new)335 nsc_ddi_ls_ins_after(ls_elt_t *old, ls_elt_t *new)
336 #else
337 void
338 ls_ins_after(ls_elt_t *old, ls_elt_t *new)
339 #endif
340 {
341 	new->ls_next = old->ls_next;
342 	new->ls_prev = old;
343 	new->ls_next->ls_prev = new;
344 	new->ls_prev->ls_next = new;
345 }
346 
347 /*
348  * ls_elt_t *
349  * ls_remque(ls_elt_t *)
350  *	Unlink first element in the specified list.
351  *
352  * Calling/Exit State:
353  *	Returns the element's address or 0 if list is empty.
354  *	Resets elements pointers to empty list state.
355  */
356 ls_elt_t *
ls_remque(ls_elt_t * p)357 ls_remque(ls_elt_t *p)
358 {
359 	ls_elt_t *result = 0;
360 
361 	if (!LS_ISEMPTY(p)) {
362 		result = p->ls_next;
363 		result->ls_prev->ls_next = result->ls_next;
364 		result->ls_next->ls_prev = result->ls_prev;
365 		LS_INIT(result);
366 	}
367 	return (result);
368 }
369 
370 /*
371  * void
372  * ls_remove(ls_elt_t *)
373  *	Unlink donated element for list.
374  *
375  * Calling/Exit State:
376  *	Resets elements pointers to empty list state.
377  */
378 #ifdef lint
379 void
nsc_ddi_ls_remove(ls_elt_t * p)380 nsc_ddi_ls_remove(ls_elt_t *p)
381 #else
382 void
383 ls_remove(ls_elt_t *p)
384 #endif
385 {
386 	p->ls_prev->ls_next = p->ls_next;
387 	p->ls_next->ls_prev = p->ls_prev;
388 	LS_INIT(p);
389 }
390