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/idtphy.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/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, ®, &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, ®, &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, ®, &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, ®, &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 };
Cache object: 2330826cc02fc47cbd12c3f2f10580a7
|