utopia.c revision 118202
1116258Sharti/*
2116258Sharti * Copyright (c) 2003
3116258Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4116258Sharti * 	All rights reserved.
5116258Sharti *
6116258Sharti * Redistribution and use in source and binary forms, with or without
7116258Sharti * modification, are permitted provided that the following conditions
8116258Sharti * are met:
9116258Sharti * 1. Redistributions of source code must retain the above copyright
10116258Sharti *    notice, this list of conditions and the following disclaimer.
11116258Sharti * 2. Redistributions in binary form must reproduce the above copyright
12116258Sharti *    notice, this list of conditions and the following disclaimer in the
13116258Sharti *    documentation and/or other materials provided with the distribution.
14116258Sharti *
15116258Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116258Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116258Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116258Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116258Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116258Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116258Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116258Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116258Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116258Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116258Sharti * SUCH DAMAGE.
26116258Sharti *
27116258Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28116258Sharti */
29116258Sharti
30116258Sharti#include <sys/cdefs.h>
31116258Sharti__FBSDID("$FreeBSD: head/sys/dev/utopia/utopia.c 118202 2003-07-30 08:35:58Z harti $");
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>
41116258Sharti#include <sys/sysctl.h>
42116258Sharti#include <sys/lock.h>
43116258Sharti#include <sys/mutex.h>
44116258Sharti#include <sys/socket.h>
45116258Sharti
46116258Sharti#include <net/if.h>
47116258Sharti#include <net/if_var.h>
48116258Sharti#include <net/if_media.h>
49116258Sharti#include <net/if_atm.h>
50116258Sharti
51116258Sharti#include <dev/utopia/suni.h>
52116258Sharti#include <dev/utopia/idtphy.h>
53116258Sharti#include <dev/utopia/utopia.h>
54116258Sharti
55116258Sharti#define READREGS(UTOPIA, REG, VALP, NP)				\
56116258Sharti    (UTOPIA)->methods->readregs((UTOPIA)->ifatm, REG, VALP, NP)
57116258Sharti#define WRITEREG(UTOPIA, REG, MASK, VAL)			\
58116258Sharti    (UTOPIA)->methods->writereg((UTOPIA)->ifatm, REG, MASK, VAL)
59116258Sharti
60116258Sharti/*
61116258Sharti * Global list of all registered interfaces
62116258Sharti */
63116258Shartistatic struct mtx utopia_list_mtx;
64116258Shartistatic LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
65116258Sharti
66116258Sharti#define UTP_RLOCK_LIST()	mtx_lock(&utopia_list_mtx)
67116258Sharti#define UTP_RUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
68116258Sharti#define UTP_WLOCK_LIST()	mtx_lock(&utopia_list_mtx)
69116258Sharti#define UTP_WUNLOCK_LIST()	mtx_unlock(&utopia_list_mtx)
70116258Sharti
71116258Sharti#define UTP_LOCK(UTP)		mtx_lock((UTP)->lock)
72116258Sharti#define UTP_UNLOCK(UTP)		mtx_unlock((UTP)->lock)
73116258Sharti#define UTP_LOCK_ASSERT(UTP)	mtx_assert((UTP)->lock, MA_OWNED)
74116258Sharti
75116258Shartistatic struct proc *utopia_kproc;
76116258Sharti
77116258Shartistatic void utopia_dump(struct utopia *) __unused;
78116258Sharti
79116258Sharti/*
80117552Sharti * Statistics update inlines
81117552Sharti */
82117552Shartistatic uint32_t
83117552Shartiutp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
84117552Sharti{
85117552Sharti	int err;
86117552Sharti	u_int n;
87117552Sharti	uint8_t regs[4];
88117552Sharti	uint32_t val;
89117552Sharti
90117552Sharti	n = nreg;
91117552Sharti	if ((err = READREGS(utp, reg, regs, &n)) != 0) {
92117552Sharti#ifdef DIAGNOSTIC
93117552Sharti		printf("%s: register read error %s(%u,%u): %d\n", __func__,
94117552Sharti		    utp->chip->name, reg, nreg, err);
95117552Sharti#endif
96117552Sharti		return (0);
97117552Sharti	}
98117552Sharti	if (n < nreg) {
99117552Sharti#ifdef DIAGNOSTIC
100117552Sharti		printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
101117552Sharti		    utp->chip->name, reg, nreg, err);
102117552Sharti#endif
103117552Sharti		return (0);
104117552Sharti	}
105117552Sharti	val = 0;
106117552Sharti	for (n = nreg; n > 0; n--) {
107117552Sharti		val <<= 8;
108117552Sharti		val |= regs[n - 1];
109117552Sharti	}
110117552Sharti	return (val & mask);
111117552Sharti}
112117552Sharti
113117552Sharti#define	UPDATE8(UTP, REG)	utp_update(UTP, REG, 1, 0xff)
114117552Sharti#define	UPDATE12(UTP, REG)	utp_update(UTP, REG, 2, 0xfff)
115117552Sharti#define	UPDATE16(UTP, REG)	utp_update(UTP, REG, 2, 0xffff)
116117552Sharti#define	UPDATE19(UTP, REG)	utp_update(UTP, REG, 3, 0x7ffff)
117117552Sharti#define	UPDATE20(UTP, REG)	utp_update(UTP, REG, 3, 0xfffff)
118117552Sharti#define	UPDATE21(UTP, REG)	utp_update(UTP, REG, 3, 0x1fffff)
119117552Sharti
120117552Sharti/*
121116258Sharti * Debugging - dump all registers.
122116258Sharti */
123116258Shartistatic void
124116258Shartiutopia_dump(struct utopia *utp)
125116258Sharti{
126116258Sharti	uint8_t regs[256];
127116258Sharti	u_int n = 256, i;
128116258Sharti	int err;
129116258Sharti
130116258Sharti	if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
131116258Sharti		printf("SUNI read error %d\n", err);
132116258Sharti		return;
133116258Sharti	}
134116258Sharti	for (i = 0; i < n; i++) {
135116258Sharti		if (i % 16 == 0)
136116258Sharti			printf("%02x:", i);
137116258Sharti		if (i % 16 == 8)
138116258Sharti			printf(" ");
139116258Sharti		printf(" %02x", regs[i]);
140116258Sharti		if (i % 16 == 15)
141116258Sharti			printf("\n");
142116258Sharti	}
143116258Sharti	if (i % 16 != 0)
144116258Sharti		printf("\n");
145116258Sharti}
146116258Sharti
147116258Sharti/*
148116258Sharti * Update the carrier status
149116258Sharti */
150116258Shartistatic void
151116258Shartiutopia_check_carrier(struct utopia *utp, u_int carr_ok)
152116258Sharti{
153116258Sharti	int old;
154116258Sharti
155116258Sharti	old = utp->carrier;
156116258Sharti	if (carr_ok) {
157116258Sharti		/* carrier */
158116258Sharti		utp->carrier = UTP_CARR_OK;
159116258Sharti		if (old != UTP_CARR_OK) {
160116258Sharti			if_printf(&utp->ifatm->ifnet, "carrier detected\n");
161118202Sharti			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1);
162116258Sharti		}
163116258Sharti	} else {
164116258Sharti		/* no carrier */
165116258Sharti		utp->carrier = UTP_CARR_LOST;
166116258Sharti		if (old == UTP_CARR_OK) {
167116258Sharti			if_printf(&utp->ifatm->ifnet, "carrier lost\n");
168118202Sharti			ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0);
169116258Sharti		}
170116258Sharti	}
171116258Sharti}
172116258Sharti
173116258Shartistatic int
174116258Shartiutopia_update_carrier_default(struct utopia *utp)
175116258Sharti{
176116258Sharti	int err;
177116258Sharti	uint8_t reg;
178116258Sharti	u_int n = 1;
179116258Sharti
180116258Sharti	if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, &reg, &n)) != 0) {
181116258Sharti		utp->carrier = UTP_CARR_UNKNOWN;
182116258Sharti		return (err);
183116258Sharti	}
184116258Sharti	utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
185116258Sharti	return (0);
186116258Sharti}
187116258Sharti
188116258Sharti/*
189116258Sharti * enable/disable scrambling
190116258Sharti */
191116258Shartistatic int
192116258Shartiutopia_set_noscramb_default(struct utopia *utp, int noscramb)
193116258Sharti{
194116258Sharti	int err;
195116258Sharti
196116258Sharti	if (noscramb) {
197116258Sharti		err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
198116258Sharti		    SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
199116258Sharti		if (err)
200116258Sharti			return (err);
201116258Sharti		err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
202116258Sharti		    SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
203116258Sharti		if (err)
204116258Sharti			return (err);
205116258Sharti		utp->state |= UTP_ST_NOSCRAMB;
206116258Sharti	} else {
207116258Sharti		err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
208116258Sharti		    SUNI_REGM_TACPCTRL_DSCR, 0);
209116258Sharti		if (err)
210116258Sharti			return (err);
211116258Sharti		err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
212116258Sharti		    SUNI_REGM_RACPCTRL_DDSCR, 0);
213116258Sharti		if (err)
214116258Sharti			return (err);
215116258Sharti		utp->state &= ~UTP_ST_NOSCRAMB;
216116258Sharti	}
217116258Sharti	return (0);
218116258Sharti}
219116258Sharti
220116258Sharti/*
221116258Sharti * set SONET/SDH mode
222116258Sharti */
223116258Shartistatic int
224116258Shartiutopia_set_sdh_default(struct utopia *utp, int sdh)
225116258Sharti{
226116258Sharti	int err;
227116258Sharti
228116258Sharti	if (sdh)
229116258Sharti		err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
230116258Sharti		    SUNI_REGM_TPOPAPTR_S,
231116258Sharti		    SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
232116258Sharti	else
233116258Sharti		err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
234116258Sharti		    SUNI_REGM_TPOPAPTR_S,
235116258Sharti		    SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
236116258Sharti	if (err != 0)
237116258Sharti		return (err);
238116258Sharti
239116258Sharti	utp->state &= ~UTP_ST_SDH;
240116258Sharti	if (sdh)
241116258Sharti		utp->state |= UTP_ST_SDH;
242116258Sharti
243116258Sharti	return (0);
244116258Sharti}
245116258Sharti
246116258Sharti/*
247116258Sharti * set idle/unassigned cells
248116258Sharti */
249116258Shartistatic int
250116258Shartiutopia_set_unass_default(struct utopia *utp, int unass)
251116258Sharti{
252116258Sharti	int err;
253116258Sharti
254116258Sharti	if (unass)
255116258Sharti		err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
256116258Sharti		    0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
257116258Sharti	else
258116258Sharti		err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
259116258Sharti		    0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
260116258Sharti	if (err != 0)
261116258Sharti		return (err);
262116258Sharti
263116258Sharti	utp->state &= ~UTP_ST_UNASS;
264116258Sharti	if (unass)
265116258Sharti		utp->state |= UTP_ST_UNASS;
266116258Sharti
267116258Sharti	return (0);
268116258Sharti}
269116258Sharti
270116258Sharti/*
271116258Sharti * Set loopback mode for the Lite
272116258Sharti */
273116258Shartistatic int
274116258Shartiutopia_set_loopback_lite(struct utopia *utp, u_int mode)
275116258Sharti{
276116258Sharti	int err;
277116258Sharti	uint32_t val;
278116258Sharti	u_int nmode;
279116258Sharti
280116258Sharti	val = 0;
281116258Sharti	nmode = mode;
282116258Sharti	if (mode & UTP_LOOP_TIME) {
283116258Sharti		nmode &= ~UTP_LOOP_TIME;
284116258Sharti		val |= SUNI_REGM_MCTRL_LOOPT;
285116258Sharti	}
286116258Sharti	if (mode & UTP_LOOP_DIAG) {
287116258Sharti		nmode &= ~UTP_LOOP_DIAG;
288116258Sharti		val |= SUNI_REGM_MCTRL_DLE;
289116258Sharti	}
290116258Sharti	if (mode & UTP_LOOP_LINE) {
291116258Sharti		nmode &= ~UTP_LOOP_LINE;
292116258Sharti		if (val & SUNI_REGM_MCTRL_DLE)
293116258Sharti			return (EINVAL);
294116258Sharti		val |= SUNI_REGM_MCTRL_LLE;
295116258Sharti	}
296116258Sharti	if (nmode != 0)
297116258Sharti		return (EINVAL);
298116258Sharti
299116258Sharti	err = WRITEREG(utp, SUNI_REGO_MCTRL,
300116258Sharti	    SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
301116258Sharti	    val);
302116258Sharti	if (err)
303116258Sharti		return (err);
304116258Sharti	utp->loopback = mode;
305116258Sharti
306116258Sharti	return (0);
307116258Sharti}
308116258Sharti
309116258Sharti/*
310116258Sharti * Set loopback mode for the Ultra
311116258Sharti */
312116258Shartistatic int
313116258Shartiutopia_set_loopback_ultra(struct utopia *utp, u_int mode)
314116258Sharti{
315116258Sharti	int err;
316116258Sharti	uint32_t val;
317116258Sharti	u_int nmode;
318116258Sharti
319116258Sharti	val = 0;
320116258Sharti	nmode = mode;
321116258Sharti	if (mode & UTP_LOOP_TIME) {
322116258Sharti		nmode &= ~UTP_LOOP_TIME;
323116258Sharti		val |= SUNI_REGM_MCTRL_LOOPT;
324116258Sharti	}
325116258Sharti	if (mode & UTP_LOOP_DIAG) {
326116258Sharti		nmode &= ~UTP_LOOP_DIAG;
327116258Sharti		if (val & SUNI_REGM_MCTRL_LOOPT)
328116258Sharti			return (EINVAL);
329116258Sharti		val |= SUNI_REGM_MCTRL_SDLE;
330116258Sharti	}
331116258Sharti	if (mode & UTP_LOOP_LINE) {
332116258Sharti		nmode &= ~UTP_LOOP_LINE;
333116258Sharti		if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
334116258Sharti			return (EINVAL);
335116258Sharti		val |= SUNI_REGM_MCTRL_LLE;
336116258Sharti	}
337116258Sharti	if (mode & UTP_LOOP_PARAL) {
338116258Sharti		nmode &= ~UTP_LOOP_PARAL;
339116258Sharti		val |= SUNI_REGM_MCTRL_PDLE;
340116258Sharti	}
341116258Sharti	if (mode & UTP_LOOP_TWIST) {
342116258Sharti		nmode &= ~UTP_LOOP_TWIST;
343116258Sharti		val |= SUNI_REGM_MCTRL_TPLE;
344116258Sharti	}
345116258Sharti	if (nmode != 0)
346116258Sharti		return (EINVAL);
347116258Sharti
348116258Sharti	err = WRITEREG(utp, SUNI_REGO_MCTRL,
349116258Sharti	    SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT |
350116258Sharti	    SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val);
351116258Sharti	if (err)
352116258Sharti		return (err);
353116258Sharti	utp->loopback = mode;
354116258Sharti
355116258Sharti	return (0);
356116258Sharti}
357116258Sharti
358116258Sharti/*
359116258Sharti * Set loopback mode for the Ultra
360116258Sharti */
361116258Shartistatic int
362116258Shartiutopia_set_loopback_622(struct utopia *utp, u_int mode)
363116258Sharti{
364116258Sharti	int err;
365116258Sharti	uint32_t val;
366116258Sharti	uint8_t config;
367116258Sharti	int smode;
368116258Sharti	u_int nmode;
369116258Sharti	u_int n = 1;
370116258Sharti
371116258Sharti	val = 0;
372116258Sharti	nmode = mode;
373116258Sharti	if (mode & UTP_LOOP_PATH) {
374116258Sharti		nmode &= ~UTP_LOOP_PATH;
375116258Sharti		val |= SUNI_REGM_MCTRLM_DPLE;
376116258Sharti	}
377116258Sharti
378116258Sharti	err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
379116258Sharti	if (err != 0)
380116258Sharti		return (err);
381116258Sharti	smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) ==
382116258Sharti	    SUNI_REGM_MCONFIG_TMODE_STS1_BIT &&
383116258Sharti	    (config & SUNI_REGM_MCONFIG_RMODE_622) ==
384116258Sharti	    SUNI_REGM_MCONFIG_RMODE_STS1_BIT);
385116258Sharti
386116258Sharti	if (mode & UTP_LOOP_TIME) {
387116258Sharti		if (!smode)
388116258Sharti			return (EINVAL);
389116258Sharti		nmode &= ~UTP_LOOP_TIME;
390116258Sharti		val |= SUNI_REGM_MCTRLM_LOOPT;
391116258Sharti	}
392116258Sharti	if (mode & UTP_LOOP_DIAG) {
393116258Sharti		nmode &= ~UTP_LOOP_DIAG;
394116258Sharti		if (val & SUNI_REGM_MCTRLM_LOOPT)
395116258Sharti			return (EINVAL);
396116258Sharti		val |= SUNI_REGM_MCTRLM_DLE;
397116258Sharti	}
398116258Sharti	if (mode & UTP_LOOP_LINE) {
399116258Sharti		nmode &= ~UTP_LOOP_LINE;
400116258Sharti		if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
401116258Sharti			return (EINVAL);
402116258Sharti		val |= SUNI_REGM_MCTRLM_LLE;
403116258Sharti	}
404116258Sharti	if (nmode != 0)
405116258Sharti		return (EINVAL);
406116258Sharti
407116258Sharti	err = WRITEREG(utp, SUNI_REGO_MCTRLM,
408116258Sharti	    SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE |
409116258Sharti	    SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val);
410116258Sharti	if (err)
411116258Sharti		return (err);
412116258Sharti	utp->loopback = mode;
413116258Sharti
414116258Sharti	return (0);
415116258Sharti}
416116258Sharti
417116258Sharti/*
418116258Sharti * Set the SUNI chip to reflect the current state in utopia.
419116258Sharti * Assume, that the chip has been reset.
420116258Sharti */
421116258Shartistatic int
422116258Shartiutopia_set_chip(struct utopia *utp)
423116258Sharti{
424116258Sharti	int err = 0;
425116258Sharti
426116258Sharti	/* set sonet/sdh */
427116258Sharti	err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
428116258Sharti
429116258Sharti	/* unassigned or idle cells */
430116258Sharti	err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS);
431116258Sharti	err |= WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a);
432116258Sharti
433116258Sharti	/* loopback */
434116258Sharti	err |= utopia_set_loopback(utp, utp->loopback);
435116258Sharti
436116258Sharti	/* update carrier state */
437116258Sharti	err |= utopia_update_carrier(utp);
438116258Sharti
439116258Sharti	/* enable interrupts on LOS */
440116258Sharti	err |= WRITEREG(utp, SUNI_REGO_RSOPCIE,
441116258Sharti	    SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
442116258Sharti
443116258Sharti	return (err ? EIO : 0);
444116258Sharti}
445116258Sharti
446116258Sharti/*
447116258Sharti * Reset the SUNI chip to reflect the current state of utopia.
448116258Sharti */
449116258Shartistatic int
450116258Shartiutopia_reset_default(struct utopia *utp)
451116258Sharti{
452116258Sharti	int err = 0;
453116258Sharti
454116258Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
455116258Sharti		err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
456116258Sharti		    SUNI_REGM_MRESET_RESET);
457116258Sharti		err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
458116258Sharti		    0);
459116258Sharti	}
460116258Sharti
461116258Sharti	/* disable test mode */
462116258Sharti	err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
463116258Sharti
464116258Sharti	err |= utopia_set_chip(utp);
465116258Sharti
466116258Sharti	return (err ? EIO : 0);
467116258Sharti}
468116258Sharti
469116258Sharti/*
470116258Sharti * Reset the SUNI chip to reflect the current state of utopia.
471116258Sharti */
472116258Shartistatic int
473116258Shartiutopia_reset_622(struct utopia *utp)
474116258Sharti{
475116258Sharti	int err = 0;
476116258Sharti
477116258Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
478116258Sharti		err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
479116258Sharti		    SUNI_REGM_MRESET_RESET);
480116258Sharti		err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
481116258Sharti		    0);
482116258Sharti	}
483116258Sharti
484116258Sharti	/* disable test mode */
485116258Sharti	err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
486116258Sharti	    SUNI_REGM_MTEST_DS27_53_622);
487116258Sharti
488116258Sharti	err |= utopia_set_chip(utp);
489116258Sharti
490116258Sharti	return (err ? EIO : 0);
491116258Sharti}
492116258Sharti
493116258Sharti/*
494116258Sharti * Handle interrupt on lite chip
495116258Sharti */
496116258Shartistatic void
497116258Shartiutopia_intr_default(struct utopia *utp)
498116258Sharti{
499116258Sharti	uint8_t regs[SUNI_REGO_MTEST];
500116258Sharti	u_int n = SUNI_REGO_MTEST;
501116258Sharti	int err;
502116258Sharti
503116258Sharti	/* Read all registers. This acks the interrupts */
504116258Sharti	if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
505116258Sharti		printf("SUNI read error %d\n", err);
506116258Sharti		return;
507116258Sharti	}
508116258Sharti	if (n <= SUNI_REGO_RSOPSIS) {
509116258Sharti		printf("%s: could not read RSOPSIS", __func__);
510116258Sharti		return;
511116258Sharti	}
512116258Sharti	/* check for LOSI (loss of signal) */
513116258Sharti	if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) &&
514116258Sharti	    (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI))
515116258Sharti		utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS]
516116258Sharti		    & SUNI_REGM_RSOPSIS_LOSV));
517116258Sharti}
518116258Sharti
519117552Sharti/*
520117552Sharti * Update statistics from a SUNI/LITE or SUNI/ULTRA
521117552Sharti */
522117552Shartistatic void
523117552Shartisuni_lite_update_stats(struct utopia *utp)
524117552Sharti{
525117552Sharti	int err;
526117552Sharti
527117552Sharti	/* write to the master if we can */
528117552Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
529117552Sharti		err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
530117552Sharti	} else {
531117552Sharti		err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
532117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
533117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
534117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
535117552Sharti		err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
536117552Sharti
537117552Sharti	}
538117552Sharti	if (err) {
539117552Sharti#ifdef DIAGNOSTIC
540117552Sharti		printf("%s: register write error %s: %d\n", __func__,
541117552Sharti		    utp->chip->name, err);
542117552Sharti#endif
543117552Sharti		return;
544117552Sharti	}
545117552Sharti
546117552Sharti	DELAY(8);
547117552Sharti
548117552Sharti	utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8);
549117552Sharti	utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24);
550117552Sharti	utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE);
551117552Sharti	utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8);
552117552Sharti	utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE);
553117552Sharti	utp->stats.rx_corr += UPDATE8(utp, SUNI_REGO_RACPCHCS);
554117552Sharti	utp->stats.rx_uncorr += UPDATE8(utp, SUNI_REGO_RACPUHCS);
555117552Sharti	utp->stats.rx_cells += UPDATE19(utp, SUNI_REGO_RACPCNT);
556117552Sharti	utp->stats.tx_cells += UPDATE19(utp, SUNI_REGO_TACPCNT);
557117552Sharti}
558117552Sharti
559117552Sharti/*
560117552Sharti * Update statistics from a SUNI/622
561117552Sharti */
562117552Shartistatic void
563117552Shartisuni_622_update_stats(struct utopia *utp)
564117552Sharti{
565117552Sharti	int err;
566117552Sharti
567117552Sharti	/* write to the master if we can */
568117552Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
569117552Sharti		err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
570117552Sharti	} else {
571117552Sharti		err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
572117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
573117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
574117552Sharti		err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
575117552Sharti		err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
576117552Sharti	}
577117552Sharti	if (err) {
578117552Sharti#ifdef DIAGNOSTIC
579117552Sharti		printf("%s: register write error %s: %d\n", __func__,
580117552Sharti		    utp->chip->name, err);
581117552Sharti#endif
582117552Sharti		return;
583117552Sharti	}
584117552Sharti
585117552Sharti	DELAY(8);
586117552Sharti
587117552Sharti	utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8);
588117552Sharti	utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24);
589117552Sharti	utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE);
590117552Sharti	utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8);
591117552Sharti	utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE);
592117552Sharti	utp->stats.rx_corr += UPDATE12(utp, SUNI_REGO_RACPCHCS_622);
593117552Sharti	utp->stats.rx_uncorr += UPDATE12(utp, SUNI_REGO_RACPUHCS_622);
594117552Sharti	utp->stats.rx_cells += UPDATE21(utp, SUNI_REGO_RACPCNT_622);
595117552Sharti	utp->stats.tx_cells += UPDATE21(utp, SUNI_REGO_TACPCNT);
596117552Sharti}
597117552Sharti
598116258Shartistatic const struct utopia_chip chip_622 = {
599116258Sharti	UTP_TYPE_SUNI_622,
600116258Sharti	"Suni/622 (PMC-5355)",
601116258Sharti	256,
602116258Sharti	utopia_reset_622,
603116258Sharti	utopia_set_sdh_default,
604116258Sharti	utopia_set_unass_default,
605116258Sharti	utopia_set_noscramb_default,
606116258Sharti	utopia_update_carrier_default,
607116258Sharti	utopia_set_loopback_622,
608116258Sharti	utopia_intr_default,
609117552Sharti	suni_622_update_stats,
610116258Sharti};
611116258Shartistatic const struct utopia_chip chip_lite = {
612116258Sharti	UTP_TYPE_SUNI_LITE,
613116258Sharti	"Suni/Lite (PMC-5346)",
614116258Sharti	256,
615116258Sharti	utopia_reset_default,
616116258Sharti	utopia_set_sdh_default,
617116258Sharti	utopia_set_unass_default,
618116258Sharti	utopia_set_noscramb_default,
619116258Sharti	utopia_update_carrier_default,
620116258Sharti	utopia_set_loopback_lite,
621116258Sharti	utopia_intr_default,
622117552Sharti	suni_lite_update_stats,
623116258Sharti};
624116258Shartistatic const struct utopia_chip chip_ultra = {
625116258Sharti	UTP_TYPE_SUNI_ULTRA,
626116258Sharti	"Suni/Ultra (PMC-5350)",
627116258Sharti	256,
628116258Sharti	utopia_reset_default,
629116258Sharti	utopia_set_sdh_default,
630116258Sharti	utopia_set_unass_default,
631116258Sharti	utopia_set_noscramb_default,
632116258Sharti	utopia_update_carrier_default,
633116258Sharti	utopia_set_loopback_ultra,
634116258Sharti	utopia_intr_default,
635117552Sharti	suni_lite_update_stats,
636116258Sharti};
637116258Sharti
638116258Sharti/*
639116258Sharti * Reset IDT77105. There is really no way to reset this thing by acessing
640116258Sharti * the registers. Load the registers with default values.
641116258Sharti */
642116258Shartistatic int
643116258Shartiidt77105_reset(struct utopia *utp)
644116258Sharti{
645116258Sharti	int err = 0;
646116258Sharti	u_int n;
647116258Sharti	uint8_t val[2];
648116258Sharti
649116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
650116258Sharti	    IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
651116258Sharti	n = 1;
652116258Sharti	err |= READREGS(utp, IDTPHY_REGO_ISTAT, val, &n);
653116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0);
654116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0);
655116258Sharti
656116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
657116258Sharti	n = 2;
658116258Sharti	err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
659116258Sharti
660116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
661116258Sharti	n = 2;
662116258Sharti	err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
663116258Sharti
664116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
665116258Sharti	n = 2;
666116258Sharti	err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
667116258Sharti
668116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
669116258Sharti	n = 2;
670116258Sharti	err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
671116258Sharti
672116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC,
673116258Sharti	    IDTPHY_REGM_MCR_DREC);
674116258Sharti	err |= WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH,
675116258Sharti	    IDTPHY_REGM_DIAG_RFLUSH);
676116258Sharti
677116258Sharti	/* loopback */
678116258Sharti	err |= utopia_set_loopback(utp, utp->loopback);
679116258Sharti
680116258Sharti	/* update carrier state */
681116258Sharti	err |= utopia_update_carrier(utp);
682116258Sharti
683116258Sharti	return (err ? EIO : 0);
684116258Sharti}
685116258Sharti
686116258Shartistatic int
687116258Shartiunknown_inval(struct utopia *utp, int what __unused)
688116258Sharti{
689116258Sharti	return (EINVAL);
690116258Sharti}
691116258Sharti
692116258Shartistatic int
693116258Shartiidt77105_update_carrier(struct utopia *utp)
694116258Sharti{
695116258Sharti	int err;
696116258Sharti	uint8_t reg;
697116258Sharti	u_int n = 1;
698116258Sharti
699116258Sharti	if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
700116258Sharti		utp->carrier = UTP_CARR_UNKNOWN;
701116258Sharti		return (err);
702116258Sharti	}
703116258Sharti	utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
704116258Sharti	return (0);
705116258Sharti}
706116258Sharti
707116258Shartistatic int
708116258Shartiidt77105_set_loopback(struct utopia *utp, u_int mode)
709116258Sharti{
710116258Sharti	int err;
711116258Sharti
712116258Sharti	switch (mode) {
713116258Sharti	  case UTP_LOOP_NONE:
714116258Sharti		err = WRITEREG(utp, IDTPHY_REGO_DIAG,
715116258Sharti		    IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
716116258Sharti		break;
717116258Sharti
718116258Sharti	  case UTP_LOOP_DIAG:
719116258Sharti		err = WRITEREG(utp, IDTPHY_REGO_DIAG,
720116258Sharti		    IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
721116258Sharti		break;
722116258Sharti
723116258Sharti	  case UTP_LOOP_LINE:
724116258Sharti		err = WRITEREG(utp, IDTPHY_REGO_DIAG,
725116258Sharti		    IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
726116258Sharti		break;
727116258Sharti
728116258Sharti	  default:
729116258Sharti		return (EINVAL);
730116258Sharti	}
731116258Sharti	if (err)
732116258Sharti		return (err);
733116258Sharti	utp->loopback = mode;
734116258Sharti	return (0);
735116258Sharti}
736116258Sharti
737116258Sharti/*
738116258Sharti * Handle interrupt on IDT77105 chip
739116258Sharti */
740116258Shartistatic void
741116258Shartiidt77105_intr(struct utopia *utp)
742116258Sharti{
743116258Sharti	uint8_t reg;
744116258Sharti	u_int n = 1;
745116258Sharti	int err;
746116258Sharti
747116258Sharti	/* Interrupt status and ack the interrupt */
748116258Sharti	if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
749116258Sharti		printf("IDT77105 read error %d\n", err);
750116258Sharti		return;
751116258Sharti	}
752116258Sharti	/* check for signal condition */
753116258Sharti	utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
754116258Sharti}
755116258Sharti
756117552Shartistatic void
757117552Shartiidt77105_update_stats(struct utopia *utp)
758117552Sharti{
759117552Sharti	int err = 0;
760117552Sharti	uint8_t regs[2];
761117552Sharti	u_int n;
762117552Sharti
763117552Sharti#ifdef DIAGNOSTIC
764117552Sharti#define UDIAG(F,A,B)	printf(F, A, B)
765117552Sharti#else
766117552Sharti#define	UDIAG(F,A,B)	do { } while (0)
767117552Sharti#endif
768117552Sharti
769117552Sharti#define	UPD(FIELD, CODE, N, MASK)					\
770117552Sharti	err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE);		\
771117552Sharti	if (err != 0) {							\
772117552Sharti		UDIAG("%s: cannot write CNTS: %d\n", __func__, err);	\
773117552Sharti		return;							\
774117552Sharti	}								\
775117552Sharti	n = N;								\
776117552Sharti	err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n);			\
777117552Sharti	if (err != 0) {							\
778117552Sharti		UDIAG("%s: cannot read CNT: %d\n", __func__, err);	\
779117552Sharti		return;							\
780117552Sharti	}								\
781117552Sharti	if (n != N) {							\
782117552Sharti		UDIAG("%s: got only %u registers\n", __func__, n);	\
783117552Sharti		return;							\
784117552Sharti	}								\
785117552Sharti	if (N == 1)							\
786117552Sharti		utp->stats.FIELD += (regs[0] & MASK);			\
787117552Sharti	else								\
788117552Sharti		utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
789117552Sharti
790117552Sharti	UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff);
791117552Sharti	UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff);
792117552Sharti	UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff);
793117552Sharti	UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f);
794117552Sharti
795117552Sharti#undef	UDIAG
796117552Sharti#undef	UPD
797117552Sharti}
798117552Sharti
799116258Shartistatic const struct utopia_chip chip_idt77105 = {
800116258Sharti	UTP_TYPE_IDT77105,
801116258Sharti	"IDT77105",
802116258Sharti	7,
803116258Sharti	idt77105_reset,
804116258Sharti	unknown_inval,
805116258Sharti	unknown_inval,
806116258Sharti	unknown_inval,
807116258Sharti	idt77105_update_carrier,
808116258Sharti	idt77105_set_loopback,
809116258Sharti	idt77105_intr,
810117552Sharti	idt77105_update_stats,
811116258Sharti};
812116258Sharti
813117546Sharti/*
814117546Sharti * Update the carrier status
815117546Sharti */
816116258Shartistatic int
817117546Shartiidt77155_update_carrier(struct utopia *utp)
818117546Sharti{
819117546Sharti	int err;
820117546Sharti	uint8_t reg;
821117546Sharti	u_int n = 1;
822117546Sharti
823117546Sharti	if ((err = READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
824117546Sharti		utp->carrier = UTP_CARR_UNKNOWN;
825117546Sharti		return (err);
826117546Sharti	}
827117546Sharti	utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
828117546Sharti	return (0);
829117546Sharti}
830117546Sharti
831117546Sharti/*
832117546Sharti * Handle interrupt on IDT77155 chip
833117546Sharti */
834117546Shartistatic void
835117546Shartiidt77155_intr(struct utopia *utp)
836117546Sharti{
837117546Sharti	uint8_t reg;
838117546Sharti	u_int n = 1;
839117546Sharti	int err;
840117546Sharti
841117546Sharti	if ((err = READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
842117546Sharti		printf("IDT77105 read error %d\n", err);
843117546Sharti		return;
844117546Sharti	}
845117546Sharti	utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
846117546Sharti}
847117546Sharti
848117546Sharti/*
849117546Sharti * set SONET/SDH mode
850117546Sharti */
851117546Shartistatic int
852117546Shartiidt77155_set_sdh(struct utopia *utp, int sdh)
853117546Sharti{
854117546Sharti	int err;
855117546Sharti
856117546Sharti	if (sdh)
857117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_PTRM,
858117546Sharti		    IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
859117546Sharti	else
860117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_PTRM,
861117546Sharti		    IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
862117546Sharti	if (err != 0)
863117546Sharti		return (err);
864117546Sharti
865117546Sharti	utp->state &= ~UTP_ST_SDH;
866117546Sharti	if (sdh)
867117546Sharti		utp->state |= UTP_ST_SDH;
868117546Sharti
869117546Sharti	return (0);
870117546Sharti}
871117546Sharti
872117546Sharti/*
873117546Sharti * set idle/unassigned cells
874117546Sharti */
875117546Shartistatic int
876117546Shartiidt77155_set_unass(struct utopia *utp, int unass)
877117546Sharti{
878117546Sharti	int err;
879117546Sharti
880117546Sharti	if (unass)
881117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
882117546Sharti	else
883117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
884117546Sharti	if (err != 0)
885117546Sharti		return (err);
886117546Sharti
887117546Sharti	utp->state &= ~UTP_ST_UNASS;
888117546Sharti	if (unass)
889117546Sharti		utp->state |= UTP_ST_UNASS;
890117546Sharti
891117546Sharti	return (0);
892117546Sharti}
893117546Sharti
894117546Sharti/*
895117546Sharti * enable/disable scrambling
896117546Sharti */
897117546Shartistatic int
898117546Shartiidt77155_set_noscramb(struct utopia *utp, int noscramb)
899117546Sharti{
900117546Sharti	int err;
901117546Sharti
902117546Sharti	if (noscramb) {
903117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_TCC,
904117546Sharti		    IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
905117546Sharti		if (err)
906117546Sharti			return (err);
907117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_RCC,
908117546Sharti		    IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
909117546Sharti		if (err)
910117546Sharti			return (err);
911117546Sharti		utp->state |= UTP_ST_NOSCRAMB;
912117546Sharti	} else {
913117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_TCC,
914117546Sharti		    IDTPHY_REGM_TCC_DSCR, 0);
915117546Sharti		if (err)
916117546Sharti			return (err);
917117546Sharti		err = WRITEREG(utp, IDTPHY_REGO_RCC,
918117546Sharti		    IDTPHY_REGM_RCC_DSCR, 0);
919117546Sharti		if (err)
920117546Sharti			return (err);
921117546Sharti		utp->state &= ~UTP_ST_NOSCRAMB;
922117546Sharti	}
923117546Sharti	return (0);
924117546Sharti}
925117546Sharti
926117546Sharti/*
927117546Sharti * Set loopback mode for the 77155
928117546Sharti */
929117546Shartistatic int
930117546Shartiidt77155_set_loopback(struct utopia *utp, u_int mode)
931117546Sharti{
932117546Sharti	int err;
933117546Sharti	uint32_t val;
934117546Sharti	u_int nmode;
935117546Sharti
936117546Sharti	val = 0;
937117546Sharti	nmode = mode;
938117546Sharti	if (mode & UTP_LOOP_TIME) {
939117546Sharti		nmode &= ~UTP_LOOP_TIME;
940117546Sharti		val |= IDTPHY_REGM_MCTL_TLOOP;
941117546Sharti	}
942117546Sharti	if (mode & UTP_LOOP_DIAG) {
943117546Sharti		nmode &= ~UTP_LOOP_DIAG;
944117546Sharti		val |= IDTPHY_REGM_MCTL_DLOOP;
945117546Sharti	}
946117546Sharti	if (mode & UTP_LOOP_LINE) {
947117546Sharti		nmode &= ~UTP_LOOP_LINE;
948117546Sharti		val |= IDTPHY_REGM_MCTL_LLOOP;
949117546Sharti	}
950117546Sharti	if (nmode != 0)
951117546Sharti		return (EINVAL);
952117546Sharti
953117546Sharti	err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
954117546Sharti	    IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
955117546Sharti	if (err)
956117546Sharti		return (err);
957117546Sharti	utp->loopback = mode;
958117546Sharti
959117546Sharti	return (0);
960117546Sharti}
961117546Sharti
962117546Sharti/*
963117546Sharti * Set the chip to reflect the current state in utopia.
964117546Sharti * Assume, that the chip has been reset.
965117546Sharti */
966117546Shartistatic int
967117546Shartiidt77155_set_chip(struct utopia *utp)
968117546Sharti{
969117546Sharti	int err = 0;
970117546Sharti
971117546Sharti	/* set sonet/sdh */
972117546Sharti	err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
973117546Sharti
974117546Sharti	/* unassigned or idle cells */
975117546Sharti	err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
976117546Sharti
977117546Sharti	/* loopback */
978117546Sharti	err |= idt77155_set_loopback(utp, utp->loopback);
979117546Sharti
980117546Sharti	/* update carrier state */
981117546Sharti	err |= idt77155_update_carrier(utp);
982117546Sharti
983117546Sharti	/* enable interrupts on LOS */
984117546Sharti	err |= WRITEREG(utp, IDTPHY_REGO_INT,
985117546Sharti	    IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI);
986117546Sharti	err |= WRITEREG(utp, IDTPHY_REGO_RSOC,
987117546Sharti	    IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI);
988117546Sharti
989117546Sharti	return (err ? EIO : 0);
990117546Sharti}
991117546Sharti
992117546Sharti/*
993117546Sharti * Reset the chip to reflect the current state of utopia.
994117546Sharti */
995117546Shartistatic int
996117546Shartiidt77155_reset(struct utopia *utp)
997117546Sharti{
998117546Sharti	int err = 0;
999117546Sharti
1000117546Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
1001117546Sharti		err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET,
1002117546Sharti		    IDTPHY_REGM_MRID_RESET);
1003117546Sharti		err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET,
1004117546Sharti		    0);
1005117546Sharti	}
1006117546Sharti
1007117546Sharti	err |= idt77155_set_chip(utp);
1008117546Sharti
1009117546Sharti	return (err ? EIO : 0);
1010117546Sharti}
1011117546Sharti
1012117552Sharti/*
1013117552Sharti * Update statistics from a IDT77155
1014117552Sharti * This appears to be the same as for the Suni/Lite and Ultra. IDT however
1015117552Sharti * makes no assessment about the transfer time. Assume 7us.
1016117552Sharti */
1017117552Shartistatic void
1018117552Shartiidt77155_update_stats(struct utopia *utp)
1019117552Sharti{
1020117552Sharti	int err;
1021117552Sharti
1022117552Sharti	/* write to the master if we can */
1023117552Sharti	if (!(utp->flags & UTP_FL_NORESET)) {
1024117552Sharti		err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
1025117552Sharti	} else {
1026117552Sharti		err = WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0);
1027117552Sharti		err |= WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0);
1028117552Sharti		err |= WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0);
1029117552Sharti		err |= WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0);
1030117552Sharti		err |= WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0);
1031117552Sharti
1032117552Sharti	}
1033117552Sharti	if (err) {
1034117552Sharti#ifdef DIAGNOSTIC
1035117552Sharti		printf("%s: register write error %s: %d\n", __func__,
1036117552Sharti		    utp->chip->name, err);
1037117552Sharti#endif
1038117552Sharti		return;
1039117552Sharti	}
1040117552Sharti
1041117552Sharti	DELAY(8);
1042117552Sharti
1043117552Sharti	utp->stats.rx_sbip += UPDATE16(utp, IDTPHY_REGO_BIPC);
1044117552Sharti	utp->stats.rx_lbip += UPDATE20(utp, IDTPHY_REGO_B2EC);
1045117552Sharti	utp->stats.rx_lfebe += UPDATE20(utp, IDTPHY_REGO_FEBEC);
1046117552Sharti	utp->stats.rx_pbip += UPDATE16(utp, IDTPHY_REGO_B3EC);
1047117552Sharti	utp->stats.rx_pfebe += UPDATE16(utp, IDTPHY_REGO_PFEBEC);
1048117552Sharti	utp->stats.rx_corr += UPDATE8(utp, IDTPHY_REGO_CEC);
1049117552Sharti	utp->stats.rx_uncorr += UPDATE8(utp, IDTPHY_REGO_UEC);
1050117552Sharti	utp->stats.rx_cells += UPDATE19(utp, IDTPHY_REGO_RCCNT);
1051117552Sharti	utp->stats.tx_cells += UPDATE19(utp, IDTPHY_REGO_TXCNT);
1052117552Sharti}
1053117552Sharti
1054117552Sharti
1055117546Shartistatic const struct utopia_chip chip_idt77155 = {
1056117546Sharti	UTP_TYPE_IDT77155,
1057117546Sharti	"IDT77155",
1058117546Sharti	0x80,
1059117546Sharti	idt77155_reset,
1060117546Sharti	idt77155_set_sdh,
1061117546Sharti	idt77155_set_unass,
1062117546Sharti	idt77155_set_noscramb,
1063117546Sharti	idt77155_update_carrier,
1064117546Sharti	idt77155_set_loopback,
1065117546Sharti	idt77155_intr,
1066117552Sharti	idt77155_update_stats,
1067117546Sharti};
1068117546Sharti
1069117546Shartistatic int
1070116258Shartiunknown_reset(struct utopia *utp __unused)
1071116258Sharti{
1072116258Sharti	return (EIO);
1073116258Sharti}
1074116258Sharti
1075116258Shartistatic int
1076116258Shartiunknown_update_carrier(struct utopia *utp)
1077116258Sharti{
1078116258Sharti	utp->carrier = UTP_CARR_UNKNOWN;
1079116258Sharti	return (0);
1080116258Sharti}
1081116258Sharti
1082116258Shartistatic int
1083116258Shartiunknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
1084116258Sharti{
1085116258Sharti	return (EINVAL);
1086116258Sharti}
1087116258Sharti
1088116258Shartistatic void
1089116258Shartiunknown_intr(struct utopia *utp __unused)
1090116258Sharti{
1091116258Sharti}
1092116258Sharti
1093117552Shartistatic void
1094117552Shartiunknown_update_stats(struct utopia *utp __unused)
1095117552Sharti{
1096117552Sharti}
1097117552Sharti
1098116258Shartistatic const struct utopia_chip chip_unknown = {
1099116258Sharti	UTP_TYPE_UNKNOWN,
1100116258Sharti	"unknown",
1101116258Sharti	0,
1102116258Sharti	unknown_reset,
1103116258Sharti	unknown_inval,
1104116258Sharti	unknown_inval,
1105116258Sharti	unknown_inval,
1106116258Sharti	unknown_update_carrier,
1107116258Sharti	unknown_set_loopback,
1108116258Sharti	unknown_intr,
1109117552Sharti	unknown_update_stats,
1110116258Sharti};
1111116258Sharti
1112116258Sharti/*
1113116258Sharti * Callbacks for the ifmedia infrastructure.
1114116258Sharti */
1115116258Shartistatic int
1116116258Shartiutopia_media_change(struct ifnet *ifp)
1117116258Sharti{
1118116258Sharti	struct ifatm *ifatm = (struct ifatm *)ifp->if_softc;
1119116258Sharti	struct utopia *utp = ifatm->phy;
1120116258Sharti	int error = 0;
1121116258Sharti
1122116258Sharti	UTP_LOCK(utp);
1123116258Sharti	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1124116258Sharti		if (utp->media->ifm_media & IFM_ATM_SDH) {
1125116258Sharti			if (!(utp->state & UTP_ST_SDH))
1126116258Sharti				error = utopia_set_sdh(utp, 1);
1127116258Sharti		} else {
1128116258Sharti			if (utp->state & UTP_ST_SDH)
1129116258Sharti				error = utopia_set_sdh(utp, 0);
1130116258Sharti		}
1131116258Sharti		if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
1132116258Sharti			if (!(utp->state & UTP_ST_UNASS))
1133116258Sharti				error = utopia_set_unass(utp, 1);
1134116258Sharti		} else {
1135116258Sharti			if (utp->state & UTP_ST_UNASS)
1136116258Sharti				error = utopia_set_unass(utp, 0);
1137116258Sharti		}
1138116258Sharti		if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
1139116258Sharti			if (!(utp->state & UTP_ST_NOSCRAMB))
1140116258Sharti				error = utopia_set_noscramb(utp, 1);
1141116258Sharti		} else {
1142116258Sharti			if (utp->state & UTP_ST_NOSCRAMB)
1143116258Sharti				error = utopia_set_noscramb(utp, 0);
1144116258Sharti		}
1145116258Sharti	} else
1146116258Sharti		error = EIO;
1147116258Sharti	UTP_UNLOCK(utp);
1148116258Sharti	return (error);
1149116258Sharti}
1150116258Sharti
1151116258Sharti/*
1152116258Sharti * Look at the carrier status.
1153116258Sharti */
1154116258Shartistatic void
1155116258Shartiutopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1156116258Sharti{
1157116258Sharti	struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy;
1158116258Sharti
1159116258Sharti	UTP_LOCK(utp);
1160116258Sharti	if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1161116258Sharti		ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
1162116258Sharti
1163116258Sharti		switch (utp->carrier) {
1164116258Sharti
1165116258Sharti		  case UTP_CARR_OK:
1166116258Sharti			ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1167116258Sharti			break;
1168116258Sharti
1169116258Sharti		  case UTP_CARR_LOST:
1170116258Sharti			ifmr->ifm_status = IFM_AVALID;
1171116258Sharti			break;
1172116258Sharti
1173116258Sharti		  default:
1174116258Sharti			ifmr->ifm_status = 0;
1175116258Sharti			break;
1176116258Sharti		}
1177116258Sharti		if (utp->state & UTP_ST_SDH) {
1178116258Sharti			ifmr->ifm_active |= IFM_ATM_SDH;
1179116258Sharti			ifmr->ifm_current |= IFM_ATM_SDH;
1180116258Sharti		}
1181116258Sharti		if (utp->state & UTP_ST_UNASS) {
1182116258Sharti			ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
1183116258Sharti			ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
1184116258Sharti		}
1185116258Sharti		if (utp->state & UTP_ST_NOSCRAMB) {
1186116258Sharti			ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
1187116258Sharti			ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
1188116258Sharti		}
1189116258Sharti	} else {
1190116258Sharti		ifmr->ifm_active = 0;
1191116258Sharti		ifmr->ifm_status = 0;
1192116258Sharti	}
1193116258Sharti	UTP_UNLOCK(utp);
1194116258Sharti}
1195116258Sharti
1196116258Sharti/*
1197116258Sharti * Initialize media from the mib
1198116258Sharti */
1199116258Shartivoid
1200116258Shartiutopia_init_media(struct utopia *utp)
1201116258Sharti{
1202116258Sharti
1203116258Sharti	ifmedia_removeall(utp->media);
1204116258Sharti	ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL);
1205116258Sharti	ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media);
1206116258Sharti}
1207116258Sharti
1208116258Sharti/*
1209116258Sharti * Reset all media
1210116258Sharti */
1211116258Shartivoid
1212116258Shartiutopia_reset_media(struct utopia *utp)
1213116258Sharti{
1214116258Sharti
1215116258Sharti	ifmedia_removeall(utp->media);
1216116258Sharti}
1217116258Sharti
1218116258Sharti/*
1219116258Sharti * This is called by the driver as soon as the SUNI registers are accessible.
1220116258Sharti * This may be either in the attach routine or the init routine of the driver.
1221116258Sharti */
1222116258Shartiint
1223116258Shartiutopia_start(struct utopia *utp)
1224116258Sharti{
1225116258Sharti	uint8_t reg;
1226116258Sharti	int err;
1227116258Sharti	u_int n = 1;
1228116258Sharti
1229116258Sharti	if ((err = READREGS(utp, SUNI_REGO_MRESET, &reg, &n)) != 0)
1230116258Sharti		return (err);
1231116258Sharti
1232116258Sharti	switch (reg & SUNI_REGM_MRESET_TYPE) {
1233116258Sharti
1234116258Sharti	  case SUNI_REGM_MRESET_TYPE_622:
1235116258Sharti		utp->chip = &chip_622;
1236116258Sharti		break;
1237116258Sharti
1238116258Sharti	  case SUNI_REGM_MRESET_TYPE_LITE:
1239117546Sharti		/* this may be either a SUNI LITE or a IDT77155 *
1240117546Sharti		 * Read register 0x70. The SUNI doesn't have it */
1241117546Sharti		n = 1;
1242117546Sharti		if ((err = READREGS(utp, IDTPHY_REGO_RBER, &reg, &n)) != 0)
1243117546Sharti			return (err);
1244117546Sharti		if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
1245117546Sharti		    (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
1246117546Sharti			utp->chip = &chip_idt77155;
1247117546Sharti		else
1248117546Sharti			utp->chip = &chip_lite;
1249116258Sharti		break;
1250116258Sharti
1251116258Sharti	  case SUNI_REGM_MRESET_TYPE_ULTRA:
1252116258Sharti		utp->chip = &chip_ultra;
1253116258Sharti		break;
1254116258Sharti
1255116258Sharti	  default:
1256116258Sharti		if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
1257116258Sharti			utp->chip = &chip_idt77105;
1258116258Sharti		else {
1259116258Sharti			if_printf(&utp->ifatm->ifnet,
1260116258Sharti			    "unknown ATM-PHY chip %#x\n", reg);
1261116258Sharti			utp->chip = &chip_unknown;
1262116258Sharti		}
1263116258Sharti		break;
1264116258Sharti	}
1265116258Sharti	utp->state |= UTP_ST_ACTIVE;
1266116258Sharti	return (0);
1267116258Sharti}
1268116258Sharti
1269116258Sharti/*
1270116258Sharti * Stop the chip
1271116258Sharti */
1272116258Shartivoid
1273116258Shartiutopia_stop(struct utopia *utp)
1274116258Sharti{
1275116258Sharti	utp->state &= ~UTP_ST_ACTIVE;
1276116258Sharti}
1277116258Sharti
1278116258Sharti/*
1279116258Sharti * Handle the sysctls
1280116258Sharti */
1281116258Shartistatic int
1282116258Shartiutopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
1283116258Sharti{
1284116258Sharti	struct utopia *utp = (struct utopia *)arg1;
1285116258Sharti	int error;
1286116258Sharti	u_int n;
1287116258Sharti	uint8_t *val;
1288116258Sharti	uint8_t new[3];
1289116258Sharti
1290116258Sharti	if ((n = utp->chip->nregs) == 0)
1291116258Sharti		return (EIO);
1292116258Sharti	val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
1293116258Sharti
1294116258Sharti	UTP_LOCK(utp);
1295116258Sharti	error = READREGS(utp, 0, val, &n);
1296116258Sharti	UTP_UNLOCK(utp);
1297116258Sharti
1298116258Sharti	if (error) {
1299116258Sharti		free(val, M_TEMP);
1300116258Sharti		return (error);
1301116258Sharti	}
1302116258Sharti
1303116258Sharti	error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
1304116258Sharti	free(val, M_TEMP);
1305116258Sharti	if (error != 0 || req->newptr == NULL)
1306116258Sharti		return (error);
1307116258Sharti
1308116258Sharti	error = SYSCTL_IN(req, new, sizeof(new));
1309116258Sharti	if (error)
1310116258Sharti		return (error);
1311116258Sharti
1312116258Sharti	UTP_LOCK(utp);
1313116258Sharti	error = WRITEREG(utp, new[0], new[1], new[2]);
1314116258Sharti	UTP_UNLOCK(utp);
1315116258Sharti
1316116258Sharti	return (error);
1317116258Sharti}
1318116258Sharti
1319117552Shartistatic int
1320117552Shartiutopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
1321117552Sharti{
1322117552Sharti	struct utopia *utp = (struct utopia *)arg1;
1323117552Sharti	void *val;
1324117552Sharti	int error;
1325117552Sharti
1326117552Sharti	val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
1327117552Sharti
1328117552Sharti	UTP_LOCK(utp);
1329117552Sharti	bcopy(&utp->stats, val, sizeof(utp->stats));
1330117552Sharti	if (req->newptr != NULL)
1331117552Sharti		bzero((char *)&utp->stats + sizeof(utp->stats.version),
1332117552Sharti		    sizeof(utp->stats) - sizeof(utp->stats.version));
1333117552Sharti	UTP_UNLOCK(utp);
1334117552Sharti
1335117552Sharti	error = SYSCTL_OUT(req, val, sizeof(utp->stats));
1336117552Sharti	free(val, M_TEMP);
1337117552Sharti
1338117552Sharti	if (error && req->newptr != NULL)
1339117552Sharti		bcopy(val, &utp->stats, sizeof(utp->stats));
1340117552Sharti
1341117552Sharti	/* ignore actual new value */
1342117552Sharti
1343117552Sharti	return (error);
1344117552Sharti}
1345117552Sharti
1346116258Sharti/*
1347116258Sharti * Handle the loopback sysctl
1348116258Sharti */
1349116258Shartistatic int
1350116258Shartiutopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
1351116258Sharti{
1352116258Sharti	struct utopia *utp = (struct utopia *)arg1;
1353116258Sharti	int error;
1354116258Sharti	u_int loopback;
1355116258Sharti
1356116258Sharti	error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
1357116258Sharti	if (error != 0 || req->newptr == NULL)
1358116258Sharti		return (error);
1359116258Sharti
1360116258Sharti	error = SYSCTL_IN(req, &loopback, sizeof(u_int));
1361116258Sharti	if (error)
1362116258Sharti		return (error);
1363116258Sharti
1364116258Sharti	UTP_LOCK(utp);
1365116258Sharti	error = utopia_set_loopback(utp, loopback);
1366116258Sharti	UTP_UNLOCK(utp);
1367116258Sharti
1368116258Sharti	return (error);
1369116258Sharti}
1370116258Sharti
1371116258Sharti/*
1372116258Sharti * Handle the type sysctl
1373116258Sharti */
1374116258Shartistatic int
1375116258Shartiutopia_sysctl_type(SYSCTL_HANDLER_ARGS)
1376116258Sharti{
1377116258Sharti	struct utopia *utp = (struct utopia *)arg1;
1378116258Sharti
1379116258Sharti	return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
1380116258Sharti}
1381116258Sharti
1382116258Sharti/*
1383116258Sharti * Handle the name sysctl
1384116258Sharti */
1385116258Shartistatic int
1386116258Shartiutopia_sysctl_name(SYSCTL_HANDLER_ARGS)
1387116258Sharti{
1388116258Sharti	struct utopia *utp = (struct utopia *)arg1;
1389116258Sharti
1390116258Sharti	return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
1391116258Sharti}
1392116258Sharti
1393116258Sharti/*
1394116258Sharti * Initialize the state. This is called from the drivers attach
1395116258Sharti * function. The mutex must be already initialized.
1396116258Sharti */
1397116258Shartiint
1398116258Shartiutopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
1399116258Sharti    struct mtx *lock, struct sysctl_ctx_list *ctx,
1400116258Sharti    struct sysctl_oid_list *children, const struct utopia_methods *m)
1401116258Sharti{
1402116258Sharti
1403116258Sharti	bzero(utp, sizeof(*utp));
1404116258Sharti	utp->ifatm = ifatm;
1405116258Sharti	utp->methods = m;
1406116258Sharti	utp->media = media;
1407116258Sharti	utp->lock = lock;
1408116258Sharti	utp->chip = &chip_unknown;
1409117552Sharti	utp->stats.version = 1;
1410116258Sharti
1411116258Sharti	ifmedia_init(media,
1412116258Sharti	    IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
1413116258Sharti	    utopia_media_change, utopia_media_status);
1414116258Sharti
1415116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
1416116258Sharti	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
1417116258Sharti	    "phy registers") == NULL)
1418116258Sharti		return (-1);
1419116258Sharti
1420116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
1421116258Sharti	    CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
1422116258Sharti	    "phy loopback mode") == NULL)
1423116258Sharti		return (-1);
1424116258Sharti
1425116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
1426116258Sharti	    CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
1427116258Sharti	    "phy type") == NULL)
1428116258Sharti		return (-1);
1429116258Sharti
1430116258Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
1431116258Sharti	    CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
1432116258Sharti	    "phy name") == NULL)
1433116258Sharti		return (-1);
1434116258Sharti
1435117552Sharti	if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
1436117552Sharti	    CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
1437117552Sharti	    "phy statistics") == NULL)
1438117552Sharti		return (-1);
1439117552Sharti
1440118202Sharti	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
1441118202Sharti	    CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
1442118202Sharti		return (-1);
1443118202Sharti
1444118202Sharti	if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
1445118202Sharti	    CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
1446118202Sharti		return (-1);
1447118202Sharti
1448116258Sharti	UTP_WLOCK_LIST();
1449116258Sharti	LIST_INSERT_HEAD(&utopia_list, utp, link);
1450116258Sharti	UTP_WUNLOCK_LIST();
1451116258Sharti
1452116258Sharti	utp->state |= UTP_ST_ATTACHED;
1453116258Sharti	return (0);
1454116258Sharti}
1455116258Sharti
1456116258Sharti/*
1457116258Sharti * Detach. We set a flag here, wakeup the daemon and let him do it.
1458116258Sharti * Here we need the lock for synchronisation with the daemon.
1459116258Sharti */
1460116258Shartivoid
1461116258Shartiutopia_detach(struct utopia *utp)
1462116258Sharti{
1463116258Sharti
1464116258Sharti	UTP_LOCK_ASSERT(utp);
1465116258Sharti	if (utp->state & UTP_ST_ATTACHED) {
1466116258Sharti		utp->state |= UTP_ST_DETACH;
1467116258Sharti		while (utp->state & UTP_ST_DETACH) {
1468116258Sharti			wakeup(&utopia_list);
1469116258Sharti			msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
1470116258Sharti		}
1471116258Sharti	}
1472116258Sharti}
1473116258Sharti
1474116258Sharti/*
1475116258Sharti * The carrier state kernel proc for those adapters that do not interrupt.
1476116258Sharti *
1477116258Sharti * We assume, that utopia_attach can safely add a new utopia while we are going
1478116258Sharti * through the list without disturbing us (we lock the list while getting
1479116258Sharti * the address of the first element, adding is always done at the head).
1480116258Sharti * Removing is entirely handled here.
1481116258Sharti */
1482116258Shartistatic void
1483116258Shartiutopia_daemon(void *arg __unused)
1484116258Sharti{
1485116258Sharti	struct utopia *utp, *next;
1486116258Sharti
1487116258Sharti	UTP_RLOCK_LIST();
1488116258Sharti	while (utopia_kproc != NULL) {
1489116258Sharti		utp = LIST_FIRST(&utopia_list);
1490116258Sharti		UTP_RUNLOCK_LIST();
1491116258Sharti
1492116258Sharti		while (utp != NULL) {
1493116258Sharti			mtx_lock(&Giant);	/* XXX depend on MPSAFE */
1494116258Sharti			UTP_LOCK(utp);
1495116258Sharti			next = LIST_NEXT(utp, link);
1496116258Sharti			if (utp->state & UTP_ST_DETACH) {
1497116258Sharti				LIST_REMOVE(utp, link);
1498116258Sharti				utp->state &= ~UTP_ST_DETACH;
1499116258Sharti				wakeup_one(utp);
1500117552Sharti			} else if (utp->state & UTP_ST_ACTIVE) {
1501117552Sharti				if (utp->flags & UTP_FL_POLL_CARRIER)
1502117552Sharti					utopia_update_carrier(utp);
1503117552Sharti				utopia_update_stats(utp);
1504116258Sharti			}
1505116258Sharti			UTP_UNLOCK(utp);
1506116258Sharti			mtx_unlock(&Giant);	/* XXX depend on MPSAFE */
1507116258Sharti			utp = next;
1508116258Sharti		}
1509116258Sharti
1510116258Sharti		UTP_RLOCK_LIST();
1511117552Sharti		msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
1512116258Sharti	}
1513116258Sharti	wakeup_one(&utopia_list);
1514116258Sharti	UTP_RUNLOCK_LIST();
1515116258Sharti	mtx_lock(&Giant);
1516116258Sharti	kthread_exit(0);
1517116258Sharti}
1518116258Sharti
1519116258Sharti/*
1520116258Sharti * Module initialisation
1521116258Sharti */
1522116258Shartistatic int
1523116258Shartiutopia_mod_init(module_t mod, int what, void *arg)
1524116258Sharti{
1525116258Sharti	int err;
1526116258Sharti	struct proc *kp;
1527116258Sharti
1528116258Sharti	switch (what) {
1529116258Sharti
1530116258Sharti	  case MOD_LOAD:
1531116258Sharti		mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
1532116258Sharti		err = kthread_create(utopia_daemon, NULL, &utopia_kproc,
1533116258Sharti		    RFHIGHPID, 0, "utopia");
1534116258Sharti		if (err != 0) {
1535116258Sharti			printf("cannot created utopia thread %d\n", err);
1536116258Sharti			return (err);
1537116258Sharti		}
1538116258Sharti		break;
1539116258Sharti
1540116258Sharti	  case MOD_UNLOAD:
1541116258Sharti		UTP_WLOCK_LIST();
1542116258Sharti		if ((kp = utopia_kproc) != NULL) {
1543116258Sharti			utopia_kproc = NULL;
1544116258Sharti			wakeup_one(&utopia_list);
1545116258Sharti			PROC_LOCK(kp);
1546116258Sharti			UTP_WUNLOCK_LIST();
1547116258Sharti			msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
1548116258Sharti			PROC_UNLOCK(kp);
1549116258Sharti		} else
1550116258Sharti			UTP_WUNLOCK_LIST();
1551116258Sharti		mtx_destroy(&utopia_list_mtx);
1552116258Sharti		break;
1553116258Sharti	}
1554116258Sharti	return (0);
1555116258Sharti}
1556116258Sharti
1557116258Shartistatic moduledata_t utopia_mod = {
1558116258Sharti        "utopia",
1559116258Sharti        utopia_mod_init,
1560116258Sharti        0
1561116258Sharti};
1562116258Sharti
1563116258ShartiDECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
1564116258ShartiMODULE_VERSION(utopia, 1);
1565