if_le_isa.c revision 1.10 1 /* $NetBSD: if_le_isa.c,v 1.10 1997/03/17 03:19:09 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Ralph Campbell and Rick Macklem.
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 University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
40 */
41
42 #include "bpfilter.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/mbuf.h>
47 #include <sys/syslog.h>
48 #include <sys/socket.h>
49 #include <sys/device.h>
50
51 #include <net/if.h>
52 #include <net/if_ether.h>
53 #include <net/if_media.h>
54
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <netinet/if_inarp.h>
58 #endif
59
60 #include <vm/vm.h>
61
62 #include <machine/cpu.h>
63 #include <machine/intr.h>
64 #include <machine/bus.h>
65
66 #include <dev/isa/isareg.h>
67 #include <dev/isa/isavar.h>
68 #include <dev/isa/isadmavar.h>
69
70 #include <dev/ic/am7990reg.h>
71 #include <dev/ic/am7990var.h>
72
73 #include <dev/isa/if_levar.h>
74
75 static char *card_type[] =
76 { "unknown", "BICC Isolan", "NE2100", "DEPCA", "PCnet-ISA" };
77
78 int le_isa_probe __P((struct device *, void *, void *));
79 void le_isa_attach __P((struct device *, struct device *, void *));
80
81 struct cfattach le_isa_ca = {
82 sizeof(struct le_softc), le_isa_probe, le_isa_attach
83 };
84
85 int depca_isa_probe __P((struct le_softc *, struct isa_attach_args *));
86 int ne2100_isa_probe __P((struct le_softc *, struct isa_attach_args *));
87 int bicc_isa_probe __P((struct le_softc *, struct isa_attach_args *));
88 int lance_isa_probe __P((struct am7990_softc *));
89
90 int le_isa_intredge __P((void *));
91
92 hide void le_isa_wrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
93 hide u_int16_t le_isa_rdcsr __P((struct am7990_softc *, u_int16_t));
94
95 void depca_copytobuf __P((struct am7990_softc *, void *, int, int));
96 void depca_copyfrombuf __P((struct am7990_softc *, void *, int, int));
97 void depca_zerobuf __P((struct am7990_softc *, int, int));
98
99 hide void
100 le_isa_wrcsr(sc, port, val)
101 struct am7990_softc *sc;
102 u_int16_t port, val;
103 {
104 struct le_softc *lesc = (struct le_softc *)sc;
105 bus_space_tag_t iot = lesc->sc_iot;
106 bus_space_handle_t ioh = lesc->sc_ioh;
107
108 bus_space_write_2(iot, ioh, lesc->sc_rap, port);
109 bus_space_write_2(iot, ioh, lesc->sc_rdp, val);
110 }
111
112 hide u_int16_t
113 le_isa_rdcsr(sc, port)
114 struct am7990_softc *sc;
115 u_int16_t port;
116 {
117 struct le_softc *lesc = (struct le_softc *)sc;
118 bus_space_tag_t iot = lesc->sc_iot;
119 bus_space_handle_t ioh = lesc->sc_ioh;
120 u_int16_t val;
121
122 bus_space_write_2(iot, ioh, lesc->sc_rap, port);
123 val = bus_space_read_2(iot, ioh, lesc->sc_rdp);
124 return (val);
125 }
126
127 int
128 le_isa_probe(parent, match, aux)
129 struct device *parent;
130 void *match, *aux;
131 {
132 struct le_softc *lesc = match;
133 struct isa_attach_args *ia = aux;
134
135 if (bicc_isa_probe(lesc, ia))
136 return (1);
137 if (ne2100_isa_probe(lesc, ia))
138 return (1);
139 if (depca_isa_probe(lesc, ia))
140 return (1);
141
142 return (0);
143 }
144
145 int
146 depca_isa_probe(lesc, ia)
147 struct le_softc *lesc;
148 struct isa_attach_args *ia;
149 {
150 struct am7990_softc *sc = &lesc->sc_am7990;
151 int iobase = ia->ia_iobase, port;
152 bus_space_tag_t iot = ia->ia_iot;
153 bus_space_handle_t ioh;
154 bus_space_handle_t memh;
155 #if 0
156 u_int32_t sum, rom_sum;
157 u_int8_t x;
158 #endif
159 int i;
160
161 /* Map i/o space. */
162 if (bus_space_map(iot, iobase, 16, 0, &ioh))
163 return 0;
164
165 if (ia->ia_maddr == MADDRUNK || ia->ia_msize == -1)
166 goto bad;
167
168 /* Map card RAM. */
169 if (bus_space_map(ia->ia_memt, ia->ia_maddr, ia->ia_msize,
170 0, &memh))
171 goto bad;
172
173 /* Just needed to check mapability; don't need it anymore. */
174 bus_space_unmap(ia->ia_memt, memh, ia->ia_msize);
175
176 lesc->sc_iot = iot;
177 lesc->sc_ioh = ioh;
178 lesc->sc_rap = DEPCA_RAP;
179 lesc->sc_rdp = DEPCA_RDP;
180 lesc->sc_card = DEPCA;
181
182 if (lance_isa_probe(sc) == 0)
183 goto bad;
184
185 bus_space_write_1(iot, ioh, DEPCA_CSR, DEPCA_CSR_DUM);
186
187 /*
188 * Extract the physical MAC address from the ROM.
189 *
190 * The address PROM is 32 bytes wide, and we access it through
191 * a single I/O port. On each read, it rotates to the next
192 * position. We find the ethernet address by looking for a
193 * particular sequence of bytes (0xff, 0x00, 0x55, 0xaa, 0xff,
194 * 0x00, 0x55, 0xaa), and then reading the next 8 bytes (the
195 * ethernet address and a checksum).
196 *
197 * It appears that the PROM can be at one of two locations, so
198 * we just try both.
199 */
200 port = DEPCA_ADP;
201 for (i = 0; i < 32; i++)
202 if (bus_space_read_1(iot, ioh, port) == 0xff &&
203 bus_space_read_1(iot, ioh, port) == 0x00 &&
204 bus_space_read_1(iot, ioh, port) == 0x55 &&
205 bus_space_read_1(iot, ioh, port) == 0xaa &&
206 bus_space_read_1(iot, ioh, port) == 0xff &&
207 bus_space_read_1(iot, ioh, port) == 0x00 &&
208 bus_space_read_1(iot, ioh, port) == 0x55 &&
209 bus_space_read_1(iot, ioh, port) == 0xaa)
210 goto found;
211 port = DEPCA_ADP + 1;
212 for (i = 0; i < 32; i++)
213 if (bus_space_read_1(iot, ioh, port) == 0xff &&
214 bus_space_read_1(iot, ioh, port) == 0x00 &&
215 bus_space_read_1(iot, ioh, port) == 0x55 &&
216 bus_space_read_1(iot, ioh, port) == 0xaa &&
217 bus_space_read_1(iot, ioh, port) == 0xff &&
218 bus_space_read_1(iot, ioh, port) == 0x00 &&
219 bus_space_read_1(iot, ioh, port) == 0x55 &&
220 bus_space_read_1(iot, ioh, port) == 0xaa)
221 goto found;
222 printf("%s: address not found\n", sc->sc_dev.dv_xname);
223 goto bad;
224
225 found:
226 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
227 sc->sc_enaddr[i] = bus_space_read_1(iot, ioh, port);
228
229 #if 0
230 sum =
231 (sc->sc_enaddr[0] << 2) +
232 (sc->sc_enaddr[1] << 10) +
233 (sc->sc_enaddr[2] << 1) +
234 (sc->sc_enaddr[3] << 9) +
235 (sc->sc_enaddr[4] << 0) +
236 (sc->sc_enaddr[5] << 8);
237 sum = (sum & 0xffff) + (sum >> 16);
238 sum = (sum & 0xffff) + (sum >> 16);
239
240 rom_sum = bus_space_read_1(iot, ioh, port);
241 rom_sum |= bus_space_read_1(iot, ioh, port) << 8;
242
243 if (sum != rom_sum) {
244 printf("%s: checksum mismatch; calculated %04x != read %04x",
245 sc->sc_dev.dv_xname, sum, rom_sum);
246 goto bad;
247 }
248 #endif
249
250 bus_space_write_1(iot, ioh, DEPCA_CSR, DEPCA_CSR_NORMAL);
251
252 /*
253 * XXX INDIRECT BROKENNESS!
254 * XXX Should always unmap, and re-map in if_le_isa_attach().
255 */
256
257 ia->ia_iosize = 16;
258 ia->ia_drq = DRQUNK;
259 return 1;
260
261 bad:
262 bus_space_unmap(iot, ioh, 16);
263 return 0;
264 }
265
266 int
267 ne2100_isa_probe(lesc, ia)
268 struct le_softc *lesc;
269 struct isa_attach_args *ia;
270 {
271 struct am7990_softc *sc = &lesc->sc_am7990;
272 int iobase = ia->ia_iobase;
273 bus_space_tag_t iot = ia->ia_iot;
274 bus_space_handle_t ioh;
275 int i;
276
277 /* Map i/o space. */
278 if (bus_space_map(iot, iobase, 24, 0, &ioh))
279 return 0;
280
281 lesc->sc_iot = iot;
282 lesc->sc_ioh = ioh;
283 lesc->sc_rap = NE2100_RAP;
284 lesc->sc_rdp = NE2100_RDP;
285 lesc->sc_card = NE2100;
286
287 if (lance_isa_probe(sc) == 0) {
288 bus_space_unmap(iot, ioh, 24);
289 return 0;
290 }
291
292 /*
293 * Extract the physical MAC address from the ROM.
294 */
295 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
296 sc->sc_enaddr[i] = bus_space_read_1(iot, ioh, i);
297
298 /*
299 * XXX INDIRECT BROKENNESS!
300 * XXX Should always unmap, and re-map in if_le_isa_attach().
301 */
302
303 ia->ia_iosize = 24;
304 return 1;
305 }
306
307 int
308 bicc_isa_probe(lesc, ia)
309 struct le_softc *lesc;
310 struct isa_attach_args *ia;
311 {
312 struct am7990_softc *sc = &lesc->sc_am7990;
313 int iobase = ia->ia_iobase;
314 bus_space_tag_t iot = ia->ia_iot;
315 bus_space_handle_t ioh;
316 int i;
317
318 /* Map i/o space. */
319 if (bus_space_map(iot, iobase, 16, 0, &ioh))
320 return 0;
321
322 lesc->sc_iot = iot;
323 lesc->sc_ioh = ioh;
324 lesc->sc_rap = BICC_RAP;
325 lesc->sc_rdp = BICC_RDP;
326 lesc->sc_card = BICC;
327
328 if (lance_isa_probe(sc) == 0) {
329 bus_space_unmap(iot, ioh, 16);
330 return 0;
331 }
332
333 /*
334 * Extract the physical MAC address from the ROM.
335 */
336 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
337 sc->sc_enaddr[i] = bus_space_read_1(iot, ioh, i * 2);
338
339 /*
340 * XXX INDIRECT BROKENNESS!
341 * XXX Should always unmap, and re-map in if_le_isa_attach().
342 */
343
344 ia->ia_iosize = 16;
345 return 1;
346 }
347
348 /*
349 * Determine which chip is present on the card.
350 */
351 int
352 lance_isa_probe(sc)
353 struct am7990_softc *sc;
354 {
355
356 /* Stop the LANCE chip and put it in a known state. */
357 le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
358 delay(100);
359
360 if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP)
361 return 0;
362
363 le_isa_wrcsr(sc, LE_CSR3, sc->sc_conf3);
364 return 1;
365 }
366
367 void
368 le_isa_attach(parent, self, aux)
369 struct device *parent, *self;
370 void *aux;
371 {
372 struct le_softc *lesc = (void *)self;
373 struct am7990_softc *sc = &lesc->sc_am7990;
374 struct isa_attach_args *ia = aux;
375 bus_space_tag_t iot = ia->ia_iot;
376 bus_space_tag_t memt = ia->ia_memt;
377 bus_space_handle_t memh;
378
379 printf(": %s Ethernet\n", card_type[lesc->sc_card]);
380
381 lesc->sc_iot = iot;
382 lesc->sc_memt = memt;
383
384 /* XXX SHOULD RE-MAP I/O SPACE HERE. */
385
386 if (lesc->sc_card == DEPCA) {
387 u_char val;
388 int i;
389
390 /* Map shared memory. */
391 if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize,
392 0, &memh))
393 panic("le_isa_attach: can't map shared memory");
394
395 lesc->sc_memh = memh;
396
397 val = 0xff;
398 for (;;) {
399 #if 0 /* XXX !! */
400 bus_space_set_region_1(memt, memh, 0, val);
401 #else
402 for (i = 0; i < ia->ia_msize; i++)
403 bus_space_write_1(memt, memh, i, val);
404 #endif
405 for (i = 0; i < ia->ia_msize; i++)
406 if (bus_space_read_1(memt, memh, 1) != val) {
407 printf("%s: failed to clear memory\n",
408 sc->sc_dev.dv_xname);
409 return;
410 }
411 if (val == 0x00)
412 break;
413 val -= 0x55;
414 }
415
416 sc->sc_conf3 = LE_C3_ACON;
417 sc->sc_mem = 0; /* Not used. */
418 sc->sc_addr = 0;
419 sc->sc_memsize = ia->ia_msize;
420 } else {
421 sc->sc_mem = malloc(16384, M_DEVBUF, M_NOWAIT);
422 if (sc->sc_mem == 0) {
423 printf("%s: couldn't allocate memory for card\n",
424 sc->sc_dev.dv_xname);
425 return;
426 }
427
428 sc->sc_conf3 = 0;
429 sc->sc_addr = kvtop(sc->sc_mem); /* XXX !! */
430 sc->sc_memsize = 16384;
431 }
432
433 if (lesc->sc_card == DEPCA) {
434 sc->sc_copytodesc = depca_copytobuf;
435 sc->sc_copyfromdesc = depca_copyfrombuf;
436 sc->sc_copytobuf = depca_copytobuf;
437 sc->sc_copyfrombuf = depca_copyfrombuf;
438 sc->sc_zerobuf = depca_zerobuf;
439 } else {
440 sc->sc_copytodesc = am7990_copytobuf_contig;
441 sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
442 sc->sc_copytobuf = am7990_copytobuf_contig;
443 sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
444 sc->sc_zerobuf = am7990_zerobuf_contig;
445 }
446
447 sc->sc_rdcsr = le_isa_rdcsr;
448 sc->sc_wrcsr = le_isa_wrcsr;
449 sc->sc_hwinit = NULL;
450
451 printf("%s", sc->sc_dev.dv_xname);
452 am7990_config(sc);
453
454 if (ia->ia_drq != DRQUNK)
455 isa_dmacascade(ia->ia_drq);
456
457 lesc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
458 IPL_NET, le_isa_intredge, sc);
459 }
460
461 /*
462 * Controller interrupt.
463 */
464 int
465 le_isa_intredge(arg)
466 void *arg;
467 {
468
469 if (am7990_intr(arg) == 0)
470 return (0);
471 for (;;)
472 if (am7990_intr(arg) == 0)
473 return (1);
474 }
475
476 /*
477 * DEPCA shared memory access functions.
478 */
479
480 void
481 depca_copytobuf(sc, from, boff, len)
482 struct am7990_softc *sc;
483 void *from;
484 int boff, len;
485 {
486 struct le_softc *lesc = (struct le_softc *)sc;
487
488 bus_space_write_region_1(lesc->sc_memt, lesc->sc_memh, boff,
489 from, len);
490 }
491
492 void
493 depca_copyfrombuf(sc, to, boff, len)
494 struct am7990_softc *sc;
495 void *to;
496 int boff, len;
497 {
498 struct le_softc *lesc = (struct le_softc *)sc;
499
500 bus_space_read_region_1(lesc->sc_memt, lesc->sc_memh, boff,
501 to, len);
502 }
503
504 void
505 depca_zerobuf(sc, boff, len)
506 struct am7990_softc *sc;
507 int boff, len;
508 {
509 struct le_softc *lesc = (struct le_softc *)sc;
510
511 #if 0 /* XXX !! */
512 bus_space_set_region_1(lesc->sc_memt, lesc->sc_memh, boff,
513 0x00, len);
514 #else
515 for (; len != 0; boff++, len--)
516 bus_space_write_1(lesc->sc_memt, lesc->sc_memh, boff, 0x00);
517 #endif
518 }
519