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