1 /* $OpenBSD: if_we.c,v 1.12 2004/05/12 06:35:11 tedu Exp $ */
2 /* $NetBSD: if_we.c,v 1.11 1998/07/05 06:49:14 jonathan Exp $ */
3
4 /*-
5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
43 * adapters.
44 *
45 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
46 *
47 * Copyright (C) 1993, David Greenman. This software may be used, modified,
48 * copied, distributed, and sold, in both source and binary form provided that
49 * the above copyright and these terms are retained. Under no circumstances is
50 * the author responsible for the proper functioning of this software, nor does
51 * the author assume any responsibility for damages incurred with its use.
52 */
53
54 /*
55 * Device driver for the Western Digital/SMC 8003 and 8013 series,
56 * and the SMC Elite Ultra (8216).
57 */
58
59 #include "bpfilter.h"
60 #include "we.h"
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/device.h>
65 #include <sys/socket.h>
66 #include <sys/mbuf.h>
67 #include <sys/syslog.h>
68
69 #include <net/if.h>
70 #include <net/if_dl.h>
71 #include <net/if_types.h>
72 #include <net/if_media.h>
73
74 #ifdef __NetBSD__
75 #include <net/if_ether.h>
76 #endif
77
78 #ifdef INET
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/in_var.h>
82 #include <netinet/ip.h>
83 #ifdef __NetBSD__
84 #include <netinet/if_inarp.h>
85 #else
86 #include <netinet/if_ether.h>
87 #endif
88 #endif
89
90 #ifdef NS
91 #include <netns/ns.h>
92 #include <netns/ns_if.h>
93 #endif
94
95 #if NBPFILTER > 0
96 #include <net/bpf.h>
97 #endif
98
99 #include <machine/bus.h>
100 #include <machine/intr.h>
101
102 #include <dev/isa/isareg.h>
103 #include <dev/isa/isavar.h>
104
105 #include <dev/ic/dp8390reg.h>
106 #include <dev/ic/dp8390var.h>
107
108 #include <dev/isa/if_wereg.h>
109
110 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
111 #define bus_space_read_region_stream_2 bus_space_read_region_2
112 #define bus_space_write_stream_2 bus_space_write_2
113 #define bus_space_write_region_stream_2 bus_space_write_region_2
114 #endif
115
116 struct we_softc {
117 struct dp8390_softc sc_dp8390;
118
119 bus_space_tag_t sc_asict; /* space tag for ASIC */
120 bus_space_handle_t sc_asich; /* space handle for ASIC */
121
122 u_int8_t sc_laar_proto;
123 u_int8_t sc_msr_proto;
124
125 u_int8_t sc_type; /* our type */
126
127 int sc_16bitp; /* are we 16 bit? */
128
129 void *sc_ih; /* interrupt handle */
130 };
131
132 int we_probe(struct device *, void *, void *);
133 void we_attach(struct device *, struct device *, void *);
134
135 struct cfattach we_isa_ca = {
136 sizeof(struct we_softc), we_probe, we_attach
137 };
138
139 #if NWE_ISAPNP
140 struct cfattach we_isapnp_ca = {
141 sizeof(struct we_softc), we_probe, we_attach
142 };
143 #endif /* NWE_ISAPNP */
144
145 #ifdef __NetBSD__
146 extern struct cfdriver we_cd;
147 #else
148 struct cfdriver we_cd = {
149 NULL, "we", DV_IFNET
150 };
151 #endif
152
153 const char *we_params(bus_space_tag_t, bus_space_handle_t, u_int8_t *,
154 bus_size_t *, int *, int *);
155 void we_set_media(struct we_softc *, int);
156
157 void we_media_init(struct dp8390_softc *);
158
159 int we_mediachange(struct dp8390_softc *);
160 void we_mediastatus(struct dp8390_softc *, struct ifmediareq *);
161
162 void we_recv_int(struct dp8390_softc *);
163 void we_init_card(struct dp8390_softc *);
164 int we_write_mbuf(struct dp8390_softc *, struct mbuf *, int);
165 int we_ring_copy(struct dp8390_softc *, int, caddr_t, u_short);
166 void we_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *);
167 int we_test_mem(struct dp8390_softc *);
168
169 __inline void we_readmem(struct we_softc *, int, u_int8_t *, int);
170
171 static const int we_584_irq[] = {
172 9, 3, 5, 7, 10, 11, 15, 4,
173 };
174 #define NWE_584_IRQ (sizeof(we_584_irq) / sizeof(we_584_irq[0]))
175
176 static const int we_790_irq[] = {
177 IRQUNK, 9, 3, 5, 7, 10, 11, 15,
178 };
179 #define NWE_790_IRQ (sizeof(we_790_irq) / sizeof(we_790_irq[0]))
180
181 /*
182 * Delay needed when switching 16-bit access to shared memory.
183 */
184 #define WE_DELAY(wsc) delay(3)
185
186 /*
187 * Enable card RAM, and 16-bit access.
188 */
189 #define WE_MEM_ENABLE(wsc) \
190 do { \
191 if ((wsc)->sc_16bitp) \
192 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
193 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
194 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
195 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
196 WE_DELAY((wsc)); \
197 } while (0)
198
199 /*
200 * Disable card RAM, and 16-bit access.
201 */
202 #define WE_MEM_DISABLE(wsc) \
203 do { \
204 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
205 WE_MSR, (wsc)->sc_msr_proto); \
206 if ((wsc)->sc_16bitp) \
207 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
208 WE_LAAR, (wsc)->sc_laar_proto); \
209 WE_DELAY((wsc)); \
210 } while (0)
211
212 int
we_probe(parent,match,aux)213 we_probe(parent, match, aux)
214 struct device *parent;
215 void *match, *aux;
216 {
217 struct isa_attach_args *ia = aux;
218 struct cfdata *cf = match;
219 bus_space_tag_t asict, memt;
220 bus_space_handle_t asich, memh;
221 bus_size_t memsize;
222 int asich_valid, memh_valid;
223 int i, is790, rv = 0;
224 u_int8_t x, type;
225
226 asict = ia->ia_iot;
227 memt = ia->ia_memt;
228
229 asich_valid = memh_valid = 0;
230
231 /* Disallow wildcarded i/o addresses. */
232 if (ia->ia_iobase == -1 /* ISACF_PORT_DEFAULT */)
233 return (0);
234
235 /* Disallow wildcarded mem address. */
236 if (ia->ia_maddr == -1 /* ISACF_IOMEM_DEFAULT */)
237 return (0);
238
239 /* Attempt to map the device. */
240 if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp") && ia->ia_ioh)
241 asich = ia->ia_ioh;
242 else {
243 if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich))
244 goto out;
245 asich_valid = 1;
246 }
247
248 #ifdef TOSH_ETHER
249 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_POW);
250 #endif
251
252 /*
253 * Attempt to do a checksum over the station address PROM.
254 * If it fails, it's probably not a WD/SMC board. There is
255 * a problem with this, though. Some clone WD8003E boards
256 * (e.g. Danpex) won't pass the checksum. In this case,
257 * the checksum byte always seems to be 0.
258 */
259 for (x = 0, i = 0; i < 8; i++)
260 x += bus_space_read_1(asict, asich, WE_PROM + i);
261
262 if (x != WE_ROM_CHECKSUM_TOTAL) {
263 /* Make sure it's an 8003E clone... */
264 if (bus_space_read_1(asict, asich, WE_CARD_ID) !=
265 WE_TYPE_WD8003E)
266 goto out;
267
268 /* Check the checksum byte. */
269 if (bus_space_read_1(asict, asich, WE_PROM + 7) != 0)
270 goto out;
271 }
272
273 /*
274 * Reset the card to force it into a known state.
275 */
276 #ifdef TOSH_ETHER
277 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST | WE_MSR_POW);
278 #else
279 bus_space_write_1(asict, asich, WE_MSR, WE_MSR_RST);
280 #endif
281 delay(100);
282
283 bus_space_write_1(asict, asich, WE_MSR,
284 bus_space_read_1(asict, asich, WE_MSR) & ~WE_MSR_RST);
285
286 /* Wait in case the card is reading it's EEPROM. */
287 delay(5000);
288
289 /*
290 * Get parameters.
291 */
292 if (we_params(asict, asich, &type, &memsize, NULL, &is790) == NULL)
293 goto out;
294
295 /* Allow user to override probed value. */
296 if (ia->ia_msize)
297 memsize = ia->ia_msize;
298
299 /* Attempt to map the memory space. */
300 if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp") && ia->ia_memh)
301 memh = ia->ia_memh;
302 else {
303 if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh))
304 goto out;
305 memh_valid = 1;
306 }
307
308 /*
309 * If possible, get the assigned interrupt number from the card
310 * and use it.
311 */
312 if (is790) {
313 u_int8_t hwr;
314
315 /* Assemble together the encoded interrupt number. */
316 hwr = bus_space_read_1(asict, asich, WE790_HWR);
317 bus_space_write_1(asict, asich, WE790_HWR,
318 hwr | WE790_HWR_SWH);
319
320 x = bus_space_read_1(asict, asich, WE790_GCR);
321 i = ((x & WE790_GCR_IR2) >> 4) |
322 ((x & (WE790_GCR_IR1|WE790_GCR_IR0)) >> 2);
323 bus_space_write_1(asict, asich, WE790_HWR,
324 hwr & ~WE790_HWR_SWH);
325
326 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_790_irq[i])
327 printf("%s%d: changing IRQ %d to %d\n",
328 we_cd.cd_name, cf->cf_unit, ia->ia_irq,
329 we_790_irq[i]);
330 ia->ia_irq = we_790_irq[i];
331 } else if (type & WE_SOFTCONFIG) {
332 /* Assemble together the encoded interrupt number. */
333 i = (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_IR2) |
334 ((bus_space_read_1(asict, asich, WE_IRR) &
335 (WE_IRR_IR0 | WE_IRR_IR1)) >> 5);
336
337 if (ia->ia_irq != IRQUNK && ia->ia_irq != we_584_irq[i])
338 printf("%s%d: changing IRQ %d to %d\n",
339 we_cd.cd_name, cf->cf_unit, ia->ia_irq,
340 we_584_irq[i]);
341 ia->ia_irq = we_584_irq[i];
342 }
343
344 /* So, we say we've found it! */
345 ia->ia_iosize = WE_NPORTS;
346 ia->ia_msize = memsize;
347 rv = 1;
348
349 out:
350 if (asich_valid)
351 bus_space_unmap(asict, asich, WE_NPORTS);
352 if (memh_valid)
353 bus_space_unmap(memt, memh, memsize);
354 return (rv);
355 }
356
357 void
we_attach(parent,self,aux)358 we_attach(parent, self, aux)
359 struct device *parent, *self;
360 void *aux;
361 {
362 struct we_softc *wsc = (struct we_softc *)self;
363 struct dp8390_softc *sc = &wsc->sc_dp8390;
364 struct isa_attach_args *ia = aux;
365 bus_space_tag_t nict, asict, memt;
366 bus_space_handle_t nich, asich, memh;
367 const char *typestr;
368 u_int8_t x;
369 int i;
370
371 nict = asict = ia->ia_iot;
372 memt = ia->ia_memt;
373
374 /* Map the device. */
375 if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp") && ia->ia_ioh)
376 asich = ia->ia_ioh;
377 else if (bus_space_map(asict, ia->ia_iobase, WE_NPORTS, 0, &asich)) {
378 printf(": can't map nic i/o space\n");
379 return;
380 }
381
382 if (bus_space_subregion(asict, asich, WE_NIC_OFFSET, WE_NIC_NPORTS,
383 &nich)) {
384 printf(": can't subregion i/o space\n");
385 return;
386 }
387
388 typestr = we_params(asict, asich, &wsc->sc_type, NULL,
389 &wsc->sc_16bitp, &sc->is790);
390 if (typestr == NULL) {
391 printf(": where did the card go?\n");
392 return;
393 }
394
395 /*
396 * Map memory space. Note we use the size that might have
397 * been overridden by the user.
398 */
399 if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp") && ia->ia_memh)
400 memh = ia->ia_memh;
401 else if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) {
402 printf(": can't map shared memory\n");
403 return;
404 }
405
406 /*
407 * Allow user to override 16-bit mode. 8-bit takes precedence.
408 */
409 if (self->dv_cfdata->cf_flags & WE_FLAGS_FORCE_16BIT_MODE)
410 wsc->sc_16bitp = 1;
411 if (self->dv_cfdata->cf_flags & WE_FLAGS_FORCE_8BIT_MODE)
412 wsc->sc_16bitp = 0;
413
414 wsc->sc_asict = asict;
415 wsc->sc_asich = asich;
416
417 sc->sc_regt = nict;
418 sc->sc_regh = nich;
419
420 sc->sc_buft = memt;
421 sc->sc_bufh = memh;
422
423 /* Interface is always enabled. */
424 sc->sc_enabled = 1;
425
426 /* Registers are linear. */
427 for (i = 0; i < 16; i++)
428 sc->sc_reg_map[i] = i;
429
430 /* Now we can use the NIC_{GET,PUT}() macros. */
431
432 printf(": %s (%s-bit)\n", typestr, wsc->sc_16bitp ? "16" : "8");
433
434 /* Get station address from EEPROM. */
435 for (i = 0; i < ETHER_ADDR_LEN; i++)
436 #ifdef __NetBSD__
437 sc->sc_enaddr[i] = bus_space_read_1(asict, asich, WE_PROM + i);
438 #else
439 sc->sc_arpcom.ac_enaddr[i] =
440 bus_space_read_1(asict, asich, WE_PROM + i);
441 #endif
442
443 /*
444 * Set upper address bits and 8/16 bit access to shared memory.
445 */
446 if (sc->is790) {
447 wsc->sc_laar_proto =
448 bus_space_read_1(asict, asich, WE_LAAR) &
449 ~WE_LAAR_M16EN;
450 bus_space_write_1(asict, asich, WE_LAAR,
451 wsc->sc_laar_proto | (wsc->sc_16bitp ? WE_LAAR_M16EN : 0));
452 } else if ((wsc->sc_type & WE_SOFTCONFIG) ||
453 #ifdef TOSH_ETHER
454 (wsc->sc_type == WE_TYPE_TOSHIBA1) ||
455 (wsc->sc_type == WE_TYPE_TOSHIBA4) ||
456 #endif
457 (wsc->sc_type == WE_TYPE_WD8013EBT)) {
458 wsc->sc_laar_proto = (ia->ia_maddr >> 19) & WE_LAAR_ADDRHI;
459 if (wsc->sc_16bitp)
460 wsc->sc_laar_proto |= WE_LAAR_L16EN;
461 bus_space_write_1(asict, asich, WE_LAAR,
462 wsc->sc_laar_proto | (wsc->sc_16bitp ? WE_LAAR_M16EN : 0));
463 }
464
465 /*
466 * Set address and enable interface shared memory.
467 */
468 if (sc->is790) {
469 /* XXX MAGIC CONSTANTS XXX */
470 x = bus_space_read_1(asict, asich, 0x04);
471 bus_space_write_1(asict, asich, 0x04, x | 0x80);
472 bus_space_write_1(asict, asich, 0x0b,
473 ((ia->ia_maddr >> 13) & 0x0f) |
474 ((ia->ia_maddr >> 11) & 0x40) |
475 (bus_space_read_1(asict, asich, 0x0b) & 0xb0));
476 bus_space_write_1(asict, asich, 0x04, x);
477 wsc->sc_msr_proto = 0x00;
478 sc->cr_proto = 0x00;
479 } else {
480 #ifdef TOSH_ETHER
481 if (wsc->sc_type == WE_TYPE_TOSHIBA1 ||
482 wsc->sc_type == WE_TYPE_TOSHIBA4) {
483 bus_space_write_1(asict, asich, WE_MSR + 1,
484 ((ia->ia_maddr >> 8) & 0xe0) | 0x04);
485 bus_space_write_1(asict, asich, WE_MSR + 2,
486 ((ia->ia_maddr >> 16) & 0x0f));
487 wsc->sc_msr_proto = WE_MSR_POW;
488 } else
489 #endif
490 wsc->sc_msr_proto = (ia->ia_maddr >> 13) &
491 WE_MSR_ADDR;
492
493 sc->cr_proto = ED_CR_RD2;
494 }
495
496 bus_space_write_1(asict, asich, WE_MSR,
497 wsc->sc_msr_proto | WE_MSR_MENB);
498 WE_DELAY(wsc);
499
500 /*
501 * DCR gets:
502 *
503 * FIFO threshold to 8, No auto-init Remote DMA,
504 * byte order=80x86.
505 *
506 * 16-bit cards also get word-wide DMA transfers.
507 */
508 sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS |
509 (wsc->sc_16bitp ? ED_DCR_WTS : 0);
510
511 sc->test_mem = we_test_mem;
512 sc->ring_copy = we_ring_copy;
513 sc->write_mbuf = we_write_mbuf;
514 sc->read_hdr = we_read_hdr;
515 sc->recv_int = we_recv_int;
516
517 sc->sc_mediachange = we_mediachange;
518 sc->sc_mediastatus = we_mediastatus;
519
520 sc->mem_start = 0;
521 sc->mem_size = ia->ia_msize;
522
523 sc->sc_flags = self->dv_cfdata->cf_flags;
524
525 /* Do generic parts of attach. */
526 if (wsc->sc_type & WE_SOFTCONFIG)
527 sc->sc_media_init = we_media_init;
528 else
529 sc->sc_media_init = dp8390_media_init;
530 if (dp8390_config(sc)) {
531 printf("%s: configuration failed\n", sc->sc_dev.dv_xname);
532 return;
533 }
534
535 /*
536 * Disable 16-bit access to shared memory - we leave it disabled
537 * so that:
538 *
539 * (1) machines reboot properly when the board is set to
540 * 16-bit mode and there are conflicting 8-bit devices
541 * within the same 128k address space as this board's
542 * shared memory, and
543 *
544 * (2) so that other 8-bit devices with shared memory
545 * in this same 128k address space will work.
546 */
547 WE_MEM_DISABLE(wsc);
548
549 /*
550 * Enable the configured interrupt.
551 */
552 if (sc->is790)
553 bus_space_write_1(asict, asich, WE790_ICR,
554 bus_space_read_1(asict, asich, WE790_ICR) |
555 WE790_ICR_EIL);
556 else if (wsc->sc_type & WE_SOFTCONFIG)
557 bus_space_write_1(asict, asich, WE_IRR,
558 bus_space_read_1(asict, asich, WE_IRR) | WE_IRR_IEN);
559 else if (ia->ia_irq == IRQUNK) {
560 printf("%s: can't wildcard IRQ on a %s\n",
561 sc->sc_dev.dv_xname, typestr);
562 return;
563 }
564
565 /* Establish interrupt handler. */
566 wsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
567 IPL_NET, dp8390_intr, sc, sc->sc_dev.dv_xname);
568 if (wsc->sc_ih == NULL)
569 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
570 }
571
572 int
we_test_mem(sc)573 we_test_mem(sc)
574 struct dp8390_softc *sc;
575 {
576 struct we_softc *wsc = (struct we_softc *)sc;
577 bus_space_tag_t memt = sc->sc_buft;
578 bus_space_handle_t memh = sc->sc_bufh;
579 bus_size_t memsize = sc->mem_size;
580 int i;
581
582 if (wsc->sc_16bitp)
583 bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1);
584 else
585 bus_space_set_region_1(memt, memh, 0, 0, memsize);
586
587 if (wsc->sc_16bitp) {
588 for (i = 0; i < memsize; i += 2) {
589 if (bus_space_read_2(memt, memh, i) != 0)
590 goto fail;
591 }
592 } else {
593 for (i = 0; i < memsize; i++) {
594 if (bus_space_read_1(memt, memh, i) != 0)
595 goto fail;
596 }
597 }
598
599 return (0);
600
601 fail:
602 printf("%s: failed to clear shared memory at offset 0x%x\n",
603 sc->sc_dev.dv_xname, i);
604 WE_MEM_DISABLE(wsc);
605 return (1);
606 }
607
608 /*
609 * Given a NIC memory source address and a host memory destination address,
610 * copy 'len' from NIC to host using shared memory. The 'len' is rounded
611 * up to a word - ok as long as mbufs are word-sized.
612 */
613 __inline void
we_readmem(wsc,from,to,len)614 we_readmem(wsc, from, to, len)
615 struct we_softc *wsc;
616 int from;
617 u_int8_t *to;
618 int len;
619 {
620 bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
621 bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
622
623 if (len & 1)
624 ++len;
625
626 if (wsc->sc_16bitp)
627 bus_space_read_region_stream_2(memt, memh, from,
628 (u_int16_t *)to, len >> 1);
629 else
630 bus_space_read_region_1(memt, memh, from,
631 to, len);
632 }
633
634 int
we_write_mbuf(sc,m,buf)635 we_write_mbuf(sc, m, buf)
636 struct dp8390_softc *sc;
637 struct mbuf *m;
638 int buf;
639 {
640 struct we_softc *wsc = (struct we_softc *)sc;
641 bus_space_tag_t memt = wsc->sc_dp8390.sc_buft;
642 bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh;
643 u_int8_t *data, savebyte[2];
644 int savelen, len, leftover;
645 #ifdef DIAGNOSTIC
646 u_int8_t *lim;
647 #endif
648
649 savelen = m->m_pkthdr.len;
650
651 WE_MEM_ENABLE(wsc);
652
653 /*
654 * 8-bit boards are simple; no alignment tricks are necessary.
655 */
656 if (wsc->sc_16bitp == 0) {
657 for (; m != NULL; buf += m->m_len, m = m->m_next)
658 bus_space_write_region_1(memt, memh,
659 buf, mtod(m, u_int8_t *), m->m_len);
660 goto out;
661 }
662
663 /* Start out with no leftover data. */
664 leftover = 0;
665 savebyte[0] = savebyte[1] = 0;
666
667 for (; m != NULL; m = m->m_next) {
668 len = m->m_len;
669 if (len == 0)
670 continue;
671 data = mtod(m, u_int8_t *);
672 #ifdef DIAGNOSTIC
673 lim = data + len;
674 #endif
675 while (len > 0) {
676 if (leftover) {
677 /*
678 * Data left over (from mbuf or realignment).
679 * Buffer the next byte, and write it and
680 * the leftover data out.
681 */
682 savebyte[1] = *data++;
683 len--;
684 bus_space_write_stream_2(memt, memh, buf,
685 *(u_int16_t *)savebyte);
686 buf += 2;
687 leftover = 0;
688 #ifdef alpha
689 #define ALIGNED_POINTER(p,t) ((((u_long)(p)) & (sizeof(t)-1)) == 0)
690 #endif
691 } else if (ALIGNED_POINTER(data, u_int16_t) == 0) {
692 /*
693 * Unaligned dta; buffer the next byte.
694 */
695 savebyte[0] = *data++;
696 len--;
697 leftover = 1;
698 } else {
699 /*
700 * Aligned data; output contiguous words as
701 * much as we can, then buffer the remaining
702 * byte, if any.
703 */
704 leftover = len & 1;
705 len &= ~1;
706 bus_space_write_region_stream_2(memt, memh,
707 buf, (u_int16_t *)data, len >> 1);
708 data += len;
709 buf += len;
710 if (leftover)
711 savebyte[0] = *data++;
712 len = 0;
713 }
714 }
715 if (len < 0)
716 panic("we_write_mbuf: negative len");
717 #ifdef DIAGNOSTIC
718 if (data != lim)
719 panic("we_write_mbuf: data != lim");
720 #endif
721 }
722 if (leftover) {
723 savebyte[1] = 0;
724 bus_space_write_stream_2(memt, memh, buf,
725 *(u_int16_t *)savebyte);
726 }
727
728 out:
729 WE_MEM_DISABLE(wsc);
730
731 return (savelen);
732 }
733
734 int
we_ring_copy(sc,src,dst,amount)735 we_ring_copy(sc, src, dst, amount)
736 struct dp8390_softc *sc;
737 int src;
738 caddr_t dst;
739 u_short amount;
740 {
741 struct we_softc *wsc = (struct we_softc *)sc;
742 u_short tmp_amount;
743
744 /* Does copy wrap to lower addr in ring buffer? */
745 if (src + amount > sc->mem_end) {
746 tmp_amount = sc->mem_end - src;
747
748 /* Copy amount up to end of NIC memory. */
749 we_readmem(wsc, src, dst, tmp_amount);
750
751 amount -= tmp_amount;
752 src = sc->mem_ring;
753 dst += tmp_amount;
754 }
755
756 we_readmem(wsc, src, dst, amount);
757
758 return (src + amount);
759 }
760
761 void
we_read_hdr(sc,packet_ptr,packet_hdrp)762 we_read_hdr(sc, packet_ptr, packet_hdrp)
763 struct dp8390_softc *sc;
764 int packet_ptr;
765 struct dp8390_ring *packet_hdrp;
766 {
767 struct we_softc *wsc = (struct we_softc *)sc;
768
769 we_readmem(wsc, packet_ptr, (u_int8_t *)packet_hdrp,
770 sizeof(struct dp8390_ring));
771 #if BYTE_ORDER == BIG_ENDIAN
772 packet_hdrp->count = swap16(packet_hdrp->count);
773 #endif
774 }
775
776 void
we_recv_int(sc)777 we_recv_int(sc)
778 struct dp8390_softc *sc;
779 {
780 struct we_softc *wsc = (struct we_softc *)sc;
781
782 WE_MEM_ENABLE(wsc);
783 dp8390_rint(sc);
784 WE_MEM_DISABLE(wsc);
785 }
786
787 void
we_media_init(struct dp8390_softc * sc)788 we_media_init(struct dp8390_softc *sc)
789 {
790 struct we_softc *wsc = (void *)sc;
791 int defmedia = IFM_ETHER;
792 u_int8_t x;
793
794 if (sc->is790) {
795 x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR);
796 bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR,
797 x | WE790_HWR_SWH);
798 if (bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_GCR) &
799 WE790_GCR_GPOUT)
800 defmedia |= IFM_10_2;
801 else
802 defmedia |= IFM_10_5;
803 bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR,
804 x &~ WE790_HWR_SWH);
805 } else {
806 x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
807 if (x & WE_IRR_OUT2)
808 defmedia |= IFM_10_2;
809 else
810 defmedia |= IFM_10_5;
811 }
812
813 ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
814 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_2, 0, NULL);
815 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_5, 0, NULL);
816 ifmedia_set(&sc->sc_media, defmedia);
817 }
818
819 int
we_mediachange(sc)820 we_mediachange(sc)
821 struct dp8390_softc *sc;
822 {
823
824 /*
825 * Current media is already set up. Just reset the interface
826 * to let the new value take hold. The new media will be
827 * set up in we_init_card() called via dp8390_init().
828 */
829 dp8390_reset(sc);
830 return (0);
831 }
832
833 void
we_mediastatus(sc,ifmr)834 we_mediastatus(sc, ifmr)
835 struct dp8390_softc *sc;
836 struct ifmediareq *ifmr;
837 {
838 struct ifmedia *ifm = &sc->sc_media;
839
840 /*
841 * The currently selected media is always the active media.
842 */
843 ifmr->ifm_active = ifm->ifm_cur->ifm_media;
844 }
845
846 void
we_init_card(sc)847 we_init_card(sc)
848 struct dp8390_softc *sc;
849 {
850 struct we_softc *wsc = (struct we_softc *)sc;
851 struct ifmedia *ifm = &sc->sc_media;
852
853 we_set_media(wsc, ifm->ifm_cur->ifm_media);
854 }
855
856 void
we_set_media(wsc,media)857 we_set_media(wsc, media)
858 struct we_softc *wsc;
859 int media;
860 {
861 struct dp8390_softc *sc = &wsc->sc_dp8390;
862 bus_space_tag_t asict = wsc->sc_asict;
863 bus_space_handle_t asich = wsc->sc_asich;
864 u_int8_t hwr, gcr, irr;
865
866 if (sc->is790) {
867 hwr = bus_space_read_1(asict, asich, WE790_HWR);
868 bus_space_write_1(asict, asich, WE790_HWR,
869 hwr | WE790_HWR_SWH);
870 gcr = bus_space_read_1(asict, asich, WE790_GCR);
871 if (IFM_SUBTYPE(media) == IFM_10_2)
872 gcr |= WE790_GCR_GPOUT;
873 else
874 gcr &= ~WE790_GCR_GPOUT;
875 bus_space_write_1(asict, asich, WE790_GCR,
876 gcr | WE790_GCR_LIT);
877 bus_space_write_1(asict, asich, WE790_HWR,
878 hwr & ~WE790_HWR_SWH);
879 return;
880 }
881
882 irr = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
883 if (IFM_SUBTYPE(media) == IFM_10_2)
884 irr |= WE_IRR_OUT2;
885 else
886 irr &= ~WE_IRR_OUT2;
887 bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_IRR, irr);
888 }
889
890 const char *
we_params(asict,asich,typep,memsizep,is16bitp,is790p)891 we_params(asict, asich, typep, memsizep, is16bitp, is790p)
892 bus_space_tag_t asict;
893 bus_space_handle_t asich;
894 u_int8_t *typep;
895 bus_size_t *memsizep;
896 int *is16bitp, *is790p;
897 {
898 const char *typestr;
899 bus_size_t memsize;
900 int is16bit, is790;
901 u_int8_t type;
902
903 memsize = 8192;
904 is16bit = is790 = 0;
905
906 type = bus_space_read_1(asict, asich, WE_CARD_ID);
907 switch (type) {
908 case WE_TYPE_WD8003S:
909 typestr = "WD8003S";
910 break;
911 case WE_TYPE_WD8003E:
912 typestr = "WD8003E";
913 break;
914 case WE_TYPE_WD8003EB:
915 typestr = "WD8003EB";
916 break;
917 case WE_TYPE_WD8003W:
918 typestr = "WD8003W";
919 break;
920 case WE_TYPE_WD8013EBT:
921 typestr = "WD8013EBT";
922 memsize = 16384;
923 is16bit = 1;
924 break;
925 case WE_TYPE_WD8013W:
926 typestr = "WD8013W";
927 memsize = 16384;
928 is16bit = 1;
929 break;
930 case WE_TYPE_WD8013EP: /* also WD8003EP */
931 if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) {
932 is16bit = 1;
933 memsize = 16384;
934 typestr = "WD8013EP";
935 } else
936 typestr = "WD8003EP";
937 break;
938 case WE_TYPE_WD8013WC:
939 typestr = "WD8013WC";
940 memsize = 16384;
941 is16bit = 1;
942 break;
943 case WE_TYPE_WD8013EBP:
944 typestr = "WD8013EBP";
945 memsize = 16384;
946 is16bit = 1;
947 break;
948 case WE_TYPE_WD8013EPC:
949 typestr = "WD8013EPC";
950 memsize = 16384;
951 is16bit = 1;
952 break;
953 case WE_TYPE_SMC8216C:
954 case WE_TYPE_SMC8216T:
955 {
956 u_int8_t hwr;
957
958 typestr = (type == WE_TYPE_SMC8216C) ?
959 "SMC8216/SMC8216C" : "SMC8216T";
960
961 hwr = bus_space_read_1(asict, asich, WE790_HWR);
962 bus_space_write_1(asict, asich, WE790_HWR,
963 hwr | WE790_HWR_SWH);
964 switch (bus_space_read_1(asict, asich, WE790_RAR) &
965 WE790_RAR_SZ64) {
966 case WE790_RAR_SZ64:
967 memsize = 65536;
968 break;
969 case WE790_RAR_SZ32:
970 memsize = 32768;
971 break;
972 case WE790_RAR_SZ16:
973 memsize = 16384;
974 break;
975 case WE790_RAR_SZ8:
976 /* 8216 has 16K shared mem -- 8416 has 8K */
977 typestr = (type == WE_TYPE_SMC8216C) ?
978 "SMC8416C/SMC8416BT" : "SMC8416T";
979 memsize = 8192;
980 break;
981 }
982 bus_space_write_1(asict, asich, WE790_HWR, hwr);
983
984 is16bit = 1;
985 is790 = 1;
986 break;
987 }
988 #ifdef TOSH_ETHER
989 case WE_TYPE_TOSHIBA1:
990 typestr = "Toshiba1";
991 memsize = 32768;
992 is16bit = 1;
993 break;
994 case WE_TYPE_TOSHIBA4:
995 typestr = "Toshiba4";
996 memsize = 32768;
997 is16bit = 1;
998 break;
999 #endif
1000 default:
1001 /* Not one we recognize. */
1002 return (NULL);
1003 }
1004
1005 /*
1006 * Make some adjustments to initial values depending on what is
1007 * found in the ICR.
1008 */
1009 if (is16bit && (type != WE_TYPE_WD8013EBT) &&
1010 #ifdef TOSH_ETHER
1011 (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) &&
1012 #endif
1013 (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) {
1014 is16bit = 0;
1015 memsize = 8192;
1016 }
1017
1018 #ifdef WE_DEBUG
1019 {
1020 int i;
1021
1022 printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
1023 "memsize = %d\n", type, typestr, is16bit, memsize);
1024 for (i = 0; i < 8; i++)
1025 printf(" %d -> 0x%x\n", i,
1026 bus_space_read_1(asict, asich, i));
1027 }
1028 #endif
1029
1030 if (typep != NULL)
1031 *typep = type;
1032 if (memsizep != NULL)
1033 *memsizep = memsize;
1034 if (is16bitp != NULL)
1035 *is16bitp = is16bit;
1036 if (is790p != NULL)
1037 *is790p = is790;
1038 return (typestr);
1039 }
1040