1139749Simp/*-
2116258Sharti * Copyright (c) 2003
3116258Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4116258Sharti * 	All rights reserved.
5116258Sharti *
6142384Sharti * Author: Hartmut Brandt <harti@freebsd.org>
7142384Sharti *
8116258Sharti * Redistribution and use in source and binary forms, with or without
9116258Sharti * modification, are permitted provided that the following conditions
10116258Sharti * are met:
11116258Sharti * 1. Redistributions of source code must retain the above copyright
12116258Sharti *    notice, this list of conditions and the following disclaimer.
13116258Sharti * 2. Redistributions in binary form must reproduce the above copyright
14116258Sharti *    notice, this list of conditions and the following disclaimer in the
15116258Sharti *    documentation and/or other materials provided with the distribution.
16116258Sharti *
17116258Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18116258Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19116258Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20116258Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21116258Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22116258Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23116258Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24116258Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25116258Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26116258Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27116258Sharti * SUCH DAMAGE.
28116258Sharti */
29116258Sharti
30116258Sharti#include <sys/cdefs.h>
31116258Sharti__FBSDID("$FreeBSD$");
32116258Sharti
33116258Sharti#include <sys/param.h>
34116258Sharti#include <sys/systm.h>
35116258Sharti#include <sys/unistd.h>
36116258Sharti#include <sys/kernel.h>
37116258Sharti#include <sys/kthread.h>
38116258Sharti#include <sys/proc.h>
39116258Sharti#include <sys/bus.h>
40116258Sharti#include <sys/malloc.h>
41129879Sphk#include <sys/module.h>
42116258Sharti#include <sys/sysctl.h>
43116258Sharti#include <sys/lock.h>
44116258Sharti#include <sys/mutex.h>
45116258Sharti#include <sys/socket.h>
46116258Sharti
47116258Sharti#include <net/if.h>
48116258Sharti#include <net/if_var.h>
49116258Sharti#include <net/if_media.h>
50116258Sharti#include <net/if_atm.h>
51116258Sharti
52116258Sharti#include <dev/utopia/suni.h>
53116258Sharti#include <dev/utopia/idtphy.h>
54116258Sharti#include <dev/utopia/utopia.h>
55142384Sharti#include <dev/utopia/utopia_priv.h>
56116258Sharti
57142384Sharti/* known chips */
58142384Shartiextern const struct utopia_chip utopia_chip_idt77155;
59142384Shartiextern const struct utopia_chip utopia_chip_idt77105;
60142384Shartiextern const struct utopia_chip utopia_chip_lite;
61142384Shartiextern const struct utopia_chip utopia_chip_ultra;
62142384Shartiextern const struct utopia_chip utopia_chip_622;
63116258Sharti
64116258Sharti/*
65116258Sharti * Global list of all registered interfaces
66116258Sharti */
67116258Shartistatic struct mtx utopia_list_mtx;
68116258Shartistatic LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
69116258Sharti
70116258Sharti#define UTP_RLOCK_LIST()	mtx_lock(&utopia_list_mtx)
71116258Sharti#define UTP_RUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
72116258Sharti#define UTP_WLOCK_LIST()	mtx_lock(&utopia_list_mtx)
73116258Sharti#define UTP_WUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
74116258Sharti
75116258Sharti#define UTP_LOCK(UTP)		mtx_lock((UTP)->lock)
76116258Sharti#define UTP_UNLOCK(UTP)		mtx_unlock((UTP)->lock)
77116258Sharti#define UTP_LOCK_ASSERT(UTP)	mtx_assert((UTP)->lock, MA_OWNED)
78116258Sharti
79116258Shartistatic struct proc *utopia_kproc;
80116258Sharti
81116258Shartistatic void utopia_dump(struct utopia *) __unused;
82116258Sharti
83116258Sharti/*
84142384Sharti * Read a multi-register value.
85117552Sharti */
86142384Shartiuint32_t
87142384Shartiutopia_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
88117552Sharti{
89117552Sharti	int err;
90117552Sharti	u_int n;
91117552Sharti	uint8_t regs[4];
92117552Sharti	uint32_t val;
93117552Sharti
94117552Sharti	n = nreg;
95142384Sharti	if ((err = UTP_READREGS(utp, reg, regs, &n)) != 0) {
96117552Sharti#ifdef DIAGNOSTIC
97117552Sharti		printf("%s: register read error %s(%u,%u): %d\n", __func__,
98117552Sharti		    utp->chip->name, reg, nreg, err);
99117552Sharti#endif
100117552Sharti		return (0);
101117552Sharti	}
102117552Sharti	if (n < nreg) {
103117552Sharti#ifdef DIAGNOSTIC
104117552Sharti		printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
105117552Sharti		    utp->chip->name, reg, nreg, err);
106117552Sharti#endif
107117552Sharti		return (0);
108117552Sharti	}
109117552Sharti	val = 0;
110117552Sharti	for (n = nreg; n > 0; n--) {
111117552Sharti		val <<= 8;
112117552Sharti		val |= regs[n - 1];
113117552Sharti	}
114117552Sharti	return (val & mask);
115117552Sharti}
116117552Sharti
117117552Sharti/*
118116258Sharti * Debugging - dump all registers.
119116258Sharti */
120116258Shartistatic void
121116258Shartiutopia_dump(struct utopia *utp)
122116258Sharti{
123116258Sharti	uint8_t regs[256];
124116258Sharti	u_int n = 256, i;
125116258Sharti	int err;
126116258Sharti
127142384Sharti	if ((err = UTP_READREGS(utp, 0, regs, &n)) != 0) {
128142384Sharti		printf("UTOPIA reg read error %d\n", err);
129116258Sharti		return;
130116258Sharti	}
131116258Sharti	for (i = 0; i < n; i++) {
132116258Sharti		if (i % 16 == 0)
133116258Sharti			printf("%02x:", i);
134116258Sharti		if (i % 16 == 8)
135116258Sharti			printf(" ");
136116258Sharti		printf(" %02x", regs[i]);
137116258Sharti		if (i % 16 == 15)
138116258Sharti			printf("\n");
139116258Sharti	}
140116258Sharti	if (i % 16 != 0)
141116258Sharti		printf("\n");
142116258Sharti}
143116258Sharti
144116258Sharti/*
145116258Sharti * Update the carrier status
146116258Sharti */
147142384Shartivoid
148116258Shartiutopia_check_carrier(struct utopia *utp, u_int carr_ok)
149116258Sharti{
150116258Sharti	int old;
151116258Sharti
152116258Sharti	old = utp->carrier;
153116258Sharti	if (carr_ok) {
154116258Sharti		/* carrier */
155116258Sharti		utp->carrier = UTP_CARR_OK;
156116258Sharti		if (old != UTP_CARR_OK) {
157147256Sbrooks			if_printf(utp->ifatm->ifp, "carrier detected\n");
158118202Sharti			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1);
159116258Sharti		}
160116258Sharti	} else {
161116258Sharti		/* no carrier */
162116258Sharti		utp->carrier = UTP_CARR_LOST;
163116258Sharti		if (old == UTP_CARR_OK) {
164147256Sbrooks			if_printf(utp->ifatm->ifp, "carrier lost\n");
165118202Sharti			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0);
166116258Sharti		}
167116258Sharti	}
168116258Sharti}
169116258Sharti
170116258Shartistatic int
171142384Shartiunknown_inval(struct utopia *utp, int what __unused)
172116258Sharti{
173116258Sharti
174116258Sharti	return (EINVAL);
175116258Sharti}
176116258Sharti
177116258Shartistatic int
178116258Shartiunknown_reset(struct utopia *utp __unused)
179116258Sharti{
180116258Sharti	return (EIO);
181116258Sharti}
182116258Sharti
183116258Shartistatic int
184116258Shartiunknown_update_carrier(struct utopia *utp)
185116258Sharti{
186116258Sharti	utp->carrier = UTP_CARR_UNKNOWN;
187116258Sharti	return (0);
188116258Sharti}
189116258Sharti
190116258Shartistatic int
191116258Shartiunknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
192116258Sharti{
193116258Sharti	return (EINVAL);
194116258Sharti}
195116258Sharti
196116258Shartistatic void
197116258Shartiunknown_intr(struct utopia *utp __unused)
198116258Sharti{
199116258Sharti}
200116258Sharti
201117552Shartistatic void
202117552Shartiunknown_update_stats(struct utopia *utp __unused)
203117552Sharti{
204117552Sharti}
205117552Sharti
206142384Shartistatic const struct utopia_chip utopia_chip_unknown = {
207116258Sharti	UTP_TYPE_UNKNOWN,
208116258Sharti	"unknown",
209116258Sharti	0,
210116258Sharti	unknown_reset,
211116258Sharti	unknown_inval,
212116258Sharti	unknown_inval,
213116258Sharti	unknown_inval,
214116258Sharti	unknown_update_carrier,
215116258Sharti	unknown_set_loopback,
216116258Sharti	unknown_intr,
217117552Sharti	unknown_update_stats,
218116258Sharti};
219116258Sharti
220116258Sharti/*
221116258Sharti * Callbacks for the ifmedia infrastructure.
222116258Sharti */
223116258Shartistatic int
224116258Shartiutopia_media_change(struct ifnet *ifp)
225116258Sharti{
226147526Sharti	struct ifatm *ifatm = IFP2IFATM(ifp);
227116258Sharti	struct utopia *utp = ifatm->phy;
228116258Sharti	int error = 0;
229116258Sharti
230116258Sharti	UTP_LOCK(utp);
231116258Sharti	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
232116258Sharti		if (utp->media->ifm_media & IFM_ATM_SDH) {
233116258Sharti			if (!(utp->state & UTP_ST_SDH))
234116258Sharti				error = utopia_set_sdh(utp, 1);
235116258Sharti		} else {
236116258Sharti			if (utp->state & UTP_ST_SDH)
237116258Sharti				error = utopia_set_sdh(utp, 0);
238116258Sharti		}
239116258Sharti		if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
240116258Sharti			if (!(utp->state & UTP_ST_UNASS))
241116258Sharti				error = utopia_set_unass(utp, 1);
242116258Sharti		} else {
243116258Sharti			if (utp->state & UTP_ST_UNASS)
244116258Sharti				error = utopia_set_unass(utp, 0);
245116258Sharti		}
246116258Sharti		if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
247116258Sharti			if (!(utp->state & UTP_ST_NOSCRAMB))
248116258Sharti				error = utopia_set_noscramb(utp, 1);
249116258Sharti		} else {
250116258Sharti			if (utp->state & UTP_ST_NOSCRAMB)
251116258Sharti				error = utopia_set_noscramb(utp, 0);
252116258Sharti		}
253116258Sharti	} else
254116258Sharti		error = EIO;
255116258Sharti	UTP_UNLOCK(utp);
256116258Sharti	return (error);
257116258Sharti}
258116258Sharti
259116258Sharti/*
260116258Sharti * Look at the carrier status.
261116258Sharti */
262116258Shartistatic void
263116258Shartiutopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
264116258Sharti{
265147526Sharti	struct utopia *utp = IFP2IFATM(ifp)->phy;
266116258Sharti
267116258Sharti	UTP_LOCK(utp);
268116258Sharti	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
269116258Sharti		ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
270116258Sharti
271116258Sharti		switch (utp->carrier) {
272116258Sharti
273116258Sharti		  case UTP_CARR_OK:
274116258Sharti			ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
275116258Sharti			break;
276116258Sharti
277116258Sharti		  case UTP_CARR_LOST:
278116258Sharti			ifmr->ifm_status = IFM_AVALID;
279116258Sharti			break;
280116258Sharti
281116258Sharti		  default:
282116258Sharti			ifmr->ifm_status = 0;
283116258Sharti			break;
284116258Sharti		}
285116258Sharti		if (utp->state & UTP_ST_SDH) {
286116258Sharti			ifmr->ifm_active |= IFM_ATM_SDH;
287116258Sharti			ifmr->ifm_current |= IFM_ATM_SDH;
288116258Sharti		}
289116258Sharti		if (utp->state & UTP_ST_UNASS) {
290116258Sharti			ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
291116258Sharti			ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
292116258Sharti		}
293116258Sharti		if (utp->state & UTP_ST_NOSCRAMB) {
294116258Sharti			ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
295116258Sharti			ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
296116258Sharti		}
297116258Sharti	} else {
298116258Sharti		ifmr->ifm_active = 0;
299116258Sharti		ifmr->ifm_status = 0;
300116258Sharti	}
301116258Sharti	UTP_UNLOCK(utp);
302116258Sharti}
303116258Sharti
304116258Sharti/*
305116258Sharti * Initialize media from the mib
306116258Sharti */
307116258Shartivoid
308116258Shartiutopia_init_media(struct utopia *utp)
309116258Sharti{
310116258Sharti
311116258Sharti	ifmedia_removeall(utp->media);
312116258Sharti	ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL);
313116258Sharti	ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media);
314116258Sharti}
315116258Sharti
316116258Sharti/*
317116258Sharti * Reset all media
318116258Sharti */
319116258Shartivoid
320116258Shartiutopia_reset_media(struct utopia *utp)
321116258Sharti{
322116258Sharti
323116258Sharti	ifmedia_removeall(utp->media);
324116258Sharti}
325116258Sharti
326116258Sharti/*
327116258Sharti * This is called by the driver as soon as the SUNI registers are accessible.
328116258Sharti * This may be either in the attach routine or the init routine of the driver.
329116258Sharti */
330116258Shartiint
331116258Shartiutopia_start(struct utopia *utp)
332116258Sharti{
333116258Sharti	uint8_t reg;
334116258Sharti	int err;
335116258Sharti	u_int n = 1;
336116258Sharti
337142384Sharti	/*
338142384Sharti	 * Try to find out what chip we have
339142384Sharti	 */
340142384Sharti	if ((err = UTP_READREGS(utp, SUNI_REGO_MRESET, &reg, &n)) != 0)
341116258Sharti		return (err);
342116258Sharti
343116258Sharti	switch (reg & SUNI_REGM_MRESET_TYPE) {
344116258Sharti
345116258Sharti	  case SUNI_REGM_MRESET_TYPE_622:
346142384Sharti		utp->chip = &utopia_chip_622;
347116258Sharti		break;
348116258Sharti
349116258Sharti	  case SUNI_REGM_MRESET_TYPE_LITE:
350117546Sharti		/* this may be either a SUNI LITE or a IDT77155 *
351117546Sharti		 * Read register 0x70. The SUNI doesn't have it */
352117546Sharti		n = 1;
353142384Sharti		if ((err = UTP_READREGS(utp, IDTPHY_REGO_RBER, &reg, &n)) != 0)
354117546Sharti			return (err);
355117546Sharti		if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
356117546Sharti		    (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
357142384Sharti			utp->chip = &utopia_chip_idt77155;
358117546Sharti		else
359142384Sharti			utp->chip = &utopia_chip_lite;
360116258Sharti		break;
361116258Sharti
362116258Sharti	  case SUNI_REGM_MRESET_TYPE_ULTRA:
363142384Sharti		utp->chip = &utopia_chip_ultra;
364116258Sharti		break;
365116258Sharti
366116258Sharti	  default:
367116258Sharti		if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
368142384Sharti			utp->chip = &utopia_chip_idt77105;
369116258Sharti		else {
370147256Sbrooks			if_printf(utp->ifatm->ifp,
371116258Sharti			    "unknown ATM-PHY chip %#x\n", reg);
372142384Sharti			utp->chip = &utopia_chip_unknown;
373116258Sharti		}
374116258Sharti		break;
375116258Sharti	}
376116258Sharti	utp->state |= UTP_ST_ACTIVE;
377116258Sharti	return (0);
378116258Sharti}
379116258Sharti
380116258Sharti/*
381116258Sharti * Stop the chip
382116258Sharti */
383116258Shartivoid
384116258Shartiutopia_stop(struct utopia *utp)
385116258Sharti{
386116258Sharti	utp->state &= ~UTP_ST_ACTIVE;
387116258Sharti}
388116258Sharti
389116258Sharti/*
390116258Sharti * Handle the sysctls
391116258Sharti */
392116258Shartistatic int
393116258Shartiutopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
394116258Sharti{
395116258Sharti	struct utopia *utp = (struct utopia *)arg1;
396116258Sharti	int error;
397116258Sharti	u_int n;
398116258Sharti	uint8_t *val;
399116258Sharti	uint8_t new[3];
400116258Sharti
401116258Sharti	if ((n = utp->chip->nregs) == 0)
402116258Sharti		return (EIO);
403116258Sharti	val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
404116258Sharti
405116258Sharti	UTP_LOCK(utp);
406142384Sharti	error = UTP_READREGS(utp, 0, val, &n);
407116258Sharti	UTP_UNLOCK(utp);
408116258Sharti
409116258Sharti	if (error) {
410116258Sharti		free(val, M_TEMP);
411116258Sharti		return (error);
412116258Sharti	}
413116258Sharti
414116258Sharti	error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
415116258Sharti	free(val, M_TEMP);
416116258Sharti	if (error != 0 || req->newptr == NULL)
417116258Sharti		return (error);
418116258Sharti
419116258Sharti	error = SYSCTL_IN(req, new, sizeof(new));
420116258Sharti	if (error)
421116258Sharti		return (error);
422116258Sharti
423116258Sharti	UTP_LOCK(utp);
424142384Sharti	error = UTP_WRITEREG(utp, new[0], new[1], new[2]);
425116258Sharti	UTP_UNLOCK(utp);
426116258Sharti
427116258Sharti	return (error);
428116258Sharti}
429116258Sharti
430117552Shartistatic int
431117552Shartiutopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
432117552Sharti{
433117552Sharti	struct utopia *utp = (struct utopia *)arg1;
434117552Sharti	void *val;
435117552Sharti	int error;
436117552Sharti
437117552Sharti	val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
438117552Sharti
439117552Sharti	UTP_LOCK(utp);
440117552Sharti	bcopy(&utp->stats, val, sizeof(utp->stats));
441117552Sharti	if (req->newptr != NULL)
442117552Sharti		bzero((char *)&utp->stats + sizeof(utp->stats.version),
443117552Sharti		    sizeof(utp->stats) - sizeof(utp->stats.version));
444117552Sharti	UTP_UNLOCK(utp);
445117552Sharti
446117552Sharti	error = SYSCTL_OUT(req, val, sizeof(utp->stats));
447117552Sharti	if (error && req->newptr != NULL)
448117552Sharti		bcopy(val, &utp->stats, sizeof(utp->stats));
449174318Sphilip	free(val, M_TEMP);
450117552Sharti
451117552Sharti	/* ignore actual new value */
452117552Sharti
453117552Sharti	return (error);
454117552Sharti}
455117552Sharti
456116258Sharti/*
457116258Sharti * Handle the loopback sysctl
458116258Sharti */
459116258Shartistatic int
460116258Shartiutopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
461116258Sharti{
462116258Sharti	struct utopia *utp = (struct utopia *)arg1;
463116258Sharti	int error;
464116258Sharti	u_int loopback;
465116258Sharti
466116258Sharti	error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
467116258Sharti	if (error != 0 || req->newptr == NULL)
468116258Sharti		return (error);
469116258Sharti
470116258Sharti	error = SYSCTL_IN(req, &loopback, sizeof(u_int));
471116258Sharti	if (error)
472116258Sharti		return (error);
473116258Sharti
474116258Sharti	UTP_LOCK(utp);
475116258Sharti	error = utopia_set_loopback(utp, loopback);
476116258Sharti	UTP_UNLOCK(utp);
477116258Sharti
478116258Sharti	return (error);
479116258Sharti}
480116258Sharti
481116258Sharti/*
482116258Sharti * Handle the type sysctl
483116258Sharti */
484116258Shartistatic int
485116258Shartiutopia_sysctl_type(SYSCTL_HANDLER_ARGS)
486116258Sharti{
487116258Sharti	struct utopia *utp = (struct utopia *)arg1;
488116258Sharti
489116258Sharti	return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
490116258Sharti}
491116258Sharti
492116258Sharti/*
493116258Sharti * Handle the name sysctl
494116258Sharti */
495116258Shartistatic int
496116258Shartiutopia_sysctl_name(SYSCTL_HANDLER_ARGS)
497116258Sharti{
498116258Sharti	struct utopia *utp = (struct utopia *)arg1;
499116258Sharti
500116258Sharti	return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
501116258Sharti}
502116258Sharti
503116258Sharti/*
504116258Sharti * Initialize the state. This is called from the drivers attach
505116258Sharti * function. The mutex must be already initialized.
506116258Sharti */
507116258Shartiint
508116258Shartiutopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
509116258Sharti    struct mtx *lock, struct sysctl_ctx_list *ctx,
510116258Sharti    struct sysctl_oid_list *children, const struct utopia_methods *m)
511116258Sharti{
512116258Sharti
513116258Sharti	bzero(utp, sizeof(*utp));
514116258Sharti	utp->ifatm = ifatm;
515116258Sharti	utp->methods = m;
516116258Sharti	utp->media = media;
517116258Sharti	utp->lock = lock;
518142384Sharti	utp->chip = &utopia_chip_unknown;
519117552Sharti	utp->stats.version = 1;
520116258Sharti
521116258Sharti	ifmedia_init(media,
522116258Sharti	    IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
523116258Sharti	    utopia_media_change, utopia_media_status);
524116258Sharti
525116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
526116258Sharti	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
527116258Sharti	    "phy registers") == NULL)
528116258Sharti		return (-1);
529116258Sharti
530116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
531116258Sharti	    CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
532116258Sharti	    "phy loopback mode") == NULL)
533116258Sharti		return (-1);
534116258Sharti
535116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
536116258Sharti	    CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
537116258Sharti	    "phy type") == NULL)
538116258Sharti		return (-1);
539116258Sharti
540116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
541116258Sharti	    CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
542116258Sharti	    "phy name") == NULL)
543116258Sharti		return (-1);
544116258Sharti
545117552Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
546117552Sharti	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
547117552Sharti	    "phy statistics") == NULL)
548117552Sharti		return (-1);
549117552Sharti
550118202Sharti	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
551118202Sharti	    CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
552118202Sharti		return (-1);
553118202Sharti
554118202Sharti	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
555118202Sharti	    CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
556118202Sharti		return (-1);
557118202Sharti
558116258Sharti	UTP_WLOCK_LIST();
559116258Sharti	LIST_INSERT_HEAD(&utopia_list, utp, link);
560116258Sharti	UTP_WUNLOCK_LIST();
561116258Sharti
562116258Sharti	utp->state |= UTP_ST_ATTACHED;
563116258Sharti	return (0);
564116258Sharti}
565116258Sharti
566116258Sharti/*
567116258Sharti * Detach. We set a flag here, wakeup the daemon and let him do it.
568116258Sharti * Here we need the lock for synchronisation with the daemon.
569116258Sharti */
570116258Shartivoid
571116258Shartiutopia_detach(struct utopia *utp)
572116258Sharti{
573116258Sharti
574116258Sharti	UTP_LOCK_ASSERT(utp);
575116258Sharti	if (utp->state & UTP_ST_ATTACHED) {
576116258Sharti		utp->state |= UTP_ST_DETACH;
577116258Sharti		while (utp->state & UTP_ST_DETACH) {
578116258Sharti			wakeup(&utopia_list);
579116258Sharti			msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
580116258Sharti		}
581116258Sharti	}
582116258Sharti}
583116258Sharti
584116258Sharti/*
585116258Sharti * The carrier state kernel proc for those adapters that do not interrupt.
586116258Sharti *
587116258Sharti * We assume, that utopia_attach can safely add a new utopia while we are going
588116258Sharti * through the list without disturbing us (we lock the list while getting
589116258Sharti * the address of the first element, adding is always done at the head).
590116258Sharti * Removing is entirely handled here.
591116258Sharti */
592116258Shartistatic void
593116258Shartiutopia_daemon(void *arg __unused)
594116258Sharti{
595116258Sharti	struct utopia *utp, *next;
596116258Sharti
597116258Sharti	UTP_RLOCK_LIST();
598116258Sharti	while (utopia_kproc != NULL) {
599116258Sharti		utp = LIST_FIRST(&utopia_list);
600116258Sharti		UTP_RUNLOCK_LIST();
601116258Sharti
602116258Sharti		while (utp != NULL) {
603116258Sharti			mtx_lock(&Giant);	/* XXX depend on MPSAFE */
604116258Sharti			UTP_LOCK(utp);
605116258Sharti			next = LIST_NEXT(utp, link);
606116258Sharti			if (utp->state & UTP_ST_DETACH) {
607116258Sharti				LIST_REMOVE(utp, link);
608116258Sharti				utp->state &= ~UTP_ST_DETACH;
609116258Sharti				wakeup_one(utp);
610117552Sharti			} else if (utp->state & UTP_ST_ACTIVE) {
611117552Sharti				if (utp->flags & UTP_FL_POLL_CARRIER)
612117552Sharti					utopia_update_carrier(utp);
613117552Sharti				utopia_update_stats(utp);
614116258Sharti			}
615116258Sharti			UTP_UNLOCK(utp);
616116258Sharti			mtx_unlock(&Giant);	/* XXX depend on MPSAFE */
617116258Sharti			utp = next;
618116258Sharti		}
619116258Sharti
620116258Sharti		UTP_RLOCK_LIST();
621117552Sharti		msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
622116258Sharti	}
623116258Sharti	wakeup_one(&utopia_list);
624116258Sharti	UTP_RUNLOCK_LIST();
625172836Sjulian	kproc_exit(0);
626116258Sharti}
627116258Sharti
628116258Sharti/*
629116258Sharti * Module initialisation
630116258Sharti */
631116258Shartistatic int
632116258Shartiutopia_mod_init(module_t mod, int what, void *arg)
633116258Sharti{
634116258Sharti	int err;
635116258Sharti	struct proc *kp;
636116258Sharti
637116258Sharti	switch (what) {
638116258Sharti
639116258Sharti	  case MOD_LOAD:
640116258Sharti		mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
641172836Sjulian		err = kproc_create(utopia_daemon, NULL, &utopia_kproc,
642116258Sharti		    RFHIGHPID, 0, "utopia");
643116258Sharti		if (err != 0) {
644116258Sharti			printf("cannot created utopia thread %d\n", err);
645116258Sharti			return (err);
646116258Sharti		}
647116258Sharti		break;
648116258Sharti
649116258Sharti	  case MOD_UNLOAD:
650116258Sharti		UTP_WLOCK_LIST();
651116258Sharti		if ((kp = utopia_kproc) != NULL) {
652116258Sharti			utopia_kproc = NULL;
653116258Sharti			wakeup_one(&utopia_list);
654116258Sharti			PROC_LOCK(kp);
655116258Sharti			UTP_WUNLOCK_LIST();
656116258Sharti			msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
657116258Sharti			PROC_UNLOCK(kp);
658116258Sharti		} else
659116258Sharti			UTP_WUNLOCK_LIST();
660116258Sharti		mtx_destroy(&utopia_list_mtx);
661116258Sharti		break;
662132199Sphk	  default:
663132199Sphk		return (EOPNOTSUPP);
664116258Sharti	}
665116258Sharti	return (0);
666116258Sharti}
667116258Sharti
668116258Shartistatic moduledata_t utopia_mod = {
669116258Sharti        "utopia",
670116258Sharti        utopia_mod_init,
671241394Skevlo        0
672116258Sharti};
673116258Sharti
674116258ShartiDECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
675116258ShartiMODULE_VERSION(utopia, 1);
676