3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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>
40 #include <sys/malloc.h>
41 #include <sys/sysctl.h>
43 #include <sys/mutex.h>
44 #include <sys/socket.h>
47 #include <net/if_var.h>
48 #include <net/if_media.h>
49 #include <net/if_atm.h>
51 #include <dev/utopia/suni.h>
52 #include <dev/utopia/idtphy.h>
53 #include <dev/utopia/utopia.h>
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)
61 * Global list of all registered interfaces
63 static struct mtx utopia_list_mtx;
64 static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
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)
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)
75 static struct proc *utopia_kproc;
77 static void utopia_dump(struct utopia *) __unused;
80 * Statistics update inlines
83 utp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
91 if ((err = READREGS(utp, reg, regs, &n)) != 0) {
93 printf("%s: register read error %s(%u,%u): %d\n", __func__,
94 utp->chip->name, reg, nreg, err);
100 printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
101 utp->chip->name, reg, nreg, err);
106 for (n = nreg; n > 0; n--) {
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)
121 * Debugging - dump all registers.
124 utopia_dump(struct utopia *utp)
130 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
131 printf("SUNI read error %d\n", err);
134 for (i = 0; i < n; i++) {
139 printf(" %02x", regs[i]);
148 * Update the carrier status
151 utopia_check_carrier(struct utopia *utp, u_int carr_ok)
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);
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);
174 utopia_update_carrier_default(struct utopia *utp)
180 if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) {
181 utp->carrier = UTP_CARR_UNKNOWN;
184 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
189 * enable/disable scrambling
192 utopia_set_noscramb_default(struct utopia *utp, int noscramb)
197 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
198 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
201 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
202 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
205 utp->state |= UTP_ST_NOSCRAMB;
207 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
208 SUNI_REGM_TACPCTRL_DSCR, 0);
211 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
212 SUNI_REGM_RACPCTRL_DDSCR, 0);
215 utp->state &= ~UTP_ST_NOSCRAMB;
224 utopia_set_sdh_default(struct utopia *utp, int sdh)
229 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
230 SUNI_REGM_TPOPAPTR_S,
231 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
233 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
234 SUNI_REGM_TPOPAPTR_S,
235 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
239 utp->state &= ~UTP_ST_SDH;
241 utp->state |= UTP_ST_SDH;
247 * set idle/unassigned cells
250 utopia_set_unass_default(struct utopia *utp, int unass)
255 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
256 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
258 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
259 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
263 utp->state &= ~UTP_ST_UNASS;
265 utp->state |= UTP_ST_UNASS;
271 * Set loopback mode for the Lite
274 utopia_set_loopback_lite(struct utopia *utp, u_int mode)
282 if (mode & UTP_LOOP_TIME) {
283 nmode &= ~UTP_LOOP_TIME;
284 val |= SUNI_REGM_MCTRL_LOOPT;
286 if (mode & UTP_LOOP_DIAG) {
287 nmode &= ~UTP_LOOP_DIAG;
288 val |= SUNI_REGM_MCTRL_DLE;
290 if (mode & UTP_LOOP_LINE) {
291 nmode &= ~UTP_LOOP_LINE;
292 if (val & SUNI_REGM_MCTRL_DLE)
294 val |= SUNI_REGM_MCTRL_LLE;
299 err = WRITEREG(utp, SUNI_REGO_MCTRL,
300 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
304 utp->loopback = mode;
310 * Set loopback mode for the Ultra
313 utopia_set_loopback_ultra(struct utopia *utp, u_int mode)
321 if (mode & UTP_LOOP_TIME) {
322 nmode &= ~UTP_LOOP_TIME;
323 val |= SUNI_REGM_MCTRL_LOOPT;
325 if (mode & UTP_LOOP_DIAG) {
326 nmode &= ~UTP_LOOP_DIAG;
327 if (val & SUNI_REGM_MCTRL_LOOPT)
329 val |= SUNI_REGM_MCTRL_SDLE;
331 if (mode & UTP_LOOP_LINE) {
332 nmode &= ~UTP_LOOP_LINE;
333 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
335 val |= SUNI_REGM_MCTRL_LLE;
337 if (mode & UTP_LOOP_PARAL) {
338 nmode &= ~UTP_LOOP_PARAL;
339 val |= SUNI_REGM_MCTRL_PDLE;
341 if (mode & UTP_LOOP_TWIST) {
342 nmode &= ~UTP_LOOP_TWIST;
343 val |= SUNI_REGM_MCTRL_TPLE;
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);
353 utp->loopback = mode;
359 * Set loopback mode for the Ultra
362 utopia_set_loopback_622(struct utopia *utp, u_int mode)
373 if (mode & UTP_LOOP_PATH) {
374 nmode &= ~UTP_LOOP_PATH;
375 val |= SUNI_REGM_MCTRLM_DPLE;
378 err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
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);
386 if (mode & UTP_LOOP_TIME) {
389 nmode &= ~UTP_LOOP_TIME;
390 val |= SUNI_REGM_MCTRLM_LOOPT;
392 if (mode & UTP_LOOP_DIAG) {
393 nmode &= ~UTP_LOOP_DIAG;
394 if (val & SUNI_REGM_MCTRLM_LOOPT)
396 val |= SUNI_REGM_MCTRLM_DLE;
398 if (mode & UTP_LOOP_LINE) {
399 nmode &= ~UTP_LOOP_LINE;
400 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
402 val |= SUNI_REGM_MCTRLM_LLE;
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);
412 utp->loopback = mode;
418 * Set the SUNI chip to reflect the current state in utopia.
419 * Assume, that the chip has been reset.
422 utopia_set_chip(struct utopia *utp)
427 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
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);
434 err |= utopia_set_loopback(utp, utp->loopback);
436 /* update carrier state */
437 err |= utopia_update_carrier(utp);
439 /* enable interrupts on LOS */
440 err |= WRITEREG(utp, SUNI_REGO_RSOPCIE,
441 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
443 return (err ? EIO : 0);
447 * Reset the SUNI chip to reflect the current state of utopia.
450 utopia_reset_default(struct utopia *utp)
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,
461 /* disable test mode */
462 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
464 err |= utopia_set_chip(utp);
466 return (err ? EIO : 0);
470 * Reset the SUNI chip to reflect the current state of utopia.
473 utopia_reset_622(struct utopia *utp)
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,
484 /* disable test mode */
485 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
486 SUNI_REGM_MTEST_DS27_53_622);
488 err |= utopia_set_chip(utp);
490 return (err ? EIO : 0);
494 * Handle interrupt on lite chip
497 utopia_intr_default(struct utopia *utp)
499 uint8_t regs[SUNI_REGO_MTEST];
500 u_int n = SUNI_REGO_MTEST;
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);
508 if (n <= SUNI_REGO_RSOPSIS) {
509 printf("%s: could not read RSOPSIS", __func__);
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));
520 * Update statistics from a SUNI/LITE or SUNI/ULTRA
523 suni_lite_update_stats(struct utopia *utp)
527 /* write to the master if we can */
528 if (!(utp->flags & UTP_FL_NORESET)) {
529 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
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);
540 printf("%s: register write error %s: %d\n", __func__,
541 utp->chip->name, err);
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);
560 * Update statistics from a SUNI/622
563 suni_622_update_stats(struct utopia *utp)
567 /* write to the master if we can */
568 if (!(utp->flags & UTP_FL_NORESET)) {
569 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
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);
579 printf("%s: register write error %s: %d\n", __func__,
580 utp->chip->name, err);
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);
598 static const struct utopia_chip chip_622 = {
600 "Suni/622 (PMC-5355)",
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,
609 suni_622_update_stats,
611 static const struct utopia_chip chip_lite = {
613 "Suni/Lite (PMC-5346)",
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,
622 suni_lite_update_stats,
624 static const struct utopia_chip chip_ultra = {
626 "Suni/Ultra (PMC-5350)",
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,
635 suni_lite_update_stats,
639 * Reset IDT77105. There is really no way to reset this thing by acessing
640 * the registers. Load the registers with default values.
643 idt77105_reset(struct utopia *utp)
649 err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
650 IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
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);
656 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
658 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
660 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
662 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
664 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
666 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
668 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
670 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
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);
678 err |= utopia_set_loopback(utp, utp->loopback);
680 /* update carrier state */
681 err |= utopia_update_carrier(utp);
683 return (err ? EIO : 0);
687 unknown_inval(struct utopia *utp, int what __unused)
693 idt77105_update_carrier(struct utopia *utp)
699 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
700 utp->carrier = UTP_CARR_UNKNOWN;
703 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
708 idt77105_set_loopback(struct utopia *utp, u_int mode)
714 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
715 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
719 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
720 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
724 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
725 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
733 utp->loopback = mode;
738 * Handle interrupt on IDT77105 chip
741 idt77105_intr(struct utopia *utp)
747 /* Interrupt status and ack the interrupt */
748 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
749 printf("IDT77105 read error %d\n", err);
752 /* check for signal condition */
753 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
757 idt77105_update_stats(struct utopia *utp)
764 #define UDIAG(F,A,B) printf(F, A, B)
766 #define UDIAG(F,A,B) do { } while (0)
769 #define UPD(FIELD, CODE, N, MASK) \
770 err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \
772 UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \
776 err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \
778 UDIAG("%s: cannot read CNT: %d\n", __func__, err); \
782 UDIAG("%s: got only %u registers\n", __func__, n); \
786 utp->stats.FIELD += (regs[0] & MASK); \
788 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
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);
799 static const struct utopia_chip chip_idt77105 = {
807 idt77105_update_carrier,
808 idt77105_set_loopback,
810 idt77105_update_stats,
814 * Update the carrier status
817 idt77155_update_carrier(struct utopia *utp)
823 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
824 utp->carrier = UTP_CARR_UNKNOWN;
827 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
832 * Handle interrupt on IDT77155 chip
835 idt77155_intr(struct utopia *utp)
841 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
842 printf("IDT77105 read error %d\n", err);
845 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
852 idt77155_set_sdh(struct utopia *utp, int sdh)
857 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
858 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
860 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
861 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
865 utp->state &= ~UTP_ST_SDH;
867 utp->state |= UTP_ST_SDH;
873 * set idle/unassigned cells
876 idt77155_set_unass(struct utopia *utp, int unass)
881 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
883 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
887 utp->state &= ~UTP_ST_UNASS;
889 utp->state |= UTP_ST_UNASS;
895 * enable/disable scrambling
898 idt77155_set_noscramb(struct utopia *utp, int noscramb)
903 err = WRITEREG(utp, IDTPHY_REGO_TCC,
904 IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
907 err = WRITEREG(utp, IDTPHY_REGO_RCC,
908 IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
911 utp->state |= UTP_ST_NOSCRAMB;
913 err = WRITEREG(utp, IDTPHY_REGO_TCC,
914 IDTPHY_REGM_TCC_DSCR, 0);
917 err = WRITEREG(utp, IDTPHY_REGO_RCC,
918 IDTPHY_REGM_RCC_DSCR, 0);
921 utp->state &= ~UTP_ST_NOSCRAMB;
927 * Set loopback mode for the 77155
930 idt77155_set_loopback(struct utopia *utp, u_int mode)
938 if (mode & UTP_LOOP_TIME) {
939 nmode &= ~UTP_LOOP_TIME;
940 val |= IDTPHY_REGM_MCTL_TLOOP;
942 if (mode & UTP_LOOP_DIAG) {
943 nmode &= ~UTP_LOOP_DIAG;
944 val |= IDTPHY_REGM_MCTL_DLOOP;
946 if (mode & UTP_LOOP_LINE) {
947 nmode &= ~UTP_LOOP_LINE;
948 val |= IDTPHY_REGM_MCTL_LLOOP;
953 err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
954 IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
957 utp->loopback = mode;
963 * Set the chip to reflect the current state in utopia.
964 * Assume, that the chip has been reset.
967 idt77155_set_chip(struct utopia *utp)
972 err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
974 /* unassigned or idle cells */
975 err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
978 err |= idt77155_set_loopback(utp, utp->loopback);
980 /* update carrier state */
981 err |= idt77155_update_carrier(utp);
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);
989 return (err ? EIO : 0);
993 * Reset the chip to reflect the current state of utopia.
996 idt77155_reset(struct utopia *utp)
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,
1007 err |= idt77155_set_chip(utp);
1009 return (err ? EIO : 0);
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.
1018 idt77155_update_stats(struct utopia *utp)
1022 /* write to the master if we can */
1023 if (!(utp->flags & UTP_FL_NORESET)) {
1024 err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
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);
1035 printf("%s: register write error %s: %d\n", __func__,
1036 utp->chip->name, err);
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);
1055 static const struct utopia_chip chip_idt77155 = {
1062 idt77155_set_noscramb,
1063 idt77155_update_carrier,
1064 idt77155_set_loopback,
1066 idt77155_update_stats,
1070 unknown_reset(struct utopia *utp __unused)
1076 unknown_update_carrier(struct utopia *utp)
1078 utp->carrier = UTP_CARR_UNKNOWN;
1083 unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
1089 unknown_intr(struct utopia *utp __unused)
1094 unknown_update_stats(struct utopia *utp __unused)
1098 static const struct utopia_chip chip_unknown = {
1106 unknown_update_carrier,
1107 unknown_set_loopback,
1109 unknown_update_stats,
1113 * Callbacks for the ifmedia infrastructure.
1116 utopia_media_change(struct ifnet *ifp)
1118 struct ifatm *ifatm = (struct ifatm *)ifp->if_softc;
1119 struct utopia *utp = ifatm->phy;
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);
1128 if (utp->state & UTP_ST_SDH)
1129 error = utopia_set_sdh(utp, 0);
1131 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
1132 if (!(utp->state & UTP_ST_UNASS))
1133 error = utopia_set_unass(utp, 1);
1135 if (utp->state & UTP_ST_UNASS)
1136 error = utopia_set_unass(utp, 0);
1138 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
1139 if (!(utp->state & UTP_ST_NOSCRAMB))
1140 error = utopia_set_noscramb(utp, 1);
1142 if (utp->state & UTP_ST_NOSCRAMB)
1143 error = utopia_set_noscramb(utp, 0);
1152 * Look at the carrier status.
1155 utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1157 struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy;
1160 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1161 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
1163 switch (utp->carrier) {
1166 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1170 ifmr->ifm_status = IFM_AVALID;
1174 ifmr->ifm_status = 0;
1177 if (utp->state & UTP_ST_SDH) {
1178 ifmr->ifm_active |= IFM_ATM_SDH;
1179 ifmr->ifm_current |= IFM_ATM_SDH;
1181 if (utp->state & UTP_ST_UNASS) {
1182 ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
1183 ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
1185 if (utp->state & UTP_ST_NOSCRAMB) {
1186 ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
1187 ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
1190 ifmr->ifm_active = 0;
1191 ifmr->ifm_status = 0;
1197 * Initialize media from the mib
1200 utopia_init_media(struct utopia *utp)
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);
1212 utopia_reset_media(struct utopia *utp)
1215 ifmedia_removeall(utp->media);
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.
1223 utopia_start(struct utopia *utp)
1229 if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0)
1232 switch (reg & SUNI_REGM_MRESET_TYPE) {
1234 case SUNI_REGM_MRESET_TYPE_622:
1235 utp->chip = &chip_622;
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 */
1242 if ((err = READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0)
1244 if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
1245 (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
1246 utp->chip = &chip_idt77155;
1248 utp->chip = &chip_lite;
1251 case SUNI_REGM_MRESET_TYPE_ULTRA:
1252 utp->chip = &chip_ultra;
1256 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
1257 utp->chip = &chip_idt77105;
1259 if_printf(&utp->ifatm->ifnet,
1260 "unknown ATM-PHY chip %#x\n", reg);
1261 utp->chip = &chip_unknown;
1265 utp->state |= UTP_ST_ACTIVE;
1273 utopia_stop(struct utopia *utp)
1275 utp->state &= ~UTP_ST_ACTIVE;
1279 * Handle the sysctls
1282 utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
1284 struct utopia *utp = (struct utopia *)arg1;
1290 if ((n = utp->chip->nregs) == 0)
1292 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
1295 error = READREGS(utp, 0, val, &n);
1303 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
1305 if (error != 0 || req->newptr == NULL)
1308 error = SYSCTL_IN(req, new, sizeof(new));
1313 error = WRITEREG(utp, new[0], new[1], new[2]);
1320 utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
1322 struct utopia *utp = (struct utopia *)arg1;
1326 val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
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));
1335 error = SYSCTL_OUT(req, val, sizeof(utp->stats));
1338 if (error && req->newptr != NULL)
1339 bcopy(val, &utp->stats, sizeof(utp->stats));
1341 /* ignore actual new value */
1347 * Handle the loopback sysctl
1350 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
1352 struct utopia *utp = (struct utopia *)arg1;
1356 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
1357 if (error != 0 || req->newptr == NULL)
1360 error = SYSCTL_IN(req, &loopback, sizeof(u_int));
1365 error = utopia_set_loopback(utp, loopback);
1372 * Handle the type sysctl
1375 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
1377 struct utopia *utp = (struct utopia *)arg1;
1379 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
1383 * Handle the name sysctl
1386 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
1388 struct utopia *utp = (struct utopia *)arg1;
1390 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
1394 * Initialize the state. This is called from the drivers attach
1395 * function. The mutex must be already initialized.
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)
1403 bzero(utp, sizeof(*utp));
1408 utp->chip = &chip_unknown;
1409 utp->stats.version = 1;
1412 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
1413 utopia_media_change, utopia_media_status);
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)
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)
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)
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)
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)
1440 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
1441 CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
1444 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
1445 CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
1449 LIST_INSERT_HEAD(&utopia_list, utp, link);
1452 utp->state |= UTP_ST_ATTACHED;
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.
1461 utopia_detach(struct utopia *utp)
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);
1475 * The carrier state kernel proc for those adapters that do not interrupt.
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.
1483 utopia_daemon(void *arg __unused)
1485 struct utopia *utp, *next;
1488 while (utopia_kproc != NULL) {
1489 utp = LIST_FIRST(&utopia_list);
1492 while (utp != NULL) {
1493 mtx_lock(&Giant); /* XXX depend on MPSAFE */
1495 next = LIST_NEXT(utp, link);
1496 if (utp->state & UTP_ST_DETACH) {
1497 LIST_REMOVE(utp, link);
1498 utp->state &= ~UTP_ST_DETACH;
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);
1506 mtx_unlock(&Giant); /* XXX depend on MPSAFE */
1511 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
1513 wakeup_one(&utopia_list);
1519 * Module initialisation
1522 utopia_mod_init(module_t mod, int what, void *arg)
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");
1534 printf("cannot created utopia thread %d\n", err);
1541 if ((kp = utopia_kproc) != NULL) {
1542 utopia_kproc = NULL;
1543 wakeup_one(&utopia_list);
1546 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
1550 mtx_destroy(&utopia_list_mtx);
1556 static moduledata_t utopia_mod = {
1562 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
1563 MODULE_VERSION(utopia, 1);