3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
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/utopia.h>
54 #include <dev/utopia/utopia_priv.h>
60 suni_set_sdh(struct utopia *utp, int sdh)
65 err = UTP_WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
67 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
69 err = UTP_WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
71 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
75 utp->state &= ~UTP_ST_SDH;
77 utp->state |= UTP_ST_SDH;
83 * set idle/unassigned cells
86 suni_set_unass(struct utopia *utp, int unass)
91 err = UTP_WRITEREG(utp, SUNI_REGO_TACPIDLEH,
92 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
94 err = UTP_WRITEREG(utp, SUNI_REGO_TACPIDLEH,
95 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
99 utp->state &= ~UTP_ST_UNASS;
101 utp->state |= UTP_ST_UNASS;
107 * enable/disable scrambling
110 suni_set_noscramb(struct utopia *utp, int noscramb)
115 err = UTP_WRITEREG(utp, SUNI_REGO_TACPCTRL,
116 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
119 err = UTP_WRITEREG(utp, SUNI_REGO_RACPCTRL,
120 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
123 utp->state |= UTP_ST_NOSCRAMB;
125 err = UTP_WRITEREG(utp, SUNI_REGO_TACPCTRL,
126 SUNI_REGM_TACPCTRL_DSCR, 0);
129 err = UTP_WRITEREG(utp, SUNI_REGO_RACPCTRL,
130 SUNI_REGM_RACPCTRL_DDSCR, 0);
133 utp->state &= ~UTP_ST_NOSCRAMB;
139 * Get current carrier state
142 suni_update_carrier(struct utopia *utp)
148 if ((err = UTP_READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) {
149 utp->carrier = UTP_CARR_UNKNOWN;
152 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
157 * Set the SUNI chip to reflect the current state in utopia.
158 * Assume, that the chip has been reset.
161 suni_set_chip(struct utopia *utp)
166 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
168 /* unassigned or idle cells */
169 err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS);
170 err |= UTP_WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a);
173 err |= utopia_set_noscramb(utp, utp->state & UTP_ST_NOSCRAMB);
176 err |= utopia_set_loopback(utp, utp->loopback);
178 /* update carrier state */
179 err |= utopia_update_carrier(utp);
181 /* enable interrupts on LOS */
182 err |= UTP_WRITEREG(utp, SUNI_REGO_RSOPCIE,
183 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
185 return (err ? EIO : 0);
189 * Reset the SUNI chip to reflect the current state of utopia.
192 suni_reset_default(struct utopia *utp)
196 if (!(utp->flags & UTP_FL_NORESET)) {
197 err |= UTP_WRITEREG(utp, SUNI_REGO_MRESET,
198 SUNI_REGM_MRESET_RESET, SUNI_REGM_MRESET_RESET);
199 err |= UTP_WRITEREG(utp, SUNI_REGO_MRESET,
200 SUNI_REGM_MRESET_RESET, 0);
203 /* disable test mode */
204 err |= UTP_WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
206 err |= suni_set_chip(utp);
208 return (err ? EIO : 0);
212 * Set loopback mode for the Lite
215 suni_set_loopback_lite(struct utopia *utp, u_int mode)
223 if (mode & UTP_LOOP_TIME) {
224 nmode &= ~UTP_LOOP_TIME;
225 val |= SUNI_REGM_MCTRL_LOOPT;
227 if (mode & UTP_LOOP_DIAG) {
228 nmode &= ~UTP_LOOP_DIAG;
229 val |= SUNI_REGM_MCTRL_DLE;
231 if (mode & UTP_LOOP_LINE) {
232 nmode &= ~UTP_LOOP_LINE;
233 if (val & SUNI_REGM_MCTRL_DLE)
235 val |= SUNI_REGM_MCTRL_LLE;
240 err = UTP_WRITEREG(utp, SUNI_REGO_MCTRL,
241 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
245 utp->loopback = mode;
251 * Update statistics from a SUNI/LITE or SUNI/ULTRA
254 suni_lite_update_stats(struct utopia *utp)
258 /* write to the master if we can */
259 if (!(utp->flags & UTP_FL_NORESET)) {
260 err = UTP_WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
262 err = UTP_WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
263 err |= UTP_WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
264 err |= UTP_WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
265 err |= UTP_WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
266 err |= UTP_WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
271 printf("%s: register write error %s: %d\n", __func__,
272 utp->chip->name, err);
279 utp->stats.rx_sbip += utopia_update(utp,
280 SUNI_REGO_RSOP_BIP8, 2, 0xffff);
281 utp->stats.rx_lbip += utopia_update(utp,
282 SUNI_REGO_RLOPBIP8_24, 3, 0xfffff);
283 utp->stats.rx_lfebe += utopia_update(utp,
284 SUNI_REGO_RLOPFEBE, 3, 0xfffff);
285 utp->stats.rx_pbip += utopia_update(utp,
286 SUNI_REGO_RPOPBIP8, 2, 0xffff);
287 utp->stats.rx_pfebe += utopia_update(utp,
288 SUNI_REGO_RPOPFEBE, 2, 0xffff);
289 utp->stats.rx_corr += utopia_update(utp,
290 SUNI_REGO_RACPCHCS, 1, 0xff);
291 utp->stats.rx_uncorr += utopia_update(utp,
292 SUNI_REGO_RACPUHCS, 1, 0xff);
293 utp->stats.rx_cells += utopia_update(utp,
294 SUNI_REGO_RACPCNT, 3, 0x7ffff);
295 utp->stats.tx_cells += utopia_update(utp,
296 SUNI_REGO_TACPCNT, 3, 0x7ffff);
300 * Handle interrupt on SUNI chip
303 suni_intr_default(struct utopia *utp)
305 uint8_t regs[SUNI_REGO_MTEST];
306 u_int n = SUNI_REGO_MTEST;
309 /* Read all registers. This acks the interrupts */
310 if ((err = UTP_READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) {
311 printf("SUNI read error %d\n", err);
314 if (n <= SUNI_REGO_RSOPSIS) {
315 printf("%s: could not read RSOPSIS", __func__);
318 /* check for LOSI (loss of signal) */
319 if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) &&
320 (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI))
321 utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS]
322 & SUNI_REGM_RSOPSIS_LOSV));
325 const struct utopia_chip utopia_chip_lite = {
327 "Suni/Lite (PMC-5346)",
334 suni_set_loopback_lite,
336 suni_lite_update_stats,
340 * Set loopback mode for the Ultra
343 suni_set_loopback_ultra(struct utopia *utp, u_int mode)
351 if (mode & UTP_LOOP_TIME) {
352 nmode &= ~UTP_LOOP_TIME;
353 val |= SUNI_REGM_MCTRL_LOOPT;
355 if (mode & UTP_LOOP_DIAG) {
356 nmode &= ~UTP_LOOP_DIAG;
357 if (val & SUNI_REGM_MCTRL_LOOPT)
359 val |= SUNI_REGM_MCTRL_SDLE;
361 if (mode & UTP_LOOP_LINE) {
362 nmode &= ~UTP_LOOP_LINE;
363 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
365 val |= SUNI_REGM_MCTRL_LLE;
367 if (mode & UTP_LOOP_PARAL) {
368 nmode &= ~UTP_LOOP_PARAL;
369 val |= SUNI_REGM_MCTRL_PDLE;
371 if (mode & UTP_LOOP_TWIST) {
372 nmode &= ~UTP_LOOP_TWIST;
373 val |= SUNI_REGM_MCTRL_TPLE;
378 err = UTP_WRITEREG(utp, SUNI_REGO_MCTRL,
379 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT |
380 SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val);
383 utp->loopback = mode;
388 const struct utopia_chip utopia_chip_ultra = {
390 "Suni/Ultra (PMC-5350)",
397 suni_set_loopback_ultra,
399 suni_lite_update_stats,
403 * Set loopback mode for the 622
406 suni_set_loopback_622(struct utopia *utp, u_int mode)
417 if (mode & UTP_LOOP_PATH) {
418 nmode &= ~UTP_LOOP_PATH;
419 val |= SUNI_REGM_MCTRLM_DPLE;
422 err = UTP_READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
425 smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) ==
426 SUNI_REGM_MCONFIG_TMODE_STS1_BIT &&
427 (config & SUNI_REGM_MCONFIG_RMODE_622) ==
428 SUNI_REGM_MCONFIG_RMODE_STS1_BIT);
430 if (mode & UTP_LOOP_TIME) {
433 nmode &= ~UTP_LOOP_TIME;
434 val |= SUNI_REGM_MCTRLM_LOOPT;
436 if (mode & UTP_LOOP_DIAG) {
437 nmode &= ~UTP_LOOP_DIAG;
438 if (val & SUNI_REGM_MCTRLM_LOOPT)
440 val |= SUNI_REGM_MCTRLM_DLE;
442 if (mode & UTP_LOOP_LINE) {
443 nmode &= ~UTP_LOOP_LINE;
444 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
446 val |= SUNI_REGM_MCTRLM_LLE;
451 err = UTP_WRITEREG(utp, SUNI_REGO_MCTRLM,
452 SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE |
453 SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val);
456 utp->loopback = mode;
462 * Reset the SUNI chip to reflect the current state of utopia.
465 suni_reset_622(struct utopia *utp)
469 if (!(utp->flags & UTP_FL_NORESET)) {
470 err |= UTP_WRITEREG(utp, SUNI_REGO_MRESET,
471 SUNI_REGM_MRESET_RESET, SUNI_REGM_MRESET_RESET);
472 err |= UTP_WRITEREG(utp, SUNI_REGO_MRESET,
473 SUNI_REGM_MRESET_RESET, 0);
476 /* disable test mode */
477 err |= UTP_WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
478 SUNI_REGM_MTEST_DS27_53_622);
480 err |= suni_set_chip(utp);
482 return (err ? EIO : 0);
486 * Update statistics from a SUNI/622
489 suni_622_update_stats(struct utopia *utp)
493 /* write to the master if we can */
494 if (!(utp->flags & UTP_FL_NORESET)) {
495 err = UTP_WRITEREG(utp, SUNI_REGO_MRESET, 0, 0);
497 err = UTP_WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0);
498 err |= UTP_WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0);
499 err |= UTP_WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0);
500 err |= UTP_WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0);
501 err |= UTP_WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0);
505 printf("%s: register write error %s: %d\n", __func__,
506 utp->chip->name, err);
513 utp->stats.rx_sbip += utopia_update(utp,
514 SUNI_REGO_RSOP_BIP8, 2, 0xffff);
515 utp->stats.rx_lbip += utopia_update(utp,
516 SUNI_REGO_RLOPBIP8_24, 3, 0xfffff);
517 utp->stats.rx_lfebe += utopia_update(utp,
518 SUNI_REGO_RLOPFEBE, 3, 0xfffff);
519 utp->stats.rx_pbip += utopia_update(utp,
520 SUNI_REGO_RPOPBIP8, 2, 0xffff);
521 utp->stats.rx_pfebe += utopia_update(utp,
522 SUNI_REGO_RPOPFEBE, 2, 0xffff);
523 utp->stats.rx_corr += utopia_update(utp,
524 SUNI_REGO_RACPCHCS_622, 2, 0xfff);
525 utp->stats.rx_uncorr += utopia_update(utp,
526 SUNI_REGO_RACPUHCS_622, 2, 0xfff);
527 utp->stats.rx_cells += utopia_update(utp,
528 SUNI_REGO_RACPCNT_622, 3, 0x1fffff);
529 utp->stats.tx_cells += utopia_update(utp,
530 SUNI_REGO_TACPCNT, 3, 0x1fffff);
533 const struct utopia_chip utopia_chip_622 = {
535 "Suni/622 (PMC-5355)",
542 suni_set_loopback_622,
544 suni_622_update_stats,