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