if_le.c revision 1.29 1 /* $NetBSD: if_le.c,v 1.29 1998/07/05 00:51:06 jonathan Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*-
41 * Copyright (c) 1997 Bernd Ernesti. All rights reserved.
42 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
43 * Copyright (c) 1992, 1993
44 * The Regents of the University of California. All rights reserved.
45 *
46 * This code is derived from software contributed to Berkeley by
47 * Ralph Campbell and Rick Macklem.
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
51 * are met:
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. All advertising materials mentioning features or use of this software
58 * must display the following acknowledgement:
59 * This product includes software developed for the NetBSD Project
60 * by Bernd Ernesti.
61 * This product includes software developed by the University of
62 * California, Berkeley and its contributors.
63 * 4. Neither the name of the University nor the names of its contributors
64 * may be used to endorse or promote products derived from this software
65 * without specific prior written permission.
66 *
67 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
68 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
69 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
70 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
71 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
72 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
73 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
74 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
75 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
76 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
77 * SUCH DAMAGE.
78 *
79 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
80 */
81
82 #include "opt_inet.h"
83 #include "bpfilter.h"
84
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/mbuf.h>
88 #include <sys/syslog.h>
89 #include <sys/socket.h>
90 #include <sys/device.h>
91
92 #include <net/if.h>
93 #include <net/if_ether.h>
94 #include <net/if_media.h>
95
96 #ifdef INET
97 #include <netinet/in.h>
98 #include <netinet/if_inarp.h>
99 #endif
100
101 #include <machine/cpu.h>
102 #include <machine/mtpr.h>
103
104 #include <amiga/amiga/device.h>
105 #include <amiga/amiga/isr.h>
106
107 #include <dev/ic/am7990reg.h>
108 #include <dev/ic/am7990var.h>
109
110 #include <amiga/dev/zbusvar.h>
111 #include <amiga/dev/if_levar.h>
112
113 int le_zbus_match __P((struct device *, struct cfdata *, void *));
114 void le_zbus_attach __P((struct device *, struct device *, void *));
115
116 struct cfattach le_zbus_ca = {
117 sizeof(struct le_softc), le_zbus_match, le_zbus_attach
118 };
119
120 hide void lepcnet_reset __P((struct am7990_softc *));
121 hide void lewrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
122 hide u_int16_t lerdcsr __P((struct am7990_softc *, u_int16_t));
123
124 hide u_int16_t ariadne_swapreg __P((u_int16_t));
125 hide void ariadne_wrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
126 hide u_int16_t ariadne_rdcsr __P((struct am7990_softc *, u_int16_t));
127 hide void ariadne_wribcr __P((struct am7990_softc *, u_int16_t, u_int16_t));
128 integrate void ariadne_copytodesc_word __P((struct am7990_softc *, void *, int, int));
129 integrate void ariadne_copyfromdesc_word __P((struct am7990_softc *, void *, int, int));
130 integrate void ariadne_copytobuf_word __P((struct am7990_softc *, void *, int, int));
131 integrate void ariadne_copyfrombuf_word __P((struct am7990_softc *, void *, int, int));
132 integrate void ariadne_zerobuf_word __P((struct am7990_softc *, int, int));
133 void ariadne_autoselect __P((struct am7990_softc *, int));
134 int ariadne_mediachange __P((struct am7990_softc *));
135 void ariadne_hwinit __P((struct am7990_softc *));
136
137 /*
138 * Media types supported by the Ariadne.
139 */
140 int lemedia_ariadne[] = {
141 IFM_ETHER | IFM_10_T,
142 IFM_ETHER | IFM_10_2,
143 IFM_ETHER | IFM_AUTO,
144 };
145 #define NLEMEDIA_ARIADNE (sizeof(lemedia_ariadne) / sizeof(lemedia_ariadne[0]))
146
147
148 hide u_int16_t
149 ariadne_swapreg(val)
150 u_int16_t val;
151 {
152
153 return (((val & 0xff) << 8 ) | (( val >> 8) & 0xff));
154 }
155
156 hide void
157 ariadne_wrcsr(sc, port, val)
158 struct am7990_softc *sc;
159 u_int16_t port, val;
160 {
161 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
162
163 ler1->ler1_rap = ariadne_swapreg(port);
164 ler1->ler1_rdp = ariadne_swapreg(val);
165 }
166
167 hide u_int16_t
168 ariadne_rdcsr(sc, port)
169 struct am7990_softc *sc;
170 u_int16_t port;
171 {
172 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
173 u_int16_t val;
174
175 ler1->ler1_rap = ariadne_swapreg(port);
176 val = ariadne_swapreg(ler1->ler1_rdp);
177 return (val);
178 }
179
180 hide void
181 ariadne_wribcr(sc, port, val)
182 struct am7990_softc *sc;
183 u_int16_t port, val;
184 {
185 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
186
187 ler1->ler1_rap = ariadne_swapreg(port);
188 ler1->ler1_idp = ariadne_swapreg(val);
189 }
190
191 hide void
192 lewrcsr(sc, port, val)
193 struct am7990_softc *sc;
194 u_int16_t port, val;
195 {
196 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
197
198 ler1->ler1_rap = port;
199 ler1->ler1_rdp = val;
200 }
201
202 hide u_int16_t
203 lerdcsr(sc, port)
204 struct am7990_softc *sc;
205 u_int16_t port;
206 {
207 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
208 u_int16_t val;
209
210 ler1->ler1_rap = port;
211 val = ler1->ler1_rdp;
212 return (val);
213 }
214
215 hide void
216 lepcnet_reset(sc)
217 struct am7990_softc *sc;
218 {
219 struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
220 volatile int dummy;
221
222 dummy = ler1->ler1_reset; /* Reset PCNet-ISA */
223 }
224
225 void
226 ariadne_autoselect(sc, on)
227 struct am7990_softc *sc;
228 int on;
229 {
230
231 /*
232 * on = 0: autoselect disabled
233 * on = 1: autoselect enabled
234 */
235 if (on == 0)
236 ariadne_wribcr(sc, LE_BCR_MC, 0x0000);
237 else
238 ariadne_wribcr(sc, LE_BCR_MC, LE_MC_ASEL);
239 }
240
241 int
242 ariadne_mediachange(sc)
243 struct am7990_softc *sc;
244 {
245 struct ifmedia *ifm = &sc->sc_media;
246
247 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
248 return (EINVAL);
249
250 /*
251 * Switch to the selected media. If autoselect is
252 * set, switch it on otherwise disable it. We'll
253 * switch to the other media when we detect loss of
254 * carrier.
255 */
256 switch (IFM_SUBTYPE(ifm->ifm_media)) {
257 case IFM_10_T:
258 sc->sc_initmodemedia = 1;
259 am7990_init(sc);
260 break;
261
262 case IFM_10_2:
263 sc->sc_initmodemedia = 0;
264 am7990_init(sc);
265 break;
266
267 case IFM_AUTO:
268 sc->sc_initmodemedia = 2;
269 ariadne_hwinit(sc);
270 break;
271
272 default:
273 return (EINVAL);
274 }
275
276 return (0);
277 }
278
279 void
280 ariadne_hwinit(sc)
281 struct am7990_softc *sc;
282 {
283
284 /*
285 * Re-program LEDs to match meaning used on the Ariadne board.
286 */
287 ariadne_wribcr(sc, LE_BCR_LED1, 0x0090);
288 ariadne_wribcr(sc, LE_BCR_LED2, 0x0081);
289 ariadne_wribcr(sc, LE_BCR_LED3, 0x0084);
290
291 /*
292 * Enabel/Disable auto selection
293 */
294 if (sc->sc_initmodemedia == 2)
295 ariadne_autoselect(sc, 1);
296 else
297 ariadne_autoselect(sc, 0);
298 }
299
300 int
301 le_zbus_match(parent, cfp, aux)
302 struct device *parent;
303 struct cfdata *cfp;
304 void *aux;
305 {
306 struct zbus_args *zap = aux;
307
308 /* Commodore ethernet card */
309 if (zap->manid == 514 && zap->prodid == 112)
310 return (1);
311
312 /* Ameristar ethernet card */
313 if (zap->manid == 1053 && zap->prodid == 1)
314 return (1);
315
316 /* Ariadne ethernet card */
317 if (zap->manid == 2167 && zap->prodid == 201)
318 return (1);
319
320 return (0);
321 }
322
323 void
324 le_zbus_attach(parent, self, aux)
325 struct device *parent, *self;
326 void *aux;
327 {
328 struct le_softc *lesc = (struct le_softc *)self;
329 struct am7990_softc *sc = &lesc->sc_am7990;
330 struct zbus_args *zap = aux;
331 u_long ser;
332
333 /* This has no effect on PCnet-ISA LANCE chips */
334 sc->sc_conf3 = LE_C3_BSWP;
335
336 /*
337 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID.
338 */
339 switch (zap->manid) {
340 case 514:
341 /* Commodore */
342 sc->sc_memsize = 32768;
343 sc->sc_enaddr[0] = 0x00;
344 sc->sc_enaddr[1] = 0x80;
345 sc->sc_enaddr[2] = 0x10;
346 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va);
347 sc->sc_mem = (void *)(0x8000 + (int)zap->va);
348 sc->sc_addr = 0x8000;
349 sc->sc_copytodesc = am7990_copytobuf_contig;
350 sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
351 sc->sc_copytobuf = am7990_copytobuf_contig;
352 sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
353 sc->sc_zerobuf = am7990_zerobuf_contig;
354 sc->sc_rdcsr = lerdcsr;
355 sc->sc_wrcsr = lewrcsr;
356 sc->sc_hwreset = NULL;
357 sc->sc_hwinit = NULL;
358 break;
359
360 case 1053:
361 /* Ameristar */
362 sc->sc_memsize = 32768;
363 sc->sc_enaddr[0] = 0x00;
364 sc->sc_enaddr[1] = 0x00;
365 sc->sc_enaddr[2] = 0x9f;
366 lesc->sc_r1 = (struct lereg1 *)(0x4000 + (int)zap->va);
367 sc->sc_mem = (void *)(0x8000 + (int)zap->va);
368 sc->sc_addr = 0x8000;
369 sc->sc_copytodesc = am7990_copytobuf_contig;
370 sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
371 sc->sc_copytobuf = am7990_copytobuf_contig;
372 sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
373 sc->sc_zerobuf = am7990_zerobuf_contig;
374 sc->sc_rdcsr = lerdcsr;
375 sc->sc_wrcsr = lewrcsr;
376 sc->sc_hwreset = NULL;
377 sc->sc_hwinit = NULL;
378 break;
379
380 case 2167:
381 /* Village Tronic */
382 sc->sc_memsize = 32768;
383 sc->sc_enaddr[0] = 0x00;
384 sc->sc_enaddr[1] = 0x60;
385 sc->sc_enaddr[2] = 0x30;
386 lesc->sc_r1 = (struct lereg1 *)(0x0370 + (int)zap->va);
387 sc->sc_mem = (void *)(0x8000 + (int)zap->va);
388 sc->sc_addr = 0x8000;
389 sc->sc_copytodesc = ariadne_copytodesc_word;
390 sc->sc_copyfromdesc = ariadne_copyfromdesc_word;
391 sc->sc_copytobuf = ariadne_copytobuf_word;
392 sc->sc_copyfrombuf = ariadne_copyfrombuf_word;
393 sc->sc_zerobuf = ariadne_zerobuf_word;
394 sc->sc_rdcsr = ariadne_rdcsr;
395 sc->sc_wrcsr = ariadne_wrcsr;
396 sc->sc_hwreset = lepcnet_reset;
397 sc->sc_hwinit = ariadne_hwinit;
398 sc->sc_mediachange = ariadne_mediachange;
399 sc->sc_supmedia = lemedia_ariadne;
400 sc->sc_nsupmedia = NLEMEDIA_ARIADNE;
401 sc->sc_defaultmedia = IFM_ETHER | IFM_AUTO;
402 sc->sc_initmodemedia = 2;
403 break;
404
405 default:
406 panic("le_zbus_attach: bad manid");
407 }
408
409 /*
410 * Serial number for board is used as host ID.
411 */
412 ser = (u_long)zap->serno;
413 sc->sc_enaddr[3] = (ser >> 16) & 0xff;
414 sc->sc_enaddr[4] = (ser >> 8) & 0xff;
415 sc->sc_enaddr[5] = (ser ) & 0xff;
416
417 am7990_config(sc);
418
419 lesc->sc_isr.isr_intr = am7990_intr;
420 lesc->sc_isr.isr_arg = sc;
421 lesc->sc_isr.isr_ipl = 2;
422 add_isr(&lesc->sc_isr);
423 }
424
425
426 integrate void
427 ariadne_copytodesc_word(sc, from, boff, len)
428 struct am7990_softc *sc;
429 void *from;
430 int boff, len;
431 {
432 u_short *b1 = from;
433 volatile u_short *b2 = sc->sc_mem + boff;
434
435 for (len >>= 1; len > 0; len--)
436 *b2++ = ariadne_swapreg(*b1++);
437 }
438
439 integrate void
440 ariadne_copyfromdesc_word(sc, to, boff, len)
441 struct am7990_softc *sc;
442 void *to;
443 int boff, len;
444 {
445 volatile u_short *b1 = sc->sc_mem + boff;
446 u_short *b2 = to;
447
448 for (len >>= 1; len > 0; len--)
449 *b2++ = ariadne_swapreg(*b1++);
450 }
451
452 #define isodd(n) ((n) & 1)
453
454 integrate void
455 ariadne_copytobuf_word(sc, from, boff, len)
456 struct am7990_softc *sc;
457 void *from;
458 int boff, len;
459 {
460 u_char *a1 = from;
461 volatile u_char *a2 = sc->sc_mem + boff;
462 u_short *b1;
463 volatile u_short *b2;
464 int i;
465
466 if (len > 0 && isodd(boff)) {
467 /* adjust source pointer */
468 b1 = (u_short *)(a1 + 1);
469 /* compute aligned destination pointer */
470 b2 = (u_short *)(a2 + 1);
471 /* copy first unaligned byte to buf */
472 b2[-1] = (b2[-1] & 0xff00) | *a1;
473 --len;
474 } else {
475 /* destination is aligned or length is zero */
476 b1 = (u_short *)a1;
477 b2 = (u_short *)a2;
478 }
479
480 /* copy full words with aligned destination */
481 for (i = len >> 1; i > 0; i--)
482 *b2++ = *b1++;
483
484 /* copy remaining byte */
485 if (isodd(len))
486 *b2 = (*b2 & 0x00ff) | (*(u_char *)b1) << 8;
487 }
488
489 integrate void
490 ariadne_copyfrombuf_word(sc, to, boff, len)
491 struct am7990_softc *sc;
492 void *to;
493 int boff, len;
494 {
495 volatile u_char *a1 = sc->sc_mem + boff;
496 u_char *a2 = to;
497 volatile u_short *b1;
498 u_short *b2;
499 int i;
500
501 if (len > 0 && isodd(boff)) {
502 /* compute aligned source pointer */
503 b1 = (u_short *)(a1 + 1);
504 /* adjust destination pointer (possibly unaligned) */
505 b2 = (u_short *)(a2 + 1);
506 /* copy first unaligned byte from buf */
507 *a2 = b1[-1];
508 --len;
509 } else {
510 /* source is aligned or length is zero */
511 b1 = (u_short *)a1;
512 b2 = (u_short *)a2;
513 }
514
515 /* copy full words with aligned source */
516 for (i = len >> 1; i > 0; i--)
517 *b2++ = *b1++;
518
519 /* copy remaining byte */
520 if (isodd(len))
521 *(u_char *)b2 = *b1 >> 8;
522 }
523
524 integrate void
525 ariadne_zerobuf_word(sc, boff, len)
526 struct am7990_softc *sc;
527 int boff, len;
528 {
529 volatile u_char *a1 = sc->sc_mem + boff;
530 volatile u_short *b1;
531 int i;
532
533 if (len > 0 && isodd(boff)) {
534 b1 = (u_short *)(a1 + 1);
535 b1[-1] &= 0xff00;
536 --len;
537 } else {
538 b1 = (u_short *)a1;
539 }
540
541 for (i = len >> 1; i > 0; i--)
542 *b1++ = 0;
543
544 if (isodd(len))
545 *b1 &= 0x00ff;
546 }
547