]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/utopia/suni.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / 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$");
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, &reg, &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 };