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