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