xref: /openbsd-src/sys/dev/isa/if_we.c (revision b9ec31cadfb65ad59de9e1a818b58bdc5c58223f)
1 /*	$OpenBSD: if_we.c,v 1.17 2006/10/20 17:02:24 brad 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 INET
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/in_var.h>
78 #include <netinet/ip.h>
79 #include <netinet/if_ether.h>
80 #endif
81 
82 #if NBPFILTER > 0
83 #include <net/bpf.h>
84 #endif
85 
86 #include <machine/bus.h>
87 #include <machine/intr.h>
88 
89 #include <dev/isa/isareg.h>
90 #include <dev/isa/isavar.h>
91 
92 #include <dev/ic/dp8390reg.h>
93 #include <dev/ic/dp8390var.h>
94 
95 #include <dev/isa/if_wereg.h>
96 
97 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
98 #define	bus_space_read_region_stream_2	bus_space_read_region_2
99 #define	bus_space_write_stream_2	bus_space_write_2
100 #define	bus_space_write_region_stream_2	bus_space_write_region_2
101 #endif
102 
103 struct we_softc {
104 	struct dp8390_softc sc_dp8390;
105 
106 	bus_space_tag_t sc_asict;	/* space tag for ASIC */
107 	bus_space_handle_t sc_asich;	/* space handle for ASIC */
108 
109 	u_int8_t sc_laar_proto;
110 	u_int8_t sc_msr_proto;
111 
112 	u_int8_t sc_type;		/* our type */
113 
114 	int sc_16bitp;			/* are we 16 bit? */
115 
116 	void *sc_ih;			/* interrupt handle */
117 };
118 
119 int	we_probe(struct device *, void *, void *);
120 void	we_attach(struct device *, struct device *, void *);
121 
122 struct cfattach we_isa_ca = {
123 	sizeof(struct we_softc), we_probe, we_attach
124 };
125 
126 #if NWE_ISAPNP
127 struct cfattach we_isapnp_ca = {
128 	sizeof(struct we_softc), we_probe, we_attach
129 };
130 #endif /* NWE_ISAPNP */
131 
132 struct cfdriver we_cd = {
133 	NULL, "we", DV_IFNET
134 };
135 
136 const char *we_params(bus_space_tag_t, bus_space_handle_t, u_int8_t *,
137 	    bus_size_t *, int *, int *);
138 void	we_set_media(struct we_softc *, int);
139 
140 void	we_media_init(struct dp8390_softc *);
141 
142 int	we_mediachange(struct dp8390_softc *);
143 void	we_mediastatus(struct dp8390_softc *, struct ifmediareq *);
144 
145 void	we_recv_int(struct dp8390_softc *);
146 void	we_init_card(struct dp8390_softc *);
147 int	we_write_mbuf(struct dp8390_softc *, struct mbuf *, int);
148 int	we_ring_copy(struct dp8390_softc *, int, caddr_t, u_short);
149 void	we_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *);
150 int	we_test_mem(struct dp8390_softc *);
151 
152 __inline void we_readmem(struct we_softc *, int, u_int8_t *, int);
153 
154 static const int we_584_irq[] = {
155 	9, 3, 5, 7, 10, 11, 15, 4,
156 };
157 #define	NWE_584_IRQ	(sizeof(we_584_irq) / sizeof(we_584_irq[0]))
158 
159 static const int we_790_irq[] = {
160 	IRQUNK, 9, 3, 5, 7, 10, 11, 15,
161 };
162 #define	NWE_790_IRQ	(sizeof(we_790_irq) / sizeof(we_790_irq[0]))
163 
164 /*
165  * Delay needed when switching 16-bit access to shared memory.
166  */
167 #define	WE_DELAY(wsc) delay(3)
168 
169 /*
170  * Enable card RAM, and 16-bit access.
171  */
172 #define	WE_MEM_ENABLE(wsc) \
173 do { \
174 	if ((wsc)->sc_16bitp) \
175 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
176 		    WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
177 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
178 	    WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
179 	WE_DELAY((wsc)); \
180 } while (0)
181 
182 /*
183  * Disable card RAM, and 16-bit access.
184  */
185 #define	WE_MEM_DISABLE(wsc) \
186 do { \
187 	bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
188 	    WE_MSR, (wsc)->sc_msr_proto); \
189 	if ((wsc)->sc_16bitp) \
190 		bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
191 		    WE_LAAR, (wsc)->sc_laar_proto); \
192 	WE_DELAY((wsc)); \
193 } while (0)
194 
195 int
196 we_probe(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 it's 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 we_init_card() called via 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 void
808 we_init_card(struct dp8390_softc *sc)
809 {
810 	struct we_softc *wsc = (struct we_softc *)sc;
811 	struct ifmedia *ifm = &sc->sc_media;
812 
813 	we_set_media(wsc, ifm->ifm_cur->ifm_media);
814 }
815 
816 void
817 we_set_media(struct we_softc *wsc, int media)
818 {
819 	struct dp8390_softc *sc = &wsc->sc_dp8390;
820 	bus_space_tag_t asict = wsc->sc_asict;
821 	bus_space_handle_t asich = wsc->sc_asich;
822 	u_int8_t hwr, gcr, irr;
823 
824 	if (sc->is790) {
825 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
826 		bus_space_write_1(asict, asich, WE790_HWR,
827 		    hwr | WE790_HWR_SWH);
828 		gcr = bus_space_read_1(asict, asich, WE790_GCR);
829 		if (IFM_SUBTYPE(media) == IFM_10_2)
830 			gcr |= WE790_GCR_GPOUT;
831 		else
832 			gcr &= ~WE790_GCR_GPOUT;
833 		bus_space_write_1(asict, asich, WE790_GCR,
834 		    gcr | WE790_GCR_LIT);
835 		bus_space_write_1(asict, asich, WE790_HWR,
836 		    hwr & ~WE790_HWR_SWH);
837 		return;
838 	}
839 
840 	irr = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR);
841 	if (IFM_SUBTYPE(media) == IFM_10_2)
842 		irr |= WE_IRR_OUT2;
843 	else
844 		irr &= ~WE_IRR_OUT2;
845 	bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_IRR, irr);
846 }
847 
848 const char *
849 we_params(bus_space_tag_t asict, bus_space_handle_t asich,
850     u_int8_t *typep, bus_size_t *memsizep, int *is16bitp,
851     int *is790p)
852 {
853 	const char *typestr;
854 	bus_size_t memsize;
855 	int is16bit, is790;
856 	u_int8_t type;
857 
858 	memsize = 8192;
859 	is16bit = is790 = 0;
860 
861 	type = bus_space_read_1(asict, asich, WE_CARD_ID);
862 	switch (type) {
863 	case WE_TYPE_WD8003S:
864 		typestr = "WD8003S";
865 		break;
866 	case WE_TYPE_WD8003E:
867 		typestr = "WD8003E";
868 		break;
869 	case WE_TYPE_WD8003EB:
870 		typestr = "WD8003EB";
871 		break;
872 	case WE_TYPE_WD8003W:
873 		typestr = "WD8003W";
874 		break;
875 	case WE_TYPE_WD8013EBT:
876 		typestr = "WD8013EBT";
877 		memsize = 16384;
878 		is16bit = 1;
879 		break;
880 	case WE_TYPE_WD8013W:
881 		typestr = "WD8013W";
882 		memsize = 16384;
883 		is16bit = 1;
884 		break;
885 	case WE_TYPE_WD8013EP:		/* also WD8003EP */
886 		if (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) {
887 			is16bit = 1;
888 			memsize = 16384;
889 			typestr = "WD8013EP";
890 		} else
891 			typestr = "WD8003EP";
892 		break;
893 	case WE_TYPE_WD8013WC:
894 		typestr = "WD8013WC";
895 		memsize = 16384;
896 		is16bit = 1;
897 		break;
898 	case WE_TYPE_WD8013EBP:
899 		typestr = "WD8013EBP";
900 		memsize = 16384;
901 		is16bit = 1;
902 		break;
903 	case WE_TYPE_WD8013EPC:
904 		typestr = "WD8013EPC";
905 		memsize = 16384;
906 		is16bit = 1;
907 		break;
908 	case WE_TYPE_SMC8216C:
909 	case WE_TYPE_SMC8216T:
910 	    {
911 		u_int8_t hwr;
912 
913 		typestr = (type == WE_TYPE_SMC8216C) ?
914 		    "SMC8216/SMC8216C" : "SMC8216T";
915 
916 		hwr = bus_space_read_1(asict, asich, WE790_HWR);
917 		bus_space_write_1(asict, asich, WE790_HWR,
918 		    hwr | WE790_HWR_SWH);
919 		switch (bus_space_read_1(asict, asich, WE790_RAR) &
920 		    WE790_RAR_SZ64) {
921 		case WE790_RAR_SZ64:
922 			memsize = 65536;
923 			break;
924 		case WE790_RAR_SZ32:
925 			memsize = 32768;
926 			break;
927 		case WE790_RAR_SZ16:
928 			memsize = 16384;
929 			break;
930 		case WE790_RAR_SZ8:
931 			/* 8216 has 16K shared mem -- 8416 has 8K */
932 			typestr = (type == WE_TYPE_SMC8216C) ?
933 			    "SMC8416C/SMC8416BT" : "SMC8416T";
934 			memsize = 8192;
935 			break;
936 		}
937 		bus_space_write_1(asict, asich, WE790_HWR, hwr);
938 
939 		is16bit = 1;
940 		is790 = 1;
941 		break;
942 	    }
943 #ifdef TOSH_ETHER
944 	case WE_TYPE_TOSHIBA1:
945 		typestr = "Toshiba1";
946 		memsize = 32768;
947 		is16bit = 1;
948 		break;
949 	case WE_TYPE_TOSHIBA4:
950 		typestr = "Toshiba4";
951 		memsize = 32768;
952 		is16bit = 1;
953 		break;
954 #endif
955 	default:
956 		/* Not one we recognize. */
957 		return (NULL);
958 	}
959 
960 	/*
961 	 * Make some adjustments to initial values depending on what is
962 	 * found in the ICR.
963 	 */
964 	if (is16bit && (type != WE_TYPE_WD8013EBT) &&
965 #ifdef TOSH_ETHER
966 	    (type != WE_TYPE_TOSHIBA1 && type != WE_TYPE_TOSHIBA4) &&
967 #endif
968 	    (bus_space_read_1(asict, asich, WE_ICR) & WE_ICR_16BIT) == 0) {
969 		is16bit = 0;
970 		memsize = 8192;
971 	}
972 
973 #ifdef WE_DEBUG
974 	{
975 		int i;
976 
977 		printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
978 		    "memsize = %d\n", type, typestr, is16bit, memsize);
979 		for (i = 0; i < 8; i++)
980 			printf("     %d -> 0x%x\n", i,
981 			    bus_space_read_1(asict, asich, i));
982 	}
983 #endif
984 
985 	if (typep != NULL)
986 		*typep = type;
987 	if (memsizep != NULL)
988 		*memsizep = memsize;
989 	if (is16bitp != NULL)
990 		*is16bitp = is16bit;
991 	if (is790p != NULL)
992 		*is790p = is790;
993 	return (typestr);
994 }
995