FreeBSD/Linux Kernel Cross Reference
sys/dev/utopia/suni.c
1 /*-
2 * Copyright (c) 2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Author: Hartmut Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: releng/9.0/sys/dev/utopia/suni.c 142384 2005-02-24 16:56:36Z harti $");
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/utopia.h>
54 #include <dev/utopia/utopia_priv.h>
55
56 /*
57 * set SONET/SDH mode
58 */
59 static int
60 suni_set_sdh(struct utopia *utp, int sdh)
61 {
62 int err;
63
64 if (sdh)
65 err = UTP_WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
66 SUNI_REGM_TPOPAPTR_S,
67 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S);
68 else
69 err = UTP_WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1,
70 SUNI_REGM_TPOPAPTR_S,
71 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S);
72 if (err != 0)
73 return (err);
74
75 utp->state &= ~UTP_ST_SDH;
76 if (sdh)
77 utp->state |= UTP_ST_SDH;
78
79 return (0);
80 }
81
82 /*
83 * set idle/unassigned cells
84 */
85 static int
86 suni_set_unass(struct utopia *utp, int unass)
87 {
88 int err;
89
90 if (unass)
91 err = UTP_WRITEREG(utp, SUNI_REGO_TACPIDLEH,
92 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP));
93 else
94 err = UTP_WRITEREG(utp, SUNI_REGO_TACPIDLEH,
95 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP));
96 if (err != 0)
97 return (err);
98
99 utp->state &= ~UTP_ST_UNASS;
100 if (unass)
101 utp->state |= UTP_ST_UNASS;
102
103 return (0);
104 }
105
106 /*
107 * enable/disable scrambling
108 */
109 static int
110 suni_set_noscramb(struct utopia *utp, int noscramb)
111 {
112 int err;
113
114 if (noscramb) {
115 err = UTP_WRITEREG(utp, SUNI_REGO_TACPCTRL,
116 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR);
117 if (err)
118 return (err);
119 err = UTP_WRITEREG(utp, SUNI_REGO_RACPCTRL,
120 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR);
121 if (err)
122 return (err);
123 utp->state |= UTP_ST_NOSCRAMB;
124 } else {
125 err = UTP_WRITEREG(utp, SUNI_REGO_TACPCTRL,
126 SUNI_REGM_TACPCTRL_DSCR, 0);
127 if (err)
128 return (err);
129 err = UTP_WRITEREG(utp, SUNI_REGO_RACPCTRL,
130 SUNI_REGM_RACPCTRL_DDSCR, 0);
131 if (err)
132 return (err);
133 utp->state &= ~UTP_ST_NOSCRAMB;
134 }
135 return (0);
136 }
137
138 /*
139 * Get current carrier state
140 */
141 static int
142 suni_update_carrier(struct utopia *utp)
143 {
144 int err;
145 uint8_t reg;
146 u_int n = 1;
147
148 if ((err = UTP_READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) {
149 utp->carrier = UTP_CARR_UNKNOWN;
150 return (err);
151 }
152 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV));
153 return (0);
154 }
155
156 /*
157 * Set the SUNI chip to reflect the current state in utopia.
158 * Assume, that the chip has been reset.
159 */
160 static int
161 suni_set_chip(struct utopia *utp)
162 {
163 int err = 0;
164
165 /* set sonet/sdh */
166 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH);
167
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);
171
172 /* set scrambling */
173 err |= utopia_set_noscramb(utp, utp->state & UTP_ST_NOSCRAMB);
174
175 /* loopback */
176 err |= utopia_set_loopback(utp, utp->loopback);
177
178 /* update carrier state */
179 err |= utopia_update_carrier(utp);
180
181 /* enable interrupts on LOS */
182 err |= UTP_WRITEREG(utp, SUNI_REGO_RSOPCIE,
183 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE);
184
185 return (err ? EIO : 0);
186 }
187
188 /*
189 * Reset the SUNI chip to reflect the current state of utopia.
190 */
191 static int
192 suni_reset_default(struct utopia *utp)
193 {
194 int err = 0;
195
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);
201 }
202
203 /* disable test mode */
204 err |= UTP_WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00);
205
206 err |= suni_set_chip(utp);
207
208 return (err ? EIO : 0);
209 }
210
211 /*
212 * Set loopback mode for the Lite
213 */
214 static int
215 suni_set_loopback_lite(struct utopia *utp, u_int mode)
216 {
217 int err;
218 uint32_t val;
219 u_int nmode;
220
221 val = 0;
222 nmode = mode;
223 if (mode & UTP_LOOP_TIME) {
224 nmode &= ~UTP_LOOP_TIME;
225 val |= SUNI_REGM_MCTRL_LOOPT;
226 }
227 if (mode & UTP_LOOP_DIAG) {
228 nmode &= ~UTP_LOOP_DIAG;
229 val |= SUNI_REGM_MCTRL_DLE;
230 }
231 if (mode & UTP_LOOP_LINE) {
232 nmode &= ~UTP_LOOP_LINE;
233 if (val & SUNI_REGM_MCTRL_DLE)
234 return (EINVAL);
235 val |= SUNI_REGM_MCTRL_LLE;
236 }
237 if (nmode != 0)
238 return (EINVAL);
239
240 err = UTP_WRITEREG(utp, SUNI_REGO_MCTRL,
241 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT,
242 val);
243 if (err)
244 return (err);
245 utp->loopback = mode;
246
247 return (0);
248 }
249
250 /*
251 * Update statistics from a SUNI/LITE or SUNI/ULTRA
252 */
253 static void
254 suni_lite_update_stats(struct utopia *utp)
255 {
256 int err;
257
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);
261 } else {
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);
267
268 }
269 if (err) {
270 #ifdef DIAGNOSTIC
271 printf("%s: register write error %s: %d\n", __func__,
272 utp->chip->name, err);
273 #endif
274 return;
275 }
276
277 DELAY(8);
278
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);
297 }
298
299 /*
300 * Handle interrupt on SUNI chip
301 */
302 static void
303 suni_intr_default(struct utopia *utp)
304 {
305 uint8_t regs[SUNI_REGO_MTEST];
306 u_int n = SUNI_REGO_MTEST;
307 int err;
308
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);
312 return;
313 }
314 if (n <= SUNI_REGO_RSOPSIS) {
315 printf("%s: could not read RSOPSIS", __func__);
316 return;
317 }
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));
323 }
324
325 const struct utopia_chip utopia_chip_lite = {
326 UTP_TYPE_SUNI_LITE,
327 "Suni/Lite (PMC-5346)",
328 256,
329 suni_reset_default,
330 suni_set_sdh,
331 suni_set_unass,
332 suni_set_noscramb,
333 suni_update_carrier,
334 suni_set_loopback_lite,
335 suni_intr_default,
336 suni_lite_update_stats,
337 };
338
339 /*
340 * Set loopback mode for the Ultra
341 */
342 static int
343 suni_set_loopback_ultra(struct utopia *utp, u_int mode)
344 {
345 int err;
346 uint32_t val;
347 u_int nmode;
348
349 val = 0;
350 nmode = mode;
351 if (mode & UTP_LOOP_TIME) {
352 nmode &= ~UTP_LOOP_TIME;
353 val |= SUNI_REGM_MCTRL_LOOPT;
354 }
355 if (mode & UTP_LOOP_DIAG) {
356 nmode &= ~UTP_LOOP_DIAG;
357 if (val & SUNI_REGM_MCTRL_LOOPT)
358 return (EINVAL);
359 val |= SUNI_REGM_MCTRL_SDLE;
360 }
361 if (mode & UTP_LOOP_LINE) {
362 nmode &= ~UTP_LOOP_LINE;
363 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE))
364 return (EINVAL);
365 val |= SUNI_REGM_MCTRL_LLE;
366 }
367 if (mode & UTP_LOOP_PARAL) {
368 nmode &= ~UTP_LOOP_PARAL;
369 val |= SUNI_REGM_MCTRL_PDLE;
370 }
371 if (mode & UTP_LOOP_TWIST) {
372 nmode &= ~UTP_LOOP_TWIST;
373 val |= SUNI_REGM_MCTRL_TPLE;
374 }
375 if (nmode != 0)
376 return (EINVAL);
377
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);
381 if (err)
382 return (err);
383 utp->loopback = mode;
384
385 return (0);
386 }
387
388 const struct utopia_chip utopia_chip_ultra = {
389 UTP_TYPE_SUNI_ULTRA,
390 "Suni/Ultra (PMC-5350)",
391 256,
392 suni_reset_default,
393 suni_set_sdh,
394 suni_set_unass,
395 suni_set_noscramb,
396 suni_update_carrier,
397 suni_set_loopback_ultra,
398 suni_intr_default,
399 suni_lite_update_stats,
400 };
401
402 /*
403 * Set loopback mode for the 622
404 */
405 static int
406 suni_set_loopback_622(struct utopia *utp, u_int mode)
407 {
408 int err;
409 uint32_t val;
410 uint8_t config;
411 int smode;
412 u_int nmode;
413 u_int n = 1;
414
415 val = 0;
416 nmode = mode;
417 if (mode & UTP_LOOP_PATH) {
418 nmode &= ~UTP_LOOP_PATH;
419 val |= SUNI_REGM_MCTRLM_DPLE;
420 }
421
422 err = UTP_READREGS(utp, SUNI_REGO_MCONFIG, &config, &n);
423 if (err != 0)
424 return (err);
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);
429
430 if (mode & UTP_LOOP_TIME) {
431 if (!smode)
432 return (EINVAL);
433 nmode &= ~UTP_LOOP_TIME;
434 val |= SUNI_REGM_MCTRLM_LOOPT;
435 }
436 if (mode & UTP_LOOP_DIAG) {
437 nmode &= ~UTP_LOOP_DIAG;
438 if (val & SUNI_REGM_MCTRLM_LOOPT)
439 return (EINVAL);
440 val |= SUNI_REGM_MCTRLM_DLE;
441 }
442 if (mode & UTP_LOOP_LINE) {
443 nmode &= ~UTP_LOOP_LINE;
444 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE))
445 return (EINVAL);
446 val |= SUNI_REGM_MCTRLM_LLE;
447 }
448 if (nmode != 0)
449 return (EINVAL);
450
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);
454 if (err)
455 return (err);
456 utp->loopback = mode;
457
458 return (0);
459 }
460
461 /*
462 * Reset the SUNI chip to reflect the current state of utopia.
463 */
464 static int
465 suni_reset_622(struct utopia *utp)
466 {
467 int err = 0;
468
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);
474 }
475
476 /* disable test mode */
477 err |= UTP_WRITEREG(utp, SUNI_REGO_MTEST, 0xff,
478 SUNI_REGM_MTEST_DS27_53_622);
479
480 err |= suni_set_chip(utp);
481
482 return (err ? EIO : 0);
483 }
484
485 /*
486 * Update statistics from a SUNI/622
487 */
488 static void
489 suni_622_update_stats(struct utopia *utp)
490 {
491 int err;
492
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);
496 } else {
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);
502 }
503 if (err) {
504 #ifdef DIAGNOSTIC
505 printf("%s: register write error %s: %d\n", __func__,
506 utp->chip->name, err);
507 #endif
508 return;
509 }
510
511 DELAY(8);
512
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);
531 }
532
533 const struct utopia_chip utopia_chip_622 = {
534 UTP_TYPE_SUNI_622,
535 "Suni/622 (PMC-5355)",
536 256,
537 suni_reset_622,
538 suni_set_sdh,
539 suni_set_unass,
540 suni_set_noscramb,
541 suni_update_carrier,
542 suni_set_loopback_622,
543 suni_intr_default,
544 suni_622_update_stats,
545 };
Cache object: e50c3c3ca1ba4e75682ab0685c0dd8e6
|