xref: /NextBSD/sys/dev/utopia/utopia.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
1 /*-
2  * Copyright (c) 2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  * 	All rights reserved.
5  *
6  * Author: Hartmut Brandt <harti@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/unistd.h>
36 #include <sys/kernel.h>
37 #include <sys/kthread.h>
38 #include <sys/proc.h>
39 #include <sys/bus.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/sysctl.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/socket.h>
46 
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/if_media.h>
50 #include <net/if_atm.h>
51 
52 #include <dev/utopia/suni.h>
53 #include <dev/utopia/idtphy.h>
54 #include <dev/utopia/utopia.h>
55 #include <dev/utopia/utopia_priv.h>
56 
57 /* known chips */
58 extern const struct utopia_chip utopia_chip_idt77155;
59 extern const struct utopia_chip utopia_chip_idt77105;
60 extern const struct utopia_chip utopia_chip_lite;
61 extern const struct utopia_chip utopia_chip_ultra;
62 extern const struct utopia_chip utopia_chip_622;
63 
64 /*
65  * Global list of all registered interfaces
66  */
67 static struct mtx utopia_list_mtx;
68 static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
69 
70 #define UTP_RLOCK_LIST()	mtx_lock(&utopia_list_mtx)
71 #define UTP_RUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
72 #define UTP_WLOCK_LIST()	mtx_lock(&utopia_list_mtx)
73 #define UTP_WUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
74 
75 #define UTP_LOCK(UTP)		mtx_lock((UTP)->lock)
76 #define UTP_UNLOCK(UTP)		mtx_unlock((UTP)->lock)
77 #define UTP_LOCK_ASSERT(UTP)	mtx_assert((UTP)->lock, MA_OWNED)
78 
79 static struct proc *utopia_kproc;
80 
81 static void utopia_dump(struct utopia *) __unused;
82 
83 /*
84  * Read a multi-register value.
85  */
86 uint32_t
utopia_update(struct utopia * utp,u_int reg,u_int nreg,uint32_t mask)87 utopia_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
88 {
89 	int err;
90 	u_int n;
91 	uint8_t regs[4];
92 	uint32_t val;
93 
94 	n = nreg;
95 	if ((err = UTP_READREGS(utp, reg, regs, &n)) != 0) {
96 #ifdef DIAGNOSTIC
97 		printf("%s: register read error %s(%u,%u): %d\n", __func__,
98 		    utp->chip->name, reg, nreg, err);
99 #endif
100 		return (0);
101 	}
102 	if (n < nreg) {
103 #ifdef DIAGNOSTIC
104 		printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
105 		    utp->chip->name, reg, nreg, err);
106 #endif
107 		return (0);
108 	}
109 	val = 0;
110 	for (n = nreg; n > 0; n--) {
111 		val <<= 8;
112 		val |= regs[n - 1];
113 	}
114 	return (val & mask);
115 }
116 
117 /*
118  * Debugging - dump all registers.
119  */
120 static void
utopia_dump(struct utopia * utp)121 utopia_dump(struct utopia *utp)
122 {
123 	uint8_t regs[256];
124 	u_int n = 256, i;
125 	int err;
126 
127 	if ((err = UTP_READREGS(utp, 0, regs, &n)) != 0) {
128 		printf("UTOPIA reg read error %d\n", err);
129 		return;
130 	}
131 	for (i = 0; i < n; i++) {
132 		if (i % 16 == 0)
133 			printf("%02x:", i);
134 		if (i % 16 == 8)
135 			printf(" ");
136 		printf(" %02x", regs[i]);
137 		if (i % 16 == 15)
138 			printf("\n");
139 	}
140 	if (i % 16 != 0)
141 		printf("\n");
142 }
143 
144 /*
145  * Update the carrier status
146  */
147 void
utopia_check_carrier(struct utopia * utp,u_int carr_ok)148 utopia_check_carrier(struct utopia *utp, u_int carr_ok)
149 {
150 	int old;
151 
152 	old = utp->carrier;
153 	if (carr_ok) {
154 		/* carrier */
155 		utp->carrier = UTP_CARR_OK;
156 		if (old != UTP_CARR_OK) {
157 			if_printf(utp->ifatm->ifp, "carrier detected\n");
158 			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1);
159 		}
160 	} else {
161 		/* no carrier */
162 		utp->carrier = UTP_CARR_LOST;
163 		if (old == UTP_CARR_OK) {
164 			if_printf(utp->ifatm->ifp, "carrier lost\n");
165 			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0);
166 		}
167 	}
168 }
169 
170 static int
unknown_inval(struct utopia * utp,int what __unused)171 unknown_inval(struct utopia *utp, int what __unused)
172 {
173 
174 	return (EINVAL);
175 }
176 
177 static int
unknown_reset(struct utopia * utp __unused)178 unknown_reset(struct utopia *utp __unused)
179 {
180 	return (EIO);
181 }
182 
183 static int
unknown_update_carrier(struct utopia * utp)184 unknown_update_carrier(struct utopia *utp)
185 {
186 	utp->carrier = UTP_CARR_UNKNOWN;
187 	return (0);
188 }
189 
190 static int
unknown_set_loopback(struct utopia * utp __unused,u_int mode __unused)191 unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
192 {
193 	return (EINVAL);
194 }
195 
196 static void
unknown_intr(struct utopia * utp __unused)197 unknown_intr(struct utopia *utp __unused)
198 {
199 }
200 
201 static void
unknown_update_stats(struct utopia * utp __unused)202 unknown_update_stats(struct utopia *utp __unused)
203 {
204 }
205 
206 static const struct utopia_chip utopia_chip_unknown = {
207 	UTP_TYPE_UNKNOWN,
208 	"unknown",
209 	0,
210 	unknown_reset,
211 	unknown_inval,
212 	unknown_inval,
213 	unknown_inval,
214 	unknown_update_carrier,
215 	unknown_set_loopback,
216 	unknown_intr,
217 	unknown_update_stats,
218 };
219 
220 /*
221  * Callbacks for the ifmedia infrastructure.
222  */
223 static int
utopia_media_change(struct ifnet * ifp)224 utopia_media_change(struct ifnet *ifp)
225 {
226 	struct ifatm *ifatm = IFP2IFATM(ifp);
227 	struct utopia *utp = ifatm->phy;
228 	int error = 0;
229 
230 	UTP_LOCK(utp);
231 	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
232 		if (utp->media->ifm_media & IFM_ATM_SDH) {
233 			if (!(utp->state & UTP_ST_SDH))
234 				error = utopia_set_sdh(utp, 1);
235 		} else {
236 			if (utp->state & UTP_ST_SDH)
237 				error = utopia_set_sdh(utp, 0);
238 		}
239 		if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
240 			if (!(utp->state & UTP_ST_UNASS))
241 				error = utopia_set_unass(utp, 1);
242 		} else {
243 			if (utp->state & UTP_ST_UNASS)
244 				error = utopia_set_unass(utp, 0);
245 		}
246 		if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
247 			if (!(utp->state & UTP_ST_NOSCRAMB))
248 				error = utopia_set_noscramb(utp, 1);
249 		} else {
250 			if (utp->state & UTP_ST_NOSCRAMB)
251 				error = utopia_set_noscramb(utp, 0);
252 		}
253 	} else
254 		error = EIO;
255 	UTP_UNLOCK(utp);
256 	return (error);
257 }
258 
259 /*
260  * Look at the carrier status.
261  */
262 static void
utopia_media_status(struct ifnet * ifp,struct ifmediareq * ifmr)263 utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
264 {
265 	struct utopia *utp = IFP2IFATM(ifp)->phy;
266 
267 	UTP_LOCK(utp);
268 	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
269 		ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
270 
271 		switch (utp->carrier) {
272 
273 		  case UTP_CARR_OK:
274 			ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
275 			break;
276 
277 		  case UTP_CARR_LOST:
278 			ifmr->ifm_status = IFM_AVALID;
279 			break;
280 
281 		  default:
282 			ifmr->ifm_status = 0;
283 			break;
284 		}
285 		if (utp->state & UTP_ST_SDH) {
286 			ifmr->ifm_active |= IFM_ATM_SDH;
287 			ifmr->ifm_current |= IFM_ATM_SDH;
288 		}
289 		if (utp->state & UTP_ST_UNASS) {
290 			ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
291 			ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
292 		}
293 		if (utp->state & UTP_ST_NOSCRAMB) {
294 			ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
295 			ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
296 		}
297 	} else {
298 		ifmr->ifm_active = 0;
299 		ifmr->ifm_status = 0;
300 	}
301 	UTP_UNLOCK(utp);
302 }
303 
304 /*
305  * Initialize media from the mib
306  */
307 void
utopia_init_media(struct utopia * utp)308 utopia_init_media(struct utopia *utp)
309 {
310 
311 	ifmedia_removeall(utp->media);
312 	ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL);
313 	ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media);
314 }
315 
316 /*
317  * Reset all media
318  */
319 void
utopia_reset_media(struct utopia * utp)320 utopia_reset_media(struct utopia *utp)
321 {
322 
323 	ifmedia_removeall(utp->media);
324 }
325 
326 /*
327  * This is called by the driver as soon as the SUNI registers are accessible.
328  * This may be either in the attach routine or the init routine of the driver.
329  */
330 int
utopia_start(struct utopia * utp)331 utopia_start(struct utopia *utp)
332 {
333 	uint8_t reg;
334 	int err;
335 	u_int n = 1;
336 
337 	/*
338 	 * Try to find out what chip we have
339 	 */
340 	if ((err = UTP_READREGS(utp, SUNI_REGO_MRESET, &reg, &n)) != 0)
341 		return (err);
342 
343 	switch (reg & SUNI_REGM_MRESET_TYPE) {
344 
345 	  case SUNI_REGM_MRESET_TYPE_622:
346 		utp->chip = &utopia_chip_622;
347 		break;
348 
349 	  case SUNI_REGM_MRESET_TYPE_LITE:
350 		/* this may be either a SUNI LITE or a IDT77155 *
351 		 * Read register 0x70. The SUNI doesn't have it */
352 		n = 1;
353 		if ((err = UTP_READREGS(utp, IDTPHY_REGO_RBER, &reg, &n)) != 0)
354 			return (err);
355 		if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
356 		    (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
357 			utp->chip = &utopia_chip_idt77155;
358 		else
359 			utp->chip = &utopia_chip_lite;
360 		break;
361 
362 	  case SUNI_REGM_MRESET_TYPE_ULTRA:
363 		utp->chip = &utopia_chip_ultra;
364 		break;
365 
366 	  default:
367 		if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
368 			utp->chip = &utopia_chip_idt77105;
369 		else {
370 			if_printf(utp->ifatm->ifp,
371 			    "unknown ATM-PHY chip %#x\n", reg);
372 			utp->chip = &utopia_chip_unknown;
373 		}
374 		break;
375 	}
376 	utp->state |= UTP_ST_ACTIVE;
377 	return (0);
378 }
379 
380 /*
381  * Stop the chip
382  */
383 void
utopia_stop(struct utopia * utp)384 utopia_stop(struct utopia *utp)
385 {
386 	utp->state &= ~UTP_ST_ACTIVE;
387 }
388 
389 /*
390  * Handle the sysctls
391  */
392 static int
utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)393 utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
394 {
395 	struct utopia *utp = (struct utopia *)arg1;
396 	int error;
397 	u_int n;
398 	uint8_t *val;
399 	uint8_t new[3];
400 
401 	if ((n = utp->chip->nregs) == 0)
402 		return (EIO);
403 	val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
404 
405 	UTP_LOCK(utp);
406 	error = UTP_READREGS(utp, 0, val, &n);
407 	UTP_UNLOCK(utp);
408 
409 	if (error) {
410 		free(val, M_TEMP);
411 		return (error);
412 	}
413 
414 	error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
415 	free(val, M_TEMP);
416 	if (error != 0 || req->newptr == NULL)
417 		return (error);
418 
419 	error = SYSCTL_IN(req, new, sizeof(new));
420 	if (error)
421 		return (error);
422 
423 	UTP_LOCK(utp);
424 	error = UTP_WRITEREG(utp, new[0], new[1], new[2]);
425 	UTP_UNLOCK(utp);
426 
427 	return (error);
428 }
429 
430 static int
utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)431 utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
432 {
433 	struct utopia *utp = (struct utopia *)arg1;
434 	void *val;
435 	int error;
436 
437 	val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
438 
439 	UTP_LOCK(utp);
440 	bcopy(&utp->stats, val, sizeof(utp->stats));
441 	if (req->newptr != NULL)
442 		bzero((char *)&utp->stats + sizeof(utp->stats.version),
443 		    sizeof(utp->stats) - sizeof(utp->stats.version));
444 	UTP_UNLOCK(utp);
445 
446 	error = SYSCTL_OUT(req, val, sizeof(utp->stats));
447 	if (error && req->newptr != NULL)
448 		bcopy(val, &utp->stats, sizeof(utp->stats));
449 	free(val, M_TEMP);
450 
451 	/* ignore actual new value */
452 
453 	return (error);
454 }
455 
456 /*
457  * Handle the loopback sysctl
458  */
459 static int
utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)460 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
461 {
462 	struct utopia *utp = (struct utopia *)arg1;
463 	int error;
464 	u_int loopback;
465 
466 	error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
467 	if (error != 0 || req->newptr == NULL)
468 		return (error);
469 
470 	error = SYSCTL_IN(req, &loopback, sizeof(u_int));
471 	if (error)
472 		return (error);
473 
474 	UTP_LOCK(utp);
475 	error = utopia_set_loopback(utp, loopback);
476 	UTP_UNLOCK(utp);
477 
478 	return (error);
479 }
480 
481 /*
482  * Handle the type sysctl
483  */
484 static int
utopia_sysctl_type(SYSCTL_HANDLER_ARGS)485 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
486 {
487 	struct utopia *utp = (struct utopia *)arg1;
488 
489 	return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
490 }
491 
492 /*
493  * Handle the name sysctl
494  */
495 static int
utopia_sysctl_name(SYSCTL_HANDLER_ARGS)496 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
497 {
498 	struct utopia *utp = (struct utopia *)arg1;
499 
500 	return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
501 }
502 
503 /*
504  * Initialize the state. This is called from the drivers attach
505  * function. The mutex must be already initialized.
506  */
507 int
utopia_attach(struct utopia * utp,struct ifatm * ifatm,struct ifmedia * media,struct mtx * lock,struct sysctl_ctx_list * ctx,struct sysctl_oid_list * children,const struct utopia_methods * m)508 utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
509     struct mtx *lock, struct sysctl_ctx_list *ctx,
510     struct sysctl_oid_list *children, const struct utopia_methods *m)
511 {
512 
513 	bzero(utp, sizeof(*utp));
514 	utp->ifatm = ifatm;
515 	utp->methods = m;
516 	utp->media = media;
517 	utp->lock = lock;
518 	utp->chip = &utopia_chip_unknown;
519 	utp->stats.version = 1;
520 
521 	ifmedia_init(media,
522 	    IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
523 	    utopia_media_change, utopia_media_status);
524 
525 	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
526 	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
527 	    "phy registers") == NULL)
528 		return (-1);
529 
530 	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
531 	    CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
532 	    "phy loopback mode") == NULL)
533 		return (-1);
534 
535 	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
536 	    CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
537 	    "phy type") == NULL)
538 		return (-1);
539 
540 	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
541 	    CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
542 	    "phy name") == NULL)
543 		return (-1);
544 
545 	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
546 	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
547 	    "phy statistics") == NULL)
548 		return (-1);
549 
550 	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
551 	    CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
552 		return (-1);
553 
554 	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
555 	    CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
556 		return (-1);
557 
558 	UTP_WLOCK_LIST();
559 	LIST_INSERT_HEAD(&utopia_list, utp, link);
560 	UTP_WUNLOCK_LIST();
561 
562 	utp->state |= UTP_ST_ATTACHED;
563 	return (0);
564 }
565 
566 /*
567  * Detach. We set a flag here, wakeup the daemon and let him do it.
568  * Here we need the lock for synchronisation with the daemon.
569  */
570 void
utopia_detach(struct utopia * utp)571 utopia_detach(struct utopia *utp)
572 {
573 
574 	UTP_LOCK_ASSERT(utp);
575 	if (utp->state & UTP_ST_ATTACHED) {
576 		utp->state |= UTP_ST_DETACH;
577 		while (utp->state & UTP_ST_DETACH) {
578 			wakeup(&utopia_list);
579 			msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
580 		}
581 	}
582 }
583 
584 /*
585  * The carrier state kernel proc for those adapters that do not interrupt.
586  *
587  * We assume, that utopia_attach can safely add a new utopia while we are going
588  * through the list without disturbing us (we lock the list while getting
589  * the address of the first element, adding is always done at the head).
590  * Removing is entirely handled here.
591  */
592 static void
utopia_daemon(void * arg __unused)593 utopia_daemon(void *arg __unused)
594 {
595 	struct utopia *utp, *next;
596 
597 	UTP_RLOCK_LIST();
598 	while (utopia_kproc != NULL) {
599 		utp = LIST_FIRST(&utopia_list);
600 		UTP_RUNLOCK_LIST();
601 
602 		while (utp != NULL) {
603 			mtx_lock(&Giant);	/* XXX depend on MPSAFE */
604 			UTP_LOCK(utp);
605 			next = LIST_NEXT(utp, link);
606 			if (utp->state & UTP_ST_DETACH) {
607 				LIST_REMOVE(utp, link);
608 				utp->state &= ~UTP_ST_DETACH;
609 				wakeup_one(utp);
610 			} else if (utp->state & UTP_ST_ACTIVE) {
611 				if (utp->flags & UTP_FL_POLL_CARRIER)
612 					utopia_update_carrier(utp);
613 				utopia_update_stats(utp);
614 			}
615 			UTP_UNLOCK(utp);
616 			mtx_unlock(&Giant);	/* XXX depend on MPSAFE */
617 			utp = next;
618 		}
619 
620 		UTP_RLOCK_LIST();
621 		msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
622 	}
623 	wakeup_one(&utopia_list);
624 	UTP_RUNLOCK_LIST();
625 	kproc_exit(0);
626 }
627 
628 /*
629  * Module initialisation
630  */
631 static int
utopia_mod_init(module_t mod,int what,void * arg)632 utopia_mod_init(module_t mod, int what, void *arg)
633 {
634 	int err;
635 	struct proc *kp;
636 
637 	switch (what) {
638 
639 	  case MOD_LOAD:
640 		mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
641 		err = kproc_create(utopia_daemon, NULL, &utopia_kproc,
642 		    RFHIGHPID, 0, "utopia");
643 		if (err != 0) {
644 			printf("cannot created utopia thread %d\n", err);
645 			return (err);
646 		}
647 		break;
648 
649 	  case MOD_UNLOAD:
650 		UTP_WLOCK_LIST();
651 		if ((kp = utopia_kproc) != NULL) {
652 			utopia_kproc = NULL;
653 			wakeup_one(&utopia_list);
654 			PROC_LOCK(kp);
655 			UTP_WUNLOCK_LIST();
656 			msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
657 			PROC_UNLOCK(kp);
658 		} else
659 			UTP_WUNLOCK_LIST();
660 		mtx_destroy(&utopia_list_mtx);
661 		break;
662 	  default:
663 		return (EOPNOTSUPP);
664 	}
665 	return (0);
666 }
667 
668 static moduledata_t utopia_mod = {
669         "utopia",
670         utopia_mod_init,
671         0
672 };
673 
674 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
675 MODULE_VERSION(utopia, 1);
676