]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/utopia/idtphy.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / utopia / idtphy.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/idtphy.h>
53 #include <dev/utopia/utopia.h>
54 #include <dev/utopia/utopia_priv.h>
55
56 /*
57  * Reset IDT77105. There is really no way to reset this thing by acessing
58  * the registers. Load the registers with default values.
59  */
60 static int
61 idt77105_reset(struct utopia *utp)
62 {
63         int err = 0;
64         u_int n;
65         uint8_t val[2];
66
67         err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, 0xff,
68             IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI);
69         n = 1;
70         err |= UTP_READREGS(utp, IDTPHY_REGO_ISTAT, val, &n);
71         err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0);
72         err |= UTP_WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0);
73
74         err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC);
75         n = 2;
76         err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
77
78         err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX);
79         n = 2;
80         err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
81
82         err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX);
83         n = 2;
84         err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
85
86         err |= UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE);
87         n = 2;
88         err |= UTP_READREGS(utp, IDTPHY_REGO_CNT, val, &n);
89
90         err |= UTP_WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC,
91             IDTPHY_REGM_MCR_DREC);
92         err |= UTP_WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH,
93             IDTPHY_REGM_DIAG_RFLUSH);
94
95         /* loopback */
96         err |= utopia_set_loopback(utp, utp->loopback);
97
98         /* update carrier state */
99         err |= utopia_update_carrier(utp);
100
101         return (err ? EIO : 0);
102 }
103
104 static int
105 idt77105_inval(struct utopia *utp, int what __unused)
106 {
107
108         return (EINVAL);
109 }
110
111 static int
112 idt77105_update_carrier(struct utopia *utp)
113 {
114         int err;
115         uint8_t reg;
116         u_int n = 1;
117
118         if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
119                 utp->carrier = UTP_CARR_UNKNOWN;
120                 return (err);
121         }
122         utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
123         return (0);
124 }
125
126 static int
127 idt77105_set_loopback(struct utopia *utp, u_int mode)
128 {
129         int err;
130
131         switch (mode) {
132           case UTP_LOOP_NONE:
133                 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
134                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE);
135                 break;
136
137           case UTP_LOOP_DIAG:
138                 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
139                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY);
140                 break;
141
142           case UTP_LOOP_LINE:
143                 err = UTP_WRITEREG(utp, IDTPHY_REGO_DIAG,
144                     IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE);
145                 break;
146
147           default:
148                 return (EINVAL);
149         }
150         if (err)
151                 return (err);
152         utp->loopback = mode;
153         return (0);
154 }
155
156 /*
157  * Handle interrupt on IDT77105 chip
158  */
159 static void
160 idt77105_intr(struct utopia *utp)
161 {
162         uint8_t reg;
163         u_int n = 1;
164         int err;
165
166         /* Interrupt status and ack the interrupt */
167         if ((err = UTP_READREGS(utp, IDTPHY_REGO_ISTAT, &reg, &n)) != 0) {
168                 printf("IDT77105 read error %d\n", err);
169                 return;
170         }
171         /* check for signal condition */
172         utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD);
173 }
174
175 static void
176 idt77105_update_stats(struct utopia *utp)
177 {
178         int err = 0;
179         uint8_t regs[2];
180         u_int n;
181
182 #ifdef DIAGNOSTIC
183 #define UDIAG(F,A,B)    printf(F, A, B)
184 #else
185 #define UDIAG(F,A,B)    do { } while (0)
186 #endif
187
188 #define UPD(FIELD, CODE, N, MASK)                                       \
189         err = UTP_WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE);          \
190         if (err != 0) {                                                 \
191                 UDIAG("%s: cannot write CNTS: %d\n", __func__, err);    \
192                 return;                                                 \
193         }                                                               \
194         n = N;                                                          \
195         err = UTP_READREGS(utp, IDTPHY_REGO_CNT, regs, &n);             \
196         if (err != 0) {                                                 \
197                 UDIAG("%s: cannot read CNT: %d\n", __func__, err);      \
198                 return;                                                 \
199         }                                                               \
200         if (n != N) {                                                   \
201                 UDIAG("%s: got only %u registers\n", __func__, n);      \
202                 return;                                                 \
203         }                                                               \
204         if (N == 1)                                                     \
205                 utp->stats.FIELD += (regs[0] & MASK);                   \
206         else                                                            \
207                 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK;
208
209         UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff);
210         UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff);
211         UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff);
212         UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f);
213
214 #undef  UDIAG
215 #undef  UPD
216 }
217
218 struct utopia_chip utopia_chip_idt77105 = {
219         UTP_TYPE_IDT77105,
220         "IDT77105",
221         7,
222         idt77105_reset,
223         idt77105_inval,
224         idt77105_inval,
225         idt77105_inval,
226         idt77105_update_carrier,
227         idt77105_set_loopback,
228         idt77105_intr,
229         idt77105_update_stats,
230 };
231
232 /*
233  * Update the carrier status
234  */
235 static int
236 idt77155_update_carrier(struct utopia *utp)
237 {
238         int err;
239         uint8_t reg;
240         u_int n = 1;
241
242         if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
243                 utp->carrier = UTP_CARR_UNKNOWN;
244                 return (err);
245         }
246         utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
247         return (0);
248 }
249
250 /*
251  * Handle interrupt on IDT77155 chip
252  */
253 static void
254 idt77155_intr(struct utopia *utp)
255 {
256         uint8_t reg;
257         u_int n = 1;
258         int err;
259
260         if ((err = UTP_READREGS(utp, IDTPHY_REGO_RSOS, &reg, &n)) != 0) {
261                 printf("IDT77105 read error %d\n", err);
262                 return;
263         }
264         utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS));
265 }
266
267 /*
268  * set SONET/SDH mode
269  */
270 static int
271 idt77155_set_sdh(struct utopia *utp, int sdh)
272 {
273         int err;
274
275         if (sdh)
276                 err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM,
277                     IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH);
278         else
279                 err = UTP_WRITEREG(utp, IDTPHY_REGO_PTRM,
280                     IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET);
281         if (err != 0)
282                 return (err);
283
284         utp->state &= ~UTP_ST_SDH;
285         if (sdh)
286                 utp->state |= UTP_ST_SDH;
287
288         return (0);
289 }
290
291 /*
292  * set idle/unassigned cells
293  */
294 static int
295 idt77155_set_unass(struct utopia *utp, int unass)
296 {
297         int err;
298
299         if (unass)
300                 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0);
301         else
302                 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1);
303         if (err != 0)
304                 return (err);
305
306         utp->state &= ~UTP_ST_UNASS;
307         if (unass)
308                 utp->state |= UTP_ST_UNASS;
309
310         return (0);
311 }
312
313 /*
314  * enable/disable scrambling
315  */
316 static int
317 idt77155_set_noscramb(struct utopia *utp, int noscramb)
318 {
319         int err;
320
321         if (noscramb) {
322                 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC,
323                     IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR);
324                 if (err)
325                         return (err);
326                 err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC,
327                     IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR);
328                 if (err)
329                         return (err);
330                 utp->state |= UTP_ST_NOSCRAMB;
331         } else {
332                 err = UTP_WRITEREG(utp, IDTPHY_REGO_TCC,
333                     IDTPHY_REGM_TCC_DSCR, 0);
334                 if (err)
335                         return (err);
336                 err = UTP_WRITEREG(utp, IDTPHY_REGO_RCC,
337                     IDTPHY_REGM_RCC_DSCR, 0);
338                 if (err)
339                         return (err);
340                 utp->state &= ~UTP_ST_NOSCRAMB;
341         }
342         return (0);
343 }
344
345 /*
346  * Set loopback mode for the 77155
347  */
348 static int
349 idt77155_set_loopback(struct utopia *utp, u_int mode)
350 {
351         int err;
352         uint32_t val;
353         u_int nmode;
354
355         val = 0;
356         nmode = mode;
357         if (mode & UTP_LOOP_TIME) {
358                 nmode &= ~UTP_LOOP_TIME;
359                 val |= IDTPHY_REGM_MCTL_TLOOP;
360         }
361         if (mode & UTP_LOOP_DIAG) {
362                 nmode &= ~UTP_LOOP_DIAG;
363                 val |= IDTPHY_REGM_MCTL_DLOOP;
364         }
365         if (mode & UTP_LOOP_LINE) {
366                 nmode &= ~UTP_LOOP_LINE;
367                 val |= IDTPHY_REGM_MCTL_LLOOP;
368         }
369         if (nmode != 0)
370                 return (EINVAL);
371
372         err = UTP_WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP |
373             IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val);
374         if (err)
375                 return (err);
376         utp->loopback = mode;
377
378         return (0);
379 }
380
381 /*
382  * Set the chip to reflect the current state in utopia.
383  * Assume, that the chip has been reset.
384  */
385 static int
386 idt77155_set_chip(struct utopia *utp)
387 {
388         int err = 0;
389
390         /* set sonet/sdh */
391         err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH);
392
393         /* unassigned or idle cells */
394         err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS);
395
396         /* loopback */
397         err |= idt77155_set_loopback(utp, utp->loopback);
398
399         /* update carrier state */
400         err |= idt77155_update_carrier(utp);
401
402         /* enable interrupts on LOS */
403         err |= UTP_WRITEREG(utp, IDTPHY_REGO_INT,
404             IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI);
405         err |= UTP_WRITEREG(utp, IDTPHY_REGO_RSOC,
406             IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI);
407
408         return (err ? EIO : 0);
409 }
410
411 /*
412  * Reset the chip to reflect the current state of utopia.
413  */
414 static int
415 idt77155_reset(struct utopia *utp)
416 {
417         int err = 0;
418
419         if (!(utp->flags & UTP_FL_NORESET)) {
420                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID,
421                     IDTPHY_REGM_MRID_RESET, IDTPHY_REGM_MRID_RESET);
422                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_MRID,
423                     IDTPHY_REGM_MRID_RESET, 0);
424         }
425
426         err |= idt77155_set_chip(utp);
427
428         return (err ? EIO : 0);
429 }
430
431 /*
432  * Update statistics from a IDT77155
433  * This appears to be the same as for the Suni/Lite and Ultra. IDT however
434  * makes no assessment about the transfer time. Assume 7us.
435  */
436 static void
437 idt77155_update_stats(struct utopia *utp)
438 {
439         int err;
440
441         /* write to the master if we can */
442         if (!(utp->flags & UTP_FL_NORESET)) {
443                 err = UTP_WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0);
444         } else {
445                 err = UTP_WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0);
446                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0);
447                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0);
448                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0);
449                 err |= UTP_WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0);
450
451         }
452         if (err) {
453 #ifdef DIAGNOSTIC
454                 printf("%s: register write error %s: %d\n", __func__,
455                     utp->chip->name, err);
456 #endif
457                 return;
458         }
459
460         DELAY(8);
461
462         utp->stats.rx_sbip += utopia_update(utp,
463             IDTPHY_REGO_BIPC, 2, 0xffff);
464         utp->stats.rx_lbip += utopia_update(utp,
465             IDTPHY_REGO_B2EC, 3, 0xfffff);
466         utp->stats.rx_lfebe += utopia_update(utp,
467             IDTPHY_REGO_FEBEC, 3, 0xfffff);
468         utp->stats.rx_pbip += utopia_update(utp,
469             IDTPHY_REGO_B3EC, 2, 0xffff);
470         utp->stats.rx_pfebe += utopia_update(utp,
471             IDTPHY_REGO_PFEBEC, 2, 0xffff);
472         utp->stats.rx_corr += utopia_update(utp,
473             IDTPHY_REGO_CEC, 1, 0xff);
474         utp->stats.rx_uncorr += utopia_update(utp,
475             IDTPHY_REGO_UEC, 1, 0xff);
476         utp->stats.rx_cells += utopia_update(utp,
477             IDTPHY_REGO_RCCNT, 3, 0x7ffff);
478         utp->stats.tx_cells += utopia_update(utp,
479             IDTPHY_REGO_TXCNT, 3, 0x7ffff);
480 }
481
482 const struct utopia_chip utopia_chip_idt77155 = {
483         UTP_TYPE_IDT77155,
484         "IDT77155",
485         0x80,
486         idt77155_reset,
487         idt77155_set_sdh,
488         idt77155_set_unass,
489         idt77155_set_noscramb,
490         idt77155_update_carrier,
491         idt77155_set_loopback,
492         idt77155_intr,
493         idt77155_update_stats,
494 };