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