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/module.h>
42 #include <sys/sysctl.h>
44 #include <sys/mutex.h>
45 #include <sys/socket.h>
48 #include <net/if_var.h>
49 #include <net/if_media.h>
50 #include <net/if_atm.h>
52 #include <dev/utopia/suni.h>
53 #include <dev/utopia/idtphy.h>
54 #include <dev/utopia/utopia.h>
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)
62 * Global list of all registered interfaces
64 static struct mtx utopia_list_mtx;
65 static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
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)
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)
76 static struct proc *utopia_kproc;
78 static void utopia_dump(struct utopia *) __unused;
81 * Statistics update inlines
84 utp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
92 if ((err = READREGS(utp, reg, regs, &n)) != 0) {
94 printf("%s: register read error %s(%u,%u): %d\n", __func__,
95 utp->chip->name, reg, nreg, err);
101 printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
102 utp->chip->name, reg, nreg, err);
107 for (n = nreg; n > 0; n--) {
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)
122 * Debugging - dump all registers.
125 utopia_dump(struct utopia *utp)
131 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
132 printf("SUNI read error %d\n", err);
135 for (i = 0; i < n; i++) {
140 printf(" %02x", regs[i]);
149 * Update the carrier status
152 utopia_check_carrier(struct utopia *utp, u_int carr_ok)
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);
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);
175 utopia_update_carrier_default(struct utopia *utp)
181 if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) {
182 utp->carrier = UTP_CARR_UNKNOWN;
185 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
190 * enable/disable scrambling
193 utopia_set_noscramb_default(struct utopia *utp, int noscramb)
198 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
199 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
202 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
203 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
206 utp->state |= UTP_ST_NOSCRAMB;
208 err = WRITEREG(utp, SUNI_REGO_TACPCTRL,
209 SUNI_REGM_TACPCTRL_DSCR, 0);
212 err = WRITEREG(utp, SUNI_REGO_RACPCTRL,
213 SUNI_REGM_RACPCTRL_DDSCR, 0);
216 utp->state &= ~UTP_ST_NOSCRAMB;
225 utopia_set_sdh_default(struct utopia *utp, int sdh)
230 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
231 SUNI_REGM_TPOPAPTR_S,
232 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
234 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
235 SUNI_REGM_TPOPAPTR_S,
236 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
240 utp->state &= ~UTP_ST_SDH;
242 utp->state |= UTP_ST_SDH;
248 * set idle/unassigned cells
251 utopia_set_unass_default(struct utopia *utp, int unass)
256 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
257 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
259 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH,
260 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
264 utp->state &= ~UTP_ST_UNASS;
266 utp->state |= UTP_ST_UNASS;
272 * Set loopback mode for the Lite
275 utopia_set_loopback_lite(struct utopia *utp, u_int mode)
283 if (mode & UTP_LOOP_TIME) {
284 nmode &= ~UTP_LOOP_TIME;
285 val |= SUNI_REGM_MCTRL_LOOPT;
287 if (mode & UTP_LOOP_DIAG) {
288 nmode &= ~UTP_LOOP_DIAG;
289 val |= SUNI_REGM_MCTRL_DLE;
291 if (mode & UTP_LOOP_LINE) {
292 nmode &= ~UTP_LOOP_LINE;
293 if (val & SUNI_REGM_MCTRL_DLE)
295 val |= SUNI_REGM_MCTRL_LLE;
300 err = WRITEREG(utp, SUNI_REGO_MCTRL,
301 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
305 utp->loopback = mode;
311 * Set loopback mode for the Ultra
314 utopia_set_loopback_ultra(struct utopia *utp, u_int mode)
322 if (mode & UTP_LOOP_TIME) {
323 nmode &= ~UTP_LOOP_TIME;
324 val |= SUNI_REGM_MCTRL_LOOPT;
326 if (mode & UTP_LOOP_DIAG) {
327 nmode &= ~UTP_LOOP_DIAG;
328 if (val & SUNI_REGM_MCTRL_LOOPT)
330 val |= SUNI_REGM_MCTRL_SDLE;
332 if (mode & UTP_LOOP_LINE) {
333 nmode &= ~UTP_LOOP_LINE;
334 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
336 val |= SUNI_REGM_MCTRL_LLE;
338 if (mode & UTP_LOOP_PARAL) {
339 nmode &= ~UTP_LOOP_PARAL;
340 val |= SUNI_REGM_MCTRL_PDLE;
342 if (mode & UTP_LOOP_TWIST) {
343 nmode &= ~UTP_LOOP_TWIST;
344 val |= SUNI_REGM_MCTRL_TPLE;
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);
354 utp->loopback = mode;
360 * Set loopback mode for the Ultra
363 utopia_set_loopback_622(struct utopia *utp, u_int mode)
374 if (mode & UTP_LOOP_PATH) {
375 nmode &= ~UTP_LOOP_PATH;
376 val |= SUNI_REGM_MCTRLM_DPLE;
379 err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
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);
387 if (mode & UTP_LOOP_TIME) {
390 nmode &= ~UTP_LOOP_TIME;
391 val |= SUNI_REGM_MCTRLM_LOOPT;
393 if (mode & UTP_LOOP_DIAG) {
394 nmode &= ~UTP_LOOP_DIAG;
395 if (val & SUNI_REGM_MCTRLM_LOOPT)
397 val |= SUNI_REGM_MCTRLM_DLE;
399 if (mode & UTP_LOOP_LINE) {
400 nmode &= ~UTP_LOOP_LINE;
401 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
403 val |= SUNI_REGM_MCTRLM_LLE;
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);
413 utp->loopback = mode;
419 * Set the SUNI chip to reflect the current state in utopia.
420 * Assume, that the chip has been reset.
423 utopia_set_chip(struct utopia *utp)
428 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
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);
435 err |= utopia_set_loopback(utp, utp->loopback);
437 /* update carrier state */
438 err |= utopia_update_carrier(utp);
440 /* enable interrupts on LOS */
441 err |= WRITEREG(utp, SUNI_REGO_RSOPCIE,
442 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
444 return (err ? EIO : 0);
448 * Reset the SUNI chip to reflect the current state of utopia.
451 utopia_reset_default(struct utopia *utp)
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,
462 /* disable test mode */
463 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
465 err |= utopia_set_chip(utp);
467 return (err ? EIO : 0);
471 * Reset the SUNI chip to reflect the current state of utopia.
474 utopia_reset_622(struct utopia *utp)
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,
485 /* disable test mode */
486 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
487 SUNI_REGM_MTEST_DS27_53_622);
489 err |= utopia_set_chip(utp);
491 return (err ? EIO : 0);
495 * Handle interrupt on lite chip
498 utopia_intr_default(struct utopia *utp)
500 uint8_t regs[SUNI_REGO_MTEST];
501 u_int n = SUNI_REGO_MTEST;
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);
509 if (n <= SUNI_REGO_RSOPSIS) {
510 printf("%s: could not read RSOPSIS", __func__);
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));
521 * Update statistics from a SUNI/LITE or SUNI/ULTRA
524 suni_lite_update_stats(struct utopia *utp)
528 /* write to the master if we can */
529 if (!(utp->flags & UTP_FL_NORESET)) {
530 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
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);
541 printf("%s: register write error %s: %d\n", __func__,
542 utp->chip->name, err);
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);
561 * Update statistics from a SUNI/622
564 suni_622_update_stats(struct utopia *utp)
568 /* write to the master if we can */
569 if (!(utp->flags & UTP_FL_NORESET)) {
570 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
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);
580 printf("%s: register write error %s: %d\n", __func__,
581 utp->chip->name, err);
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);
599 static const struct utopia_chip chip_622 = {
601 "Suni/622 (PMC-5355)",
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,
610 suni_622_update_stats,
612 static const struct utopia_chip chip_lite = {
614 "Suni/Lite (PMC-5346)",
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,
623 suni_lite_update_stats,
625 static const struct utopia_chip chip_ultra = {
627 "Suni/Ultra (PMC-5350)",
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,
636 suni_lite_update_stats,
640 * Reset IDT77105. There is really no way to reset this thing by acessing
641 * the registers. Load the registers with default values.
644 idt77105_reset(struct utopia *utp)
650 err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
651 IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
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);
657 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
659 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
661 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
663 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
665 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
667 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
669 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
671 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n);
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);
679 err |= utopia_set_loopback(utp, utp->loopback);
681 /* update carrier state */
682 err |= utopia_update_carrier(utp);
684 return (err ? EIO : 0);
688 unknown_inval(struct utopia *utp, int what __unused)
694 idt77105_update_carrier(struct utopia *utp)
700 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
701 utp->carrier = UTP_CARR_UNKNOWN;
704 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
709 idt77105_set_loopback(struct utopia *utp, u_int mode)
715 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
716 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
720 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
721 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
725 err = WRITEREG(utp, IDTPHY_REGO_DIAG,
726 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
734 utp->loopback = mode;
739 * Handle interrupt on IDT77105 chip
742 idt77105_intr(struct utopia *utp)
748 /* Interrupt status and ack the interrupt */
749 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) {
750 printf("IDT77105 read error %d\n", err);
753 /* check for signal condition */
754 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
758 idt77105_update_stats(struct utopia *utp)
765 #define UDIAG(F,A,B) printf(F, A, B)
767 #define UDIAG(F,A,B) do { } while (0)
770 #define UPD(FIELD, CODE, N, MASK) \
771 err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \
773 UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \
777 err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \
779 UDIAG("%s: cannot read CNT: %d\n", __func__, err); \
783 UDIAG("%s: got only %u registers\n", __func__, n); \
787 utp->stats.FIELD += (regs[0] & MASK); \
789 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
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);
800 static const struct utopia_chip chip_idt77105 = {
808 idt77105_update_carrier,
809 idt77105_set_loopback,
811 idt77105_update_stats,
815 * Update the carrier status
818 idt77155_update_carrier(struct utopia *utp)
824 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
825 utp->carrier = UTP_CARR_UNKNOWN;
828 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
833 * Handle interrupt on IDT77155 chip
836 idt77155_intr(struct utopia *utp)
842 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) {
843 printf("IDT77105 read error %d\n", err);
846 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
853 idt77155_set_sdh(struct utopia *utp, int sdh)
858 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
859 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
861 err = WRITEREG(utp, IDTPHY_REGO_PTRM,
862 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
866 utp->state &= ~UTP_ST_SDH;
868 utp->state |= UTP_ST_SDH;
874 * set idle/unassigned cells
877 idt77155_set_unass(struct utopia *utp, int unass)
882 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
884 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
888 utp->state &= ~UTP_ST_UNASS;
890 utp->state |= UTP_ST_UNASS;
896 * enable/disable scrambling
899 idt77155_set_noscramb(struct utopia *utp, int noscramb)
904 err = WRITEREG(utp, IDTPHY_REGO_TCC,
905 IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
908 err = WRITEREG(utp, IDTPHY_REGO_RCC,
909 IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
912 utp->state |= UTP_ST_NOSCRAMB;
914 err = WRITEREG(utp, IDTPHY_REGO_TCC,
915 IDTPHY_REGM_TCC_DSCR, 0);
918 err = WRITEREG(utp, IDTPHY_REGO_RCC,
919 IDTPHY_REGM_RCC_DSCR, 0);
922 utp->state &= ~UTP_ST_NOSCRAMB;
928 * Set loopback mode for the 77155
931 idt77155_set_loopback(struct utopia *utp, u_int mode)
939 if (mode & UTP_LOOP_TIME) {
940 nmode &= ~UTP_LOOP_TIME;
941 val |= IDTPHY_REGM_MCTL_TLOOP;
943 if (mode & UTP_LOOP_DIAG) {
944 nmode &= ~UTP_LOOP_DIAG;
945 val |= IDTPHY_REGM_MCTL_DLOOP;
947 if (mode & UTP_LOOP_LINE) {
948 nmode &= ~UTP_LOOP_LINE;
949 val |= IDTPHY_REGM_MCTL_LLOOP;
954 err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
955 IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
958 utp->loopback = mode;
964 * Set the chip to reflect the current state in utopia.
965 * Assume, that the chip has been reset.
968 idt77155_set_chip(struct utopia *utp)
973 err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
975 /* unassigned or idle cells */
976 err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
979 err |= idt77155_set_loopback(utp, utp->loopback);
981 /* update carrier state */
982 err |= idt77155_update_carrier(utp);
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);
990 return (err ? EIO : 0);
994 * Reset the chip to reflect the current state of utopia.
997 idt77155_reset(struct utopia *utp)
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,
1008 err |= idt77155_set_chip(utp);
1010 return (err ? EIO : 0);
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.
1019 idt77155_update_stats(struct utopia *utp)
1023 /* write to the master if we can */
1024 if (!(utp->flags & UTP_FL_NORESET)) {
1025 err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
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);
1036 printf("%s: register write error %s: %d\n", __func__,
1037 utp->chip->name, err);
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);
1056 static const struct utopia_chip chip_idt77155 = {
1063 idt77155_set_noscramb,
1064 idt77155_update_carrier,
1065 idt77155_set_loopback,
1067 idt77155_update_stats,
1071 unknown_reset(struct utopia *utp __unused)
1077 unknown_update_carrier(struct utopia *utp)
1079 utp->carrier = UTP_CARR_UNKNOWN;
1084 unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
1090 unknown_intr(struct utopia *utp __unused)
1095 unknown_update_stats(struct utopia *utp __unused)
1099 static const struct utopia_chip chip_unknown = {
1107 unknown_update_carrier,
1108 unknown_set_loopback,
1110 unknown_update_stats,
1114 * Callbacks for the ifmedia infrastructure.
1117 utopia_media_change(struct ifnet *ifp)
1119 struct ifatm *ifatm = (struct ifatm *)ifp->if_softc;
1120 struct utopia *utp = ifatm->phy;
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);
1129 if (utp->state & UTP_ST_SDH)
1130 error = utopia_set_sdh(utp, 0);
1132 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
1133 if (!(utp->state & UTP_ST_UNASS))
1134 error = utopia_set_unass(utp, 1);
1136 if (utp->state & UTP_ST_UNASS)
1137 error = utopia_set_unass(utp, 0);
1139 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
1140 if (!(utp->state & UTP_ST_NOSCRAMB))
1141 error = utopia_set_noscramb(utp, 1);
1143 if (utp->state & UTP_ST_NOSCRAMB)
1144 error = utopia_set_noscramb(utp, 0);
1153 * Look at the carrier status.
1156 utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1158 struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy;
1161 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
1162 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
1164 switch (utp->carrier) {
1167 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1171 ifmr->ifm_status = IFM_AVALID;
1175 ifmr->ifm_status = 0;
1178 if (utp->state & UTP_ST_SDH) {
1179 ifmr->ifm_active |= IFM_ATM_SDH;
1180 ifmr->ifm_current |= IFM_ATM_SDH;
1182 if (utp->state & UTP_ST_UNASS) {
1183 ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
1184 ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
1186 if (utp->state & UTP_ST_NOSCRAMB) {
1187 ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
1188 ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
1191 ifmr->ifm_active = 0;
1192 ifmr->ifm_status = 0;
1198 * Initialize media from the mib
1201 utopia_init_media(struct utopia *utp)
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);
1213 utopia_reset_media(struct utopia *utp)
1216 ifmedia_removeall(utp->media);
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.
1224 utopia_start(struct utopia *utp)
1230 if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0)
1233 switch (reg & SUNI_REGM_MRESET_TYPE) {
1235 case SUNI_REGM_MRESET_TYPE_622:
1236 utp->chip = &chip_622;
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 */
1243 if ((err = READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0)
1245 if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
1246 (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
1247 utp->chip = &chip_idt77155;
1249 utp->chip = &chip_lite;
1252 case SUNI_REGM_MRESET_TYPE_ULTRA:
1253 utp->chip = &chip_ultra;
1257 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
1258 utp->chip = &chip_idt77105;
1260 if_printf(&utp->ifatm->ifnet,
1261 "unknown ATM-PHY chip %#x\n", reg);
1262 utp->chip = &chip_unknown;
1266 utp->state |= UTP_ST_ACTIVE;
1274 utopia_stop(struct utopia *utp)
1276 utp->state &= ~UTP_ST_ACTIVE;
1280 * Handle the sysctls
1283 utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
1285 struct utopia *utp = (struct utopia *)arg1;
1291 if ((n = utp->chip->nregs) == 0)
1293 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
1296 error = READREGS(utp, 0, val, &n);
1304 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
1306 if (error != 0 || req->newptr == NULL)
1309 error = SYSCTL_IN(req, new, sizeof(new));
1314 error = WRITEREG(utp, new[0], new[1], new[2]);
1321 utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
1323 struct utopia *utp = (struct utopia *)arg1;
1327 val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
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));
1336 error = SYSCTL_OUT(req, val, sizeof(utp->stats));
1339 if (error && req->newptr != NULL)
1340 bcopy(val, &utp->stats, sizeof(utp->stats));
1342 /* ignore actual new value */
1348 * Handle the loopback sysctl
1351 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
1353 struct utopia *utp = (struct utopia *)arg1;
1357 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
1358 if (error != 0 || req->newptr == NULL)
1361 error = SYSCTL_IN(req, &loopback, sizeof(u_int));
1366 error = utopia_set_loopback(utp, loopback);
1373 * Handle the type sysctl
1376 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
1378 struct utopia *utp = (struct utopia *)arg1;
1380 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
1384 * Handle the name sysctl
1387 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
1389 struct utopia *utp = (struct utopia *)arg1;
1391 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
1395 * Initialize the state. This is called from the drivers attach
1396 * function. The mutex must be already initialized.
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)
1404 bzero(utp, sizeof(*utp));
1409 utp->chip = &chip_unknown;
1410 utp->stats.version = 1;
1413 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
1414 utopia_media_change, utopia_media_status);
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)
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)
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)
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)
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)
1441 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
1442 CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
1445 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
1446 CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
1450 LIST_INSERT_HEAD(&utopia_list, utp, link);
1453 utp->state |= UTP_ST_ATTACHED;
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.
1462 utopia_detach(struct utopia *utp)
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);
1476 * The carrier state kernel proc for those adapters that do not interrupt.
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.
1484 utopia_daemon(void *arg __unused)
1486 struct utopia *utp, *next;
1489 while (utopia_kproc != NULL) {
1490 utp = LIST_FIRST(&utopia_list);
1493 while (utp != NULL) {
1494 mtx_lock(&Giant); /* XXX depend on MPSAFE */
1496 next = LIST_NEXT(utp, link);
1497 if (utp->state & UTP_ST_DETACH) {
1498 LIST_REMOVE(utp, link);
1499 utp->state &= ~UTP_ST_DETACH;
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);
1507 mtx_unlock(&Giant); /* XXX depend on MPSAFE */
1512 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
1514 wakeup_one(&utopia_list);
1520 * Module initialisation
1523 utopia_mod_init(module_t mod, int what, void *arg)
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");
1535 printf("cannot created utopia thread %d\n", err);
1542 if ((kp = utopia_kproc) != NULL) {
1543 utopia_kproc = NULL;
1544 wakeup_one(&utopia_list);
1547 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
1551 mtx_destroy(&utopia_list_mtx);
1557 static moduledata_t utopia_mod = {
1563 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
1564 MODULE_VERSION(utopia, 1);