]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/utopia/utopia.c
This commit was generated by cvs2svn to compensate for changes in r128266,
[FreeBSD/FreeBSD.git] / sys / dev / utopia / utopia.c
1 /*
2  * Copyright (c) 2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
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/sysctl.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/socket.h>
45
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/if_media.h>
49 #include <net/if_atm.h>
50
51 #include <dev/utopia/suni.h>
52 #include <dev/utopia/idtphy.h>
53 #include <dev/utopia/utopia.h>
54
55 #define READREGS(UTOPIA, REG, VALP, NP)                         \
56     (UTOPIA)->methods->readregs((UTOPIA)->ifatm, REG, VALP, NP)
57 #define WRITEREG(UTOPIA, REG, MASK, VAL)                        \
58     (UTOPIA)->methods->writereg((UTOPIA)->ifatm, REG, MASK, VAL)
59
60 /*
61  * Global list of all registered interfaces
62  */
63 static struct mtx utopia_list_mtx;
64 static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
65
66 #define UTP_RLOCK_LIST()        mtx_lock(&utopia_list_mtx)
67 #define UTP_RUNLOCK_LIST()      mtx_unlock(&utopia_list_mtx)
68 #define UTP_WLOCK_LIST()        mtx_lock(&utopia_list_mtx)
69 #define UTP_WUNLOCK_LIST()      mtx_unlock(&utopia_list_mtx)
70
71 #define UTP_LOCK(UTP)           mtx_lock((UTP)->lock)
72 #define UTP_UNLOCK(UTP)         mtx_unlock((UTP)->lock)
73 #define UTP_LOCK_ASSERT(UTP)    mtx_assert((UTP)->lock, MA_OWNED)
74
75 static struct proc *utopia_kproc;
76
77 static void utopia_dump(struct utopia *) __unused;
78
79 /*
80  * Statistics update inlines
81  */
82 static uint32_t
83 utp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
84 {
85         int err;
86         u_int n;
87         uint8_t regs[4];
88         uint32_t val;
89
90         n = nreg;
91         if ((err = READREGS(utp, reg, regs, &n)) != 0) {
92 #ifdef DIAGNOSTIC
93                 printf("%s: register read error %s(%u,%u): %d\n", __func__,
94                     utp->chip->name, reg, nreg, err);
95 #endif
96                 return (0);
97         }
98         if (n < nreg) {
99 #ifdef DIAGNOSTIC
100                 printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
101                     utp->chip->name, reg, nreg, err);
102 #endif
103                 return (0);
104         }
105         val = 0;
106         for (n = nreg; n > 0; n--) {
107                 val <<= 8;
108                 val |= regs[n - 1];
109         }
110         return (val & mask);
111 }
112
113 #define UPDATE8(UTP, REG)       utp_update(UTP, REG, 1, 0xff)
114 #define UPDATE12(UTP, REG)      utp_update(UTP, REG, 2, 0xfff)
115 #define UPDATE16(UTP, REG)      utp_update(UTP, REG, 2, 0xffff)
116 #define UPDATE19(UTP, REG)      utp_update(UTP, REG, 3, 0x7ffff)
117 #define UPDATE20(UTP, REG)      utp_update(UTP, REG, 3, 0xfffff)
118 #define UPDATE21(UTP, REG)      utp_update(UTP, REG, 3, 0x1fffff)
119
120 /*
121  * Debugging - dump all registers.
122  */
123 static void
124 utopia_dump(struct utopia *utp)
125 {
126         uint8_t regs[256];
127         u_int n = 256, i;
128         int err;
129
130         if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
131                 printf("SUNI read error %d\n", err);
132                 return;
133         }
134         for (i = 0; i < n; i++) {
135                 if (i % 16 == 0)
136                         printf("%02x:", i);
137                 if (i % 16 == 8)
138                         printf(" ");
139                 printf(" %02x", regs[i]);
140                 if (i % 16 == 15)
141                         printf("\n");
142         }
143         if (i % 16 != 0)
144                 printf("\n");
145 }
146
147 /*
148  * Update the carrier status
149  */
150 static void
151 utopia_check_carrier(struct utopia *utp, u_int carr_ok)
152 {
153         int old;
154
155         old = utp->carrier;
156         if (carr_ok) {
157                 /* carrier */
158                 utp->carrier = UTP_CARR_OK;
159                 if (old != UTP_CARR_OK) {
160                         if_printf(&utp->ifatm->ifnet, "carrier detected\n");
161                         ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1);
162                 }
163         } else {
164                 /* no carrier */
165                 utp->carrier = UTP_CARR_LOST;
166                 if (old == UTP_CARR_OK) {
167                         if_printf(&utp->ifatm->ifnet, "carrier lost\n");
168                         ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0);
169                 }
170         }
171 }
172
173 static int
174 utopia_update_carrier_default(struct utopia *utp)
175 {
176         int err;
177         uint8_t reg;
178         u_int n = 1;
179
180         if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, &reg, &n)) != 0) {
181                 utp->carrier = UTP_CARR_UNKNOWN;
182                 return (err);
183         }
184         utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
185         return (0);
186 }
187
188 /*
189  * enable/disable scrambling
190  */
191 static int
192 utopia_set_noscramb_default(struct utopia *utp, int noscramb)
193 {
194         int err;
195
196         if (noscramb) {
197                 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
198                     SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
199                 if (err)
200                         return (err);
201                 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
202                     SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
203                 if (err)
204                         return (err);
205                 utp->state |= UTP_ST_NOSCRAMB;
206         } else {
207                 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
208                     SUNI_REGM_TACPCTRL_DSCR, 0);
209                 if (err)
210                         return (err);
211                 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
212                     SUNI_REGM_RACPCTRL_DDSCR, 0);
213                 if (err)
214                         return (err);
215                 utp->state &= ~UTP_ST_NOSCRAMB;
216         }
217         return (0);
218 }
219
220 /*
221  * set SONET/SDH mode
222  */
223 static int
224 utopia_set_sdh_default(struct utopia *utp, int sdh)
225 {
226         int err;
227
228         if (sdh)
229                 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
230                     SUNI_REGM_TPOPAPTR_S,
231                     SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
232         else
233                 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
234                     SUNI_REGM_TPOPAPTR_S,
235                     SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
236         if (err != 0)
237                 return (err);
238
239         utp->state &= ~UTP_ST_SDH;
240         if (sdh)
241                 utp->state |= UTP_ST_SDH;
242
243         return (0);
244 }
245
246 /*
247  * set idle/unassigned cells
248  */
249 static int
250 utopia_set_unass_default(struct utopia *utp, int unass)
251 {
252         int err;
253
254         if (unass)
255                 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
256                     0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
257         else
258                 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
259                     0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
260         if (err != 0)
261                 return (err);
262
263         utp->state &= ~UTP_ST_UNASS;
264         if (unass)
265                 utp->state |= UTP_ST_UNASS;
266
267         return (0);
268 }
269
270 /*
271  * Set loopback mode for the Lite
272  */
273 static int
274 utopia_set_loopback_lite(struct utopia *utp, u_int mode)
275 {
276         int err;
277         uint32_t val;
278         u_int nmode;
279
280         val = 0;
281         nmode = mode;
282         if (mode & UTP_LOOP_TIME) {
283                 nmode &= ~UTP_LOOP_TIME;
284                 val |= SUNI_REGM_MCTRL_LOOPT;
285         }
286         if (mode & UTP_LOOP_DIAG) {
287                 nmode &= ~UTP_LOOP_DIAG;
288                 val |= SUNI_REGM_MCTRL_DLE;
289         }
290         if (mode & UTP_LOOP_LINE) {
291                 nmode &= ~UTP_LOOP_LINE;
292                 if (val & SUNI_REGM_MCTRL_DLE)
293                         return (EINVAL);
294                 val |= SUNI_REGM_MCTRL_LLE;
295         }
296         if (nmode != 0)
297                 return (EINVAL);
298
299         err = WRITEREG(utp, SUNI_REGO_MCTRL,
300             SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
301             val);
302         if (err)
303                 return (err);
304         utp->loopback = mode;
305
306         return (0);
307 }
308
309 /*
310  * Set loopback mode for the Ultra
311  */
312 static int
313 utopia_set_loopback_ultra(struct utopia *utp, u_int mode)
314 {
315         int err;
316         uint32_t val;
317         u_int nmode;
318
319         val = 0;
320         nmode = mode;
321         if (mode & UTP_LOOP_TIME) {
322                 nmode &= ~UTP_LOOP_TIME;
323                 val |= SUNI_REGM_MCTRL_LOOPT;
324         }
325         if (mode & UTP_LOOP_DIAG) {
326                 nmode &= ~UTP_LOOP_DIAG;
327                 if (val & SUNI_REGM_MCTRL_LOOPT)
328                         return (EINVAL);
329                 val |= SUNI_REGM_MCTRL_SDLE;
330         }
331         if (mode & UTP_LOOP_LINE) {
332                 nmode &= ~UTP_LOOP_LINE;
333                 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
334                         return (EINVAL);
335                 val |= SUNI_REGM_MCTRL_LLE;
336         }
337         if (mode & UTP_LOOP_PARAL) {
338                 nmode &= ~UTP_LOOP_PARAL;
339                 val |= SUNI_REGM_MCTRL_PDLE;
340         }
341         if (mode & UTP_LOOP_TWIST) {
342                 nmode &= ~UTP_LOOP_TWIST;
343                 val |= SUNI_REGM_MCTRL_TPLE;
344         }
345         if (nmode != 0)
346                 return (EINVAL);
347
348         err = WRITEREG(utp, SUNI_REGO_MCTRL,
349             SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT |
350             SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val);
351         if (err)
352                 return (err);
353         utp->loopback = mode;
354
355         return (0);
356 }
357
358 /*
359  * Set loopback mode for the Ultra
360  */
361 static int
362 utopia_set_loopback_622(struct utopia *utp, u_int mode)
363 {
364         int err;
365         uint32_t val;
366         uint8_t config;
367         int smode;
368         u_int nmode;
369         u_int n = 1;
370
371         val = 0;
372         nmode = mode;
373         if (mode & UTP_LOOP_PATH) {
374                 nmode &= ~UTP_LOOP_PATH;
375                 val |= SUNI_REGM_MCTRLM_DPLE;
376         }
377
378         err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
379         if (err != 0)
380                 return (err);
381         smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) ==
382             SUNI_REGM_MCONFIG_TMODE_STS1_BIT &&
383             (config & SUNI_REGM_MCONFIG_RMODE_622) ==
384             SUNI_REGM_MCONFIG_RMODE_STS1_BIT);
385
386         if (mode & UTP_LOOP_TIME) {
387                 if (!smode)
388                         return (EINVAL);
389                 nmode &= ~UTP_LOOP_TIME;
390                 val |= SUNI_REGM_MCTRLM_LOOPT;
391         }
392         if (mode & UTP_LOOP_DIAG) {
393                 nmode &= ~UTP_LOOP_DIAG;
394                 if (val & SUNI_REGM_MCTRLM_LOOPT)
395                         return (EINVAL);
396                 val |= SUNI_REGM_MCTRLM_DLE;
397         }
398         if (mode & UTP_LOOP_LINE) {
399                 nmode &= ~UTP_LOOP_LINE;
400                 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
401                         return (EINVAL);
402                 val |= SUNI_REGM_MCTRLM_LLE;
403         }
404         if (nmode != 0)
405                 return (EINVAL);
406
407         err = WRITEREG(utp, SUNI_REGO_MCTRLM,
408             SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE |
409             SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val);
410         if (err)
411                 return (err);
412         utp->loopback = mode;
413
414         return (0);
415 }
416
417 /*
418  * Set the SUNI chip to reflect the current state in utopia.
419  * Assume, that the chip has been reset.
420  */
421 static int
422 utopia_set_chip(struct utopia *utp)
423 {
424         int err = 0;
425
426         /* set sonet/sdh */
427         err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
428
429         /* unassigned or idle cells */
430         err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS);
431         err |= WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a);
432
433         /* loopback */
434         err |= utopia_set_loopback(utp, utp->loopback);
435
436         /* update carrier state */
437         err |= utopia_update_carrier(utp);
438
439         /* enable interrupts on LOS */
440         err |= WRITEREG(utp, SUNI_REGO_RSOPCIE,
441             SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
442
443         return (err ? EIO : 0);
444 }
445
446 /*
447  * Reset the SUNI chip to reflect the current state of utopia.
448  */
449 static int
450 utopia_reset_default(struct utopia *utp)
451 {
452         int err = 0;
453
454         if (!(utp->flags & UTP_FL_NORESET)) {
455                 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
456                     SUNI_REGM_MRESET_RESET);
457                 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
458                     0);
459         }
460
461         /* disable test mode */
462         err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
463
464         err |= utopia_set_chip(utp);
465
466         return (err ? EIO : 0);
467 }
468
469 /*
470  * Reset the SUNI chip to reflect the current state of utopia.
471  */
472 static int
473 utopia_reset_622(struct utopia *utp)
474 {
475         int err = 0;
476
477         if (!(utp->flags & UTP_FL_NORESET)) {
478                 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
479                     SUNI_REGM_MRESET_RESET);
480                 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET,
481                     0);
482         }
483
484         /* disable test mode */
485         err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
486             SUNI_REGM_MTEST_DS27_53_622);
487
488         err |= utopia_set_chip(utp);
489
490         return (err ? EIO : 0);
491 }
492
493 /*
494  * Handle interrupt on lite chip
495  */
496 static void
497 utopia_intr_default(struct utopia *utp)
498 {
499         uint8_t regs[SUNI_REGO_MTEST];
500         u_int n = SUNI_REGO_MTEST;
501         int err;
502
503         /* Read all registers. This acks the interrupts */
504         if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
505                 printf("SUNI read error %d\n", err);
506                 return;
507         }
508         if (n <= SUNI_REGO_RSOPSIS) {
509                 printf("%s: could not read RSOPSIS", __func__);
510                 return;
511         }
512         /* check for LOSI (loss of signal) */
513         if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) &&
514             (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI))
515                 utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS]
516                     & SUNI_REGM_RSOPSIS_LOSV));
517 }
518
519 /*
520  * Update statistics from a SUNI/LITE or SUNI/ULTRA
521  */
522 static void
523 suni_lite_update_stats(struct utopia *utp)
524 {
525         int err;
526
527         /* write to the master if we can */
528         if (!(utp->flags & UTP_FL_NORESET)) {
529                 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
530         } else {
531                 err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
532                 err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
533                 err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
534                 err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
535                 err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
536
537         }
538         if (err) {
539 #ifdef DIAGNOSTIC
540                 printf("%s: register write error %s: %d\n", __func__,
541                     utp->chip->name, err);
542 #endif
543                 return;
544         }
545
546         DELAY(8);
547
548         utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8);
549         utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24);
550         utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE);
551         utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8);
552         utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE);
553         utp->stats.rx_corr += UPDATE8(utp, SUNI_REGO_RACPCHCS);
554         utp->stats.rx_uncorr += UPDATE8(utp, SUNI_REGO_RACPUHCS);
555         utp->stats.rx_cells += UPDATE19(utp, SUNI_REGO_RACPCNT);
556         utp->stats.tx_cells += UPDATE19(utp, SUNI_REGO_TACPCNT);
557 }
558
559 /*
560  * Update statistics from a SUNI/622
561  */
562 static void
563 suni_622_update_stats(struct utopia *utp)
564 {
565         int err;
566
567         /* write to the master if we can */
568         if (!(utp->flags & UTP_FL_NORESET)) {
569                 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
570         } else {
571                 err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
572                 err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
573                 err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
574                 err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
575                 err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
576         }
577         if (err) {
578 #ifdef DIAGNOSTIC
579                 printf("%s: register write error %s: %d\n", __func__,
580                     utp->chip->name, err);
581 #endif
582                 return;
583         }
584
585         DELAY(8);
586
587         utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8);
588         utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24);
589         utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE);
590         utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8);
591         utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE);
592         utp->stats.rx_corr += UPDATE12(utp, SUNI_REGO_RACPCHCS_622);
593         utp->stats.rx_uncorr += UPDATE12(utp, SUNI_REGO_RACPUHCS_622);
594         utp->stats.rx_cells += UPDATE21(utp, SUNI_REGO_RACPCNT_622);
595         utp->stats.tx_cells += UPDATE21(utp, SUNI_REGO_TACPCNT);
596 }
597
598 static const struct utopia_chip chip_622 = {
599         UTP_TYPE_SUNI_622,
600         "Suni/622 (PMC-5355)",
601         256,
602         utopia_reset_622,
603         utopia_set_sdh_default,
604         utopia_set_unass_default,
605         utopia_set_noscramb_default,
606         utopia_update_carrier_default,
607         utopia_set_loopback_622,
608         utopia_intr_default,
609         suni_622_update_stats,
610 };
611 static const struct utopia_chip chip_lite = {
612         UTP_TYPE_SUNI_LITE,
613         "Suni/Lite (PMC-5346)",
614         256,
615         utopia_reset_default,
616         utopia_set_sdh_default,
617         utopia_set_unass_default,
618         utopia_set_noscramb_default,
619         utopia_update_carrier_default,
620         utopia_set_loopback_lite,
621         utopia_intr_default,
622         suni_lite_update_stats,
623 };
624 static const struct utopia_chip chip_ultra = {
625         UTP_TYPE_SUNI_ULTRA,
626         "Suni/Ultra (PMC-5350)",
627         256,
628         utopia_reset_default,
629         utopia_set_sdh_default,
630         utopia_set_unass_default,
631         utopia_set_noscramb_default,
632         utopia_update_carrier_default,
633         utopia_set_loopback_ultra,
634         utopia_intr_default,
635         suni_lite_update_stats,
636 };
637
638 /*
639  * Reset IDT77105. There is really no way to reset this thing by acessing
640  * the registers. Load the registers with default values.
641  */
642 static int
643 idt77105_reset(struct utopia *utp)
644 {
645         int err = 0;
646         u_int n;
647         uint8_t val[2];
648
649         err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
650             IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
651         n = 1;
652         err |= READREGS(utp, IDTPHY_REGO_ISTAT, val, &n);
653         err |= WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0);
654         err |= WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0);
655
656         err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
657         n = 2;
658         err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
659
660         err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
661         n = 2;
662         err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
663
664         err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
665         n = 2;
666         err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
667
668         err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
669         n = 2;
670         err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
671
672         err |= WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC,
673             IDTPHY_REGM_MCR_DREC);
674         err |= WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH,
675             IDTPHY_REGM_DIAG_RFLUSH);
676
677         /* loopback */
678         err |= utopia_set_loopback(utp, utp->loopback);
679
680         /* update carrier state */
681         err |= utopia_update_carrier(utp);
682
683         return (err ? EIO : 0);
684 }
685
686 static int
687 unknown_inval(struct utopia *utp, int what __unused)
688 {
689         return (EINVAL);
690 }
691
692 static int
693 idt77105_update_carrier(struct utopia *utp)
694 {
695         int err;
696         uint8_t reg;
697         u_int n = 1;
698
699         if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
700                 utp->carrier = UTP_CARR_UNKNOWN;
701                 return (err);
702         }
703         utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
704         return (0);
705 }
706
707 static int
708 idt77105_set_loopback(struct utopia *utp, u_int mode)
709 {
710         int err;
711
712         switch (mode) {
713           case UTP_LOOP_NONE:
714                 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
715                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
716                 break;
717
718           case UTP_LOOP_DIAG:
719                 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
720                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
721                 break;
722
723           case UTP_LOOP_LINE:
724                 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
725                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
726                 break;
727
728           default:
729                 return (EINVAL);
730         }
731         if (err)
732                 return (err);
733         utp->loopback = mode;
734         return (0);
735 }
736
737 /*
738  * Handle interrupt on IDT77105 chip
739  */
740 static void
741 idt77105_intr(struct utopia *utp)
742 {
743         uint8_t reg;
744         u_int n = 1;
745         int err;
746
747         /* Interrupt status and ack the interrupt */
748         if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
749                 printf("IDT77105 read error %d\n", err);
750                 return;
751         }
752         /* check for signal condition */
753         utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
754 }
755
756 static void
757 idt77105_update_stats(struct utopia *utp)
758 {
759         int err = 0;
760         uint8_t regs[2];
761         u_int n;
762
763 #ifdef DIAGNOSTIC
764 #define UDIAG(F,A,B)    printf(F, A, B)
765 #else
766 #define UDIAG(F,A,B)    do { } while (0)
767 #endif
768
769 #define UPD(FIELD, CODE, N, MASK)                                       \
770         err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE);              \
771         if (err != 0) {                                                 \
772                 UDIAG("%s: cannot write CNTS: %d\n", __func__, err);    \
773                 return;                                                 \
774         }                                                               \
775         n = N;                                                          \
776         err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n);                 \
777         if (err != 0) {                                                 \
778                 UDIAG("%s: cannot read CNT: %d\n", __func__, err);      \
779                 return;                                                 \
780         }                                                               \
781         if (n != N) {                                                   \
782                 UDIAG("%s: got only %u registers\n", __func__, n);      \
783                 return;                                                 \
784         }                                                               \
785         if (N == 1)                                                     \
786                 utp->stats.FIELD += (regs[0] & MASK);                   \
787         else                                                            \
788                 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
789
790         UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff);
791         UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff);
792         UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff);
793         UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f);
794
795 #undef  UDIAG
796 #undef  UPD
797 }
798
799 static const struct utopia_chip chip_idt77105 = {
800         UTP_TYPE_IDT77105,
801         "IDT77105",
802         7,
803         idt77105_reset,
804         unknown_inval,
805         unknown_inval,
806         unknown_inval,
807         idt77105_update_carrier,
808         idt77105_set_loopback,
809         idt77105_intr,
810         idt77105_update_stats,
811 };
812
813 /*
814  * Update the carrier status
815  */
816 static int
817 idt77155_update_carrier(struct utopia *utp)
818 {
819         int err;
820         uint8_t reg;
821         u_int n = 1;
822
823         if ((err = READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
824                 utp->carrier = UTP_CARR_UNKNOWN;
825                 return (err);
826         }
827         utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
828         return (0);
829 }
830
831 /*
832  * Handle interrupt on IDT77155 chip
833  */
834 static void
835 idt77155_intr(struct utopia *utp)
836 {
837         uint8_t reg;
838         u_int n = 1;
839         int err;
840
841         if ((err = READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
842                 printf("IDT77105 read error %d\n", err);
843                 return;
844         }
845         utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
846 }
847
848 /*
849  * set SONET/SDH mode
850  */
851 static int
852 idt77155_set_sdh(struct utopia *utp, int sdh)
853 {
854         int err;
855
856         if (sdh)
857                 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
858                     IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
859         else
860                 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
861                     IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
862         if (err != 0)
863                 return (err);
864
865         utp->state &= ~UTP_ST_SDH;
866         if (sdh)
867                 utp->state |= UTP_ST_SDH;
868
869         return (0);
870 }
871
872 /*
873  * set idle/unassigned cells
874  */
875 static int
876 idt77155_set_unass(struct utopia *utp, int unass)
877 {
878         int err;
879
880         if (unass)
881                 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
882         else
883                 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
884         if (err != 0)
885                 return (err);
886
887         utp->state &= ~UTP_ST_UNASS;
888         if (unass)
889                 utp->state |= UTP_ST_UNASS;
890
891         return (0);
892 }
893
894 /*
895  * enable/disable scrambling
896  */
897 static int
898 idt77155_set_noscramb(struct utopia *utp, int noscramb)
899 {
900         int err;
901
902         if (noscramb) {
903                 err = WRITEREG(utp, IDTPHY_REGO_TCC,
904                     IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
905                 if (err)
906                         return (err);
907                 err = WRITEREG(utp, IDTPHY_REGO_RCC,
908                     IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
909                 if (err)
910                         return (err);
911                 utp->state |= UTP_ST_NOSCRAMB;
912         } else {
913                 err = WRITEREG(utp, IDTPHY_REGO_TCC,
914                     IDTPHY_REGM_TCC_DSCR, 0);
915                 if (err)
916                         return (err);
917                 err = WRITEREG(utp, IDTPHY_REGO_RCC,
918                     IDTPHY_REGM_RCC_DSCR, 0);
919                 if (err)
920                         return (err);
921                 utp->state &= ~UTP_ST_NOSCRAMB;
922         }
923         return (0);
924 }
925
926 /*
927  * Set loopback mode for the 77155
928  */
929 static int
930 idt77155_set_loopback(struct utopia *utp, u_int mode)
931 {
932         int err;
933         uint32_t val;
934         u_int nmode;
935
936         val = 0;
937         nmode = mode;
938         if (mode & UTP_LOOP_TIME) {
939                 nmode &= ~UTP_LOOP_TIME;
940                 val |= IDTPHY_REGM_MCTL_TLOOP;
941         }
942         if (mode & UTP_LOOP_DIAG) {
943                 nmode &= ~UTP_LOOP_DIAG;
944                 val |= IDTPHY_REGM_MCTL_DLOOP;
945         }
946         if (mode & UTP_LOOP_LINE) {
947                 nmode &= ~UTP_LOOP_LINE;
948                 val |= IDTPHY_REGM_MCTL_LLOOP;
949         }
950         if (nmode != 0)
951                 return (EINVAL);
952
953         err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
954             IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
955         if (err)
956                 return (err);
957         utp->loopback = mode;
958
959         return (0);
960 }
961
962 /*
963  * Set the chip to reflect the current state in utopia.
964  * Assume, that the chip has been reset.
965  */
966 static int
967 idt77155_set_chip(struct utopia *utp)
968 {
969         int err = 0;
970
971         /* set sonet/sdh */
972         err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
973
974         /* unassigned or idle cells */
975         err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
976
977         /* loopback */
978         err |= idt77155_set_loopback(utp, utp->loopback);
979
980         /* update carrier state */
981         err |= idt77155_update_carrier(utp);
982
983         /* enable interrupts on LOS */
984         err |= WRITEREG(utp, IDTPHY_REGO_INT,
985             IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI);
986         err |= WRITEREG(utp, IDTPHY_REGO_RSOC,
987             IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI);
988
989         return (err ? EIO : 0);
990 }
991
992 /*
993  * Reset the chip to reflect the current state of utopia.
994  */
995 static int
996 idt77155_reset(struct utopia *utp)
997 {
998         int err = 0;
999
1000         if (!(utp->flags & UTP_FL_NORESET)) {
1001                 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET,
1002                     IDTPHY_REGM_MRID_RESET);
1003                 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET,
1004                     0);
1005         }
1006
1007         err |= idt77155_set_chip(utp);
1008
1009         return (err ? EIO : 0);
1010 }
1011
1012 /*
1013  * Update statistics from a IDT77155
1014  * This appears to be the same as for the Suni/Lite and Ultra. IDT however
1015  * makes no assessment about the transfer time. Assume 7us.
1016  */
1017 static void
1018 idt77155_update_stats(struct utopia *utp)
1019 {
1020         int err;
1021
1022         /* write to the master if we can */
1023         if (!(utp->flags & UTP_FL_NORESET)) {
1024                 err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
1025         } else {
1026                 err = WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0);
1027                 err |= WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0);
1028                 err |= WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0);
1029                 err |= WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0);
1030                 err |= WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0);
1031
1032         }
1033         if (err) {
1034 #ifdef DIAGNOSTIC
1035                 printf("%s: register write error %s: %d\n", __func__,
1036                     utp->chip->name, err);
1037 #endif
1038                 return;
1039         }
1040
1041         DELAY(8);
1042
1043         utp->stats.rx_sbip += UPDATE16(utp, IDTPHY_REGO_BIPC);
1044         utp->stats.rx_lbip += UPDATE20(utp, IDTPHY_REGO_B2EC);
1045         utp->stats.rx_lfebe += UPDATE20(utp, IDTPHY_REGO_FEBEC);
1046         utp->stats.rx_pbip += UPDATE16(utp, IDTPHY_REGO_B3EC);
1047         utp->stats.rx_pfebe += UPDATE16(utp, IDTPHY_REGO_PFEBEC);
1048         utp->stats.rx_corr += UPDATE8(utp, IDTPHY_REGO_CEC);
1049         utp->stats.rx_uncorr += UPDATE8(utp, IDTPHY_REGO_UEC);
1050         utp->stats.rx_cells += UPDATE19(utp, IDTPHY_REGO_RCCNT);
1051         utp->stats.tx_cells += UPDATE19(utp, IDTPHY_REGO_TXCNT);
1052 }
1053
1054
1055 static const struct utopia_chip chip_idt77155 = {
1056         UTP_TYPE_IDT77155,
1057         "IDT77155",
1058         0x80,
1059         idt77155_reset,
1060         idt77155_set_sdh,
1061         idt77155_set_unass,
1062         idt77155_set_noscramb,
1063         idt77155_update_carrier,
1064         idt77155_set_loopback,
1065         idt77155_intr,
1066         idt77155_update_stats,
1067 };
1068
1069 static int
1070 unknown_reset(struct utopia *utp __unused)
1071 {
1072         return (EIO);
1073 }
1074
1075 static int
1076 unknown_update_carrier(struct utopia *utp)
1077 {
1078         utp->carrier = UTP_CARR_UNKNOWN;
1079         return (0);
1080 }
1081
1082 static int
1083 unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
1084 {
1085         return (EINVAL);
1086 }
1087
1088 static void
1089 unknown_intr(struct utopia *utp __unused)
1090 {
1091 }
1092
1093 static void
1094 unknown_update_stats(struct utopia *utp __unused)
1095 {
1096 }
1097
1098 static const struct utopia_chip chip_unknown = {
1099         UTP_TYPE_UNKNOWN,
1100         "unknown",
1101         0,
1102         unknown_reset,
1103         unknown_inval,
1104         unknown_inval,
1105         unknown_inval,
1106         unknown_update_carrier,
1107         unknown_set_loopback,
1108         unknown_intr,
1109         unknown_update_stats,
1110 };
1111
1112 /*
1113  * Callbacks for the ifmedia infrastructure.
1114  */
1115 static int
1116 utopia_media_change(struct ifnet *ifp)
1117 {
1118         struct ifatm *ifatm = (struct ifatm *)ifp->if_softc;
1119         struct utopia *utp = ifatm->phy;
1120         int error = 0;
1121
1122         UTP_LOCK(utp);
1123         if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1124                 if (utp->media->ifm_media & IFM_ATM_SDH) {
1125                         if (!(utp->state & UTP_ST_SDH))
1126                                 error = utopia_set_sdh(utp, 1);
1127                 } else {
1128                         if (utp->state & UTP_ST_SDH)
1129                                 error = utopia_set_sdh(utp, 0);
1130                 }
1131                 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
1132                         if (!(utp->state & UTP_ST_UNASS))
1133                                 error = utopia_set_unass(utp, 1);
1134                 } else {
1135                         if (utp->state & UTP_ST_UNASS)
1136                                 error = utopia_set_unass(utp, 0);
1137                 }
1138                 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
1139                         if (!(utp->state & UTP_ST_NOSCRAMB))
1140                                 error = utopia_set_noscramb(utp, 1);
1141                 } else {
1142                         if (utp->state & UTP_ST_NOSCRAMB)
1143                                 error = utopia_set_noscramb(utp, 0);
1144                 }
1145         } else
1146                 error = EIO;
1147         UTP_UNLOCK(utp);
1148         return (error);
1149 }
1150
1151 /*
1152  * Look at the carrier status.
1153  */
1154 static void
1155 utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1156 {
1157         struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy;
1158
1159         UTP_LOCK(utp);
1160         if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1161                 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
1162
1163                 switch (utp->carrier) {
1164
1165                   case UTP_CARR_OK:
1166                         ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1167                         break;
1168
1169                   case UTP_CARR_LOST:
1170                         ifmr->ifm_status = IFM_AVALID;
1171                         break;
1172
1173                   default:
1174                         ifmr->ifm_status = 0;
1175                         break;
1176                 }
1177                 if (utp->state & UTP_ST_SDH) {
1178                         ifmr->ifm_active |= IFM_ATM_SDH;
1179                         ifmr->ifm_current |= IFM_ATM_SDH;
1180                 }
1181                 if (utp->state & UTP_ST_UNASS) {
1182                         ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
1183                         ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
1184                 }
1185                 if (utp->state & UTP_ST_NOSCRAMB) {
1186                         ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
1187                         ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
1188                 }
1189         } else {
1190                 ifmr->ifm_active = 0;
1191                 ifmr->ifm_status = 0;
1192         }
1193         UTP_UNLOCK(utp);
1194 }
1195
1196 /*
1197  * Initialize media from the mib
1198  */
1199 void
1200 utopia_init_media(struct utopia *utp)
1201 {
1202
1203         ifmedia_removeall(utp->media);
1204         ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL);
1205         ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media);
1206 }
1207
1208 /*
1209  * Reset all media
1210  */
1211 void
1212 utopia_reset_media(struct utopia *utp)
1213 {
1214
1215         ifmedia_removeall(utp->media);
1216 }
1217
1218 /*
1219  * This is called by the driver as soon as the SUNI registers are accessible.
1220  * This may be either in the attach routine or the init routine of the driver.
1221  */
1222 int
1223 utopia_start(struct utopia *utp)
1224 {
1225         uint8_t reg;
1226         int err;
1227         u_int n = 1;
1228
1229         if ((err = READREGS(utp, SUNI_REGO_MRESET, &reg, &n)) != 0)
1230                 return (err);
1231
1232         switch (reg & SUNI_REGM_MRESET_TYPE) {
1233
1234           case SUNI_REGM_MRESET_TYPE_622:
1235                 utp->chip = &chip_622;
1236                 break;
1237
1238           case SUNI_REGM_MRESET_TYPE_LITE:
1239                 /* this may be either a SUNI LITE or a IDT77155 *
1240                  * Read register 0x70. The SUNI doesn't have it */
1241                 n = 1;
1242                 if ((err = READREGS(utp, IDTPHY_REGO_RBER, &reg, &n)) != 0)
1243                         return (err);
1244                 if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
1245                     (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
1246                         utp->chip = &chip_idt77155;
1247                 else
1248                         utp->chip = &chip_lite;
1249                 break;
1250
1251           case SUNI_REGM_MRESET_TYPE_ULTRA:
1252                 utp->chip = &chip_ultra;
1253                 break;
1254
1255           default:
1256                 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
1257                         utp->chip = &chip_idt77105;
1258                 else {
1259                         if_printf(&utp->ifatm->ifnet,
1260                             "unknown ATM-PHY chip %#x\n", reg);
1261                         utp->chip = &chip_unknown;
1262                 }
1263                 break;
1264         }
1265         utp->state |= UTP_ST_ACTIVE;
1266         return (0);
1267 }
1268
1269 /*
1270  * Stop the chip
1271  */
1272 void
1273 utopia_stop(struct utopia *utp)
1274 {
1275         utp->state &= ~UTP_ST_ACTIVE;
1276 }
1277
1278 /*
1279  * Handle the sysctls
1280  */
1281 static int
1282 utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
1283 {
1284         struct utopia *utp = (struct utopia *)arg1;
1285         int error;
1286         u_int n;
1287         uint8_t *val;
1288         uint8_t new[3];
1289
1290         if ((n = utp->chip->nregs) == 0)
1291                 return (EIO);
1292         val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
1293
1294         UTP_LOCK(utp);
1295         error = READREGS(utp, 0, val, &n);
1296         UTP_UNLOCK(utp);
1297
1298         if (error) {
1299                 free(val, M_TEMP);
1300                 return (error);
1301         }
1302
1303         error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
1304         free(val, M_TEMP);
1305         if (error != 0 || req->newptr == NULL)
1306                 return (error);
1307
1308         error = SYSCTL_IN(req, new, sizeof(new));
1309         if (error)
1310                 return (error);
1311
1312         UTP_LOCK(utp);
1313         error = WRITEREG(utp, new[0], new[1], new[2]);
1314         UTP_UNLOCK(utp);
1315
1316         return (error);
1317 }
1318
1319 static int
1320 utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
1321 {
1322         struct utopia *utp = (struct utopia *)arg1;
1323         void *val;
1324         int error;
1325
1326         val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
1327
1328         UTP_LOCK(utp);
1329         bcopy(&utp->stats, val, sizeof(utp->stats));
1330         if (req->newptr != NULL)
1331                 bzero((char *)&utp->stats + sizeof(utp->stats.version),
1332                     sizeof(utp->stats) - sizeof(utp->stats.version));
1333         UTP_UNLOCK(utp);
1334
1335         error = SYSCTL_OUT(req, val, sizeof(utp->stats));
1336         free(val, M_TEMP);
1337
1338         if (error && req->newptr != NULL)
1339                 bcopy(val, &utp->stats, sizeof(utp->stats));
1340
1341         /* ignore actual new value */
1342
1343         return (error);
1344 }
1345
1346 /*
1347  * Handle the loopback sysctl
1348  */
1349 static int
1350 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
1351 {
1352         struct utopia *utp = (struct utopia *)arg1;
1353         int error;
1354         u_int loopback;
1355
1356         error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
1357         if (error != 0 || req->newptr == NULL)
1358                 return (error);
1359
1360         error = SYSCTL_IN(req, &loopback, sizeof(u_int));
1361         if (error)
1362                 return (error);
1363
1364         UTP_LOCK(utp);
1365         error = utopia_set_loopback(utp, loopback);
1366         UTP_UNLOCK(utp);
1367
1368         return (error);
1369 }
1370
1371 /*
1372  * Handle the type sysctl
1373  */
1374 static int
1375 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
1376 {
1377         struct utopia *utp = (struct utopia *)arg1;
1378
1379         return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
1380 }
1381
1382 /*
1383  * Handle the name sysctl
1384  */
1385 static int
1386 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
1387 {
1388         struct utopia *utp = (struct utopia *)arg1;
1389
1390         return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
1391 }
1392
1393 /*
1394  * Initialize the state. This is called from the drivers attach
1395  * function. The mutex must be already initialized.
1396  */
1397 int
1398 utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
1399     struct mtx *lock, struct sysctl_ctx_list *ctx,
1400     struct sysctl_oid_list *children, const struct utopia_methods *m)
1401 {
1402
1403         bzero(utp, sizeof(*utp));
1404         utp->ifatm = ifatm;
1405         utp->methods = m;
1406         utp->media = media;
1407         utp->lock = lock;
1408         utp->chip = &chip_unknown;
1409         utp->stats.version = 1;
1410
1411         ifmedia_init(media,
1412             IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
1413             utopia_media_change, utopia_media_status);
1414
1415         if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
1416             CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
1417             "phy registers") == NULL)
1418                 return (-1);
1419
1420         if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
1421             CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
1422             "phy loopback mode") == NULL)
1423                 return (-1);
1424
1425         if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
1426             CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
1427             "phy type") == NULL)
1428                 return (-1);
1429
1430         if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
1431             CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
1432             "phy name") == NULL)
1433                 return (-1);
1434
1435         if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
1436             CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
1437             "phy statistics") == NULL)
1438                 return (-1);
1439
1440         if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
1441             CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
1442                 return (-1);
1443
1444         if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
1445             CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
1446                 return (-1);
1447
1448         UTP_WLOCK_LIST();
1449         LIST_INSERT_HEAD(&utopia_list, utp, link);
1450         UTP_WUNLOCK_LIST();
1451
1452         utp->state |= UTP_ST_ATTACHED;
1453         return (0);
1454 }
1455
1456 /*
1457  * Detach. We set a flag here, wakeup the daemon and let him do it.
1458  * Here we need the lock for synchronisation with the daemon.
1459  */
1460 void
1461 utopia_detach(struct utopia *utp)
1462 {
1463
1464         UTP_LOCK_ASSERT(utp);
1465         if (utp->state & UTP_ST_ATTACHED) {
1466                 utp->state |= UTP_ST_DETACH;
1467                 while (utp->state & UTP_ST_DETACH) {
1468                         wakeup(&utopia_list);
1469                         msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
1470                 }
1471         }
1472 }
1473
1474 /*
1475  * The carrier state kernel proc for those adapters that do not interrupt.
1476  *
1477  * We assume, that utopia_attach can safely add a new utopia while we are going
1478  * through the list without disturbing us (we lock the list while getting
1479  * the address of the first element, adding is always done at the head).
1480  * Removing is entirely handled here.
1481  */
1482 static void
1483 utopia_daemon(void *arg __unused)
1484 {
1485         struct utopia *utp, *next;
1486
1487         UTP_RLOCK_LIST();
1488         while (utopia_kproc != NULL) {
1489                 utp = LIST_FIRST(&utopia_list);
1490                 UTP_RUNLOCK_LIST();
1491
1492                 while (utp != NULL) {
1493                         mtx_lock(&Giant);       /* XXX depend on MPSAFE */
1494                         UTP_LOCK(utp);
1495                         next = LIST_NEXT(utp, link);
1496                         if (utp->state & UTP_ST_DETACH) {
1497                                 LIST_REMOVE(utp, link);
1498                                 utp->state &= ~UTP_ST_DETACH;
1499                                 wakeup_one(utp);
1500                         } else if (utp->state & UTP_ST_ACTIVE) {
1501                                 if (utp->flags & UTP_FL_POLL_CARRIER)
1502                                         utopia_update_carrier(utp);
1503                                 utopia_update_stats(utp);
1504                         }
1505                         UTP_UNLOCK(utp);
1506                         mtx_unlock(&Giant);     /* XXX depend on MPSAFE */
1507                         utp = next;
1508                 }
1509
1510                 UTP_RLOCK_LIST();
1511                 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
1512         }
1513         wakeup_one(&utopia_list);
1514         UTP_RUNLOCK_LIST();
1515         kthread_exit(0);
1516 }
1517
1518 /*
1519  * Module initialisation
1520  */
1521 static int
1522 utopia_mod_init(module_t mod, int what, void *arg)
1523 {
1524         int err;
1525         struct proc *kp;
1526
1527         switch (what) {
1528
1529           case MOD_LOAD:
1530                 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
1531                 err = kthread_create(utopia_daemon, NULL, &utopia_kproc,
1532                     RFHIGHPID, 0, "utopia");
1533                 if (err != 0) {
1534                         printf("cannot created utopia thread %d\n", err);
1535                         return (err);
1536                 }
1537                 break;
1538
1539           case MOD_UNLOAD:
1540                 UTP_WLOCK_LIST();
1541                 if ((kp = utopia_kproc) != NULL) {
1542                         utopia_kproc = NULL;
1543                         wakeup_one(&utopia_list);
1544                         PROC_LOCK(kp);
1545                         UTP_WUNLOCK_LIST();
1546                         msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
1547                         PROC_UNLOCK(kp);
1548                 } else
1549                         UTP_WUNLOCK_LIST();
1550                 mtx_destroy(&utopia_list_mtx);
1551                 break;
1552         }
1553         return (0);
1554 }
1555
1556 static moduledata_t utopia_mod = {
1557         "utopia",
1558         utopia_mod_init,
1559         0
1560 };
1561                 
1562 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
1563 MODULE_VERSION(utopia, 1);