1 /*-
2  * Copyright (c) 2005, M. Warner Losh
3  * All rights reserved.
4  * Copyright (c) 1995, David Greenman
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: stable/10/sys/dev/ed/if_ed_wd80x3.c 190483 2009-03-28 04:56:56Z imp $");
32 
33 #include "opt_ed.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/sockio.h>
38 #include <sys/mbuf.h>
39 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/syslog.h>
42 
43 #include <sys/bus.h>
44 
45 #include <machine/bus.h>
46 #include <sys/rman.h>
47 #include <machine/resource.h>
48 
49 #include <net/ethernet.h>
50 #include <net/if.h>
51 #include <net/if_arp.h>
52 #include <net/if_dl.h>
53 #include <net/if_mib.h>
54 #include <net/if_media.h>
55 
56 #include <net/bpf.h>
57 
58 #include <dev/ed/if_edreg.h>
59 #include <dev/ed/if_edvar.h>
60 
61 /*
62  * Interrupt conversion table for WD/SMC ASIC/83C584
63  */
64 static uint16_t ed_intr_val[] = {
65 	9,
66 	3,
67 	5,
68 	7,
69 	10,
70 	11,
71 	15,
72 	4
73 };
74 
75 /*
76  * Interrupt conversion table for 83C790
77  */
78 static uint16_t ed_790_intr_val[] = {
79 	0,
80 	9,
81 	3,
82 	5,
83 	7,
84 	10,
85 	11,
86 	15
87 };
88 
89 /*
90  * Probe and vendor-specific initialization routine for SMC/WD80x3 boards
91  */
92 int
ed_probe_WD80x3_generic(device_t dev,int flags,uint16_t * intr_vals[])93 ed_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[])
94 {
95 	struct ed_softc *sc = device_get_softc(dev);
96 	int	error;
97 	int     i;
98 	u_int   memsize;
99 	u_char  iptr, isa16bit, sum, totalsum;
100 	u_long	irq, junk, pmem;
101 
102 	sc->chip_type = ED_CHIP_TYPE_DP8390;
103 
104 	if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) {
105 		totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER;
106 		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW);
107 		DELAY(10000);
108 	}
109 	else
110 		totalsum = ED_WD_ROM_CHECKSUM_TOTAL;
111 
112 	/*
113 	 * Attempt to do a checksum over the station address PROM. If it
114 	 * fails, it's probably not a SMC/WD board. There is a problem with
115 	 * this, though: some clone WD boards don't pass the checksum test.
116 	 * Danpex boards for one.
117 	 */
118 	for (sum = 0, i = 0; i < 8; ++i)
119 		sum += ed_asic_inb(sc, ED_WD_PROM + i);
120 
121 	if (sum != totalsum) {
122 		/*
123 		 * Checksum is invalid. This often happens with cheap WD8003E
124 		 * clones.  In this case, the checksum byte (the eighth byte)
125 		 * seems to always be zero.
126 		 */
127 		if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
128 		    ed_asic_inb(sc, ED_WD_PROM + 7) != 0)
129 			return (ENXIO);
130 	}
131 	/* reset card to force it into a known state. */
132 	if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER)
133 		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
134 	else
135 		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST);
136 
137 	DELAY(100);
138 	ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST);
139 	/* wait in the case this card is reading its EEROM */
140 	DELAY(5000);
141 
142 	sc->vendor = ED_VENDOR_WD_SMC;
143 	sc->type = ed_asic_inb(sc, ED_WD_CARD_ID);
144 
145 	/*
146 	 * Set initial values for width/size.
147 	 */
148 	memsize = 8192;
149 	isa16bit = 0;
150 	switch (sc->type) {
151 	case ED_TYPE_WD8003S:
152 		sc->type_str = "WD8003S";
153 		break;
154 	case ED_TYPE_WD8003E:
155 		sc->type_str = "WD8003E";
156 		break;
157 	case ED_TYPE_WD8003EB:
158 		sc->type_str = "WD8003EB";
159 		break;
160 	case ED_TYPE_WD8003W:
161 		sc->type_str = "WD8003W";
162 		break;
163 	case ED_TYPE_WD8013EBT:
164 		sc->type_str = "WD8013EBT";
165 		memsize = 16384;
166 		isa16bit = 1;
167 		break;
168 	case ED_TYPE_WD8013W:
169 		sc->type_str = "WD8013W";
170 		memsize = 16384;
171 		isa16bit = 1;
172 		break;
173 	case ED_TYPE_WD8013EP:	/* also WD8003EP */
174 		if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) {
175 			isa16bit = 1;
176 			memsize = 16384;
177 			sc->type_str = "WD8013EP";
178 		} else
179 			sc->type_str = "WD8003EP";
180 		break;
181 	case ED_TYPE_WD8013WC:
182 		sc->type_str = "WD8013WC";
183 		memsize = 16384;
184 		isa16bit = 1;
185 		break;
186 	case ED_TYPE_WD8013EBP:
187 		sc->type_str = "WD8013EBP";
188 		memsize = 16384;
189 		isa16bit = 1;
190 		break;
191 	case ED_TYPE_WD8013EPC:
192 		sc->type_str = "WD8013EPC";
193 		memsize = 16384;
194 		isa16bit = 1;
195 		break;
196 	case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */
197 	case ED_TYPE_SMC8216T:
198 		if (sc->type == ED_TYPE_SMC8216C)
199 			sc->type_str = "SMC8216/SMC8216C";
200 		else
201 			sc->type_str = "SMC8216T";
202 
203 		ed_asic_outb(sc, ED_WD790_HWR,
204 		    ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
205 		switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) {
206 		case ED_WD790_RAR_SZ64:
207 			memsize = 65536;
208 			break;
209 		case ED_WD790_RAR_SZ32:
210 			memsize = 32768;
211 			break;
212 		case ED_WD790_RAR_SZ16:
213 			memsize = 16384;
214 			break;
215 		case ED_WD790_RAR_SZ8:
216 			/* 8216 has 16K shared mem -- 8416 has 8K */
217 			if (sc->type == ED_TYPE_SMC8216C)
218 				sc->type_str = "SMC8416C/SMC8416BT";
219 			else
220 				sc->type_str = "SMC8416T";
221 			memsize = 8192;
222 			break;
223 		}
224 		ed_asic_outb(sc, ED_WD790_HWR,
225 		    ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
226 
227 		isa16bit = 1;
228 		sc->chip_type = ED_CHIP_TYPE_WD790;
229 		break;
230 	case ED_TYPE_TOSHIBA1:
231 		sc->type_str = "Toshiba1";
232 		memsize = 32768;
233 		isa16bit = 1;
234 		break;
235 	case ED_TYPE_TOSHIBA4:
236 		sc->type_str = "Toshiba4";
237 		memsize = 32768;
238 		isa16bit = 1;
239 		break;
240 	default:
241 		sc->type_str = "";
242 		break;
243 	}
244 
245 	/*
246 	 * Make some adjustments to initial values depending on what is found
247 	 * in the ICR.
248 	 */
249 	if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
250 	  && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
251 	    && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
252 		isa16bit = 0;
253 		memsize = 8192;
254 	}
255 
256 	/* Override memsize? XXX */
257 	error = ed_alloc_memory(dev, 0, memsize);
258 	if (error)
259 		return (error);
260 	sc->mem_start = 0;
261 
262 #ifdef ED_DEBUG
263 	printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n",
264 	    sc->type, sc->type_str, isa16bit, memsize,
265 	    rman_get_size(sc->mem_res));
266 	for (i = 0; i < 8; i++)
267 		printf("%x -> %x\n", i, ed_asic_inb(sc, i));
268 #endif
269 	pmem = rman_get_start(sc->mem_res);
270 	if (!(flags & ED_FLAGS_PCCARD)) {
271 		error = ed_isa_mem_ok(dev, pmem, memsize);
272 		if (error)
273 			return (error);
274 	}
275 
276 	/*
277 	 * (note that if the user specifies both of the following flags that
278 	 * '8bit' mode intentionally has precedence)
279 	 */
280 	if (flags & ED_FLAGS_FORCE_16BIT_MODE)
281 		isa16bit = 1;
282 	if (flags & ED_FLAGS_FORCE_8BIT_MODE)
283 		isa16bit = 0;
284 
285 	/*
286 	 * If possible, get the assigned interrupt number from the card and
287 	 * use it.
288 	 */
289 	if ((sc->type & ED_WD_SOFTCONFIG) &&
290 	    (sc->chip_type != ED_CHIP_TYPE_WD790)) {
291 
292 		/*
293 		 * Assemble together the encoded interrupt number.
294 		 */
295 		iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) |
296 		    ((ed_asic_inb(sc, ED_WD_IRR) &
297 		      (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
298 
299 		/*
300 		 * If no interrupt specified (or "?"), use what the board tells us.
301 		 */
302 		error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
303 		if (error && intr_vals[0] != NULL)
304 			error = bus_set_resource(dev, SYS_RES_IRQ, 0,
305 			    intr_vals[0][iptr], 1);
306 		if (error)
307 			return (error);
308 
309 		/*
310 		 * Enable the interrupt.
311 		 */
312 		ed_asic_outb(sc, ED_WD_IRR,
313 		     ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN);
314 	}
315 	if (sc->chip_type == ED_CHIP_TYPE_WD790) {
316 		ed_asic_outb(sc, ED_WD790_HWR,
317 		  ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
318 		iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
319 			(ed_asic_inb(sc, ED_WD790_GCR) &
320 			 (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2);
321 		ed_asic_outb(sc, ED_WD790_HWR,
322 		    ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
323 
324 		/*
325 		 * If no interrupt specified (or "?"), use what the board tells us.
326 		 */
327 		error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
328 		if (error && intr_vals[1] != NULL)
329 			error = bus_set_resource(dev, SYS_RES_IRQ, 0,
330 			  intr_vals[1][iptr], 1);
331 		if (error)
332 			return (error);
333 
334 		/*
335 		 * Enable interrupts.
336 		 */
337 		ed_asic_outb(sc, ED_WD790_ICR,
338 		  ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL);
339 	}
340 	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
341 	if (error) {
342 		device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n",
343 			      sc->type_str);
344 		return (ENXIO);
345 	}
346 	sc->isa16bit = isa16bit;
347 	sc->mem_shared = 1;
348 
349 	/*
350 	 * allocate one xmit buffer if < 16k, two buffers otherwise
351 	 */
352 	if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
353 		sc->txb_cnt = 1;
354 	else
355 		sc->txb_cnt = 2;
356 	sc->tx_page_start = ED_WD_PAGE_OFFSET;
357 	sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt;
358 	sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE;
359 	sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start);
360 	sc->mem_size = memsize;
361 	sc->mem_end = sc->mem_start + memsize;
362 
363 	/*
364 	 * Get station address from on-board ROM
365 	 */
366 	for (i = 0; i < ETHER_ADDR_LEN; ++i)
367 		sc->enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i);
368 
369 	/*
370 	 * Set upper address bits and 8/16 bit access to shared memory.
371 	 */
372 	if (isa16bit) {
373 		if (sc->chip_type == ED_CHIP_TYPE_WD790)
374 			sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR);
375 		else
376 			sc->wd_laar_proto = ED_WD_LAAR_L16EN |
377 			    ((pmem >> 19) & ED_WD_LAAR_ADDRHI);
378 		/*
379 		 * Enable 16bit access
380 		 */
381 		ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto |
382 		    ED_WD_LAAR_M16EN);
383 	} else {
384 		if (((sc->type & ED_WD_SOFTCONFIG) ||
385 		     (sc->type == ED_TYPE_TOSHIBA1) ||
386 		     (sc->type == ED_TYPE_TOSHIBA4) ||
387 		     (sc->type == ED_TYPE_WD8013EBT)) &&
388 		    (sc->chip_type != ED_CHIP_TYPE_WD790)) {
389 			sc->wd_laar_proto = (pmem >> 19) &
390 			    ED_WD_LAAR_ADDRHI;
391 			ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto);
392 		}
393 	}
394 
395 	/*
396 	 * Set address and enable interface shared memory.
397 	 */
398 	if (sc->chip_type != ED_CHIP_TYPE_WD790) {
399 		if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) {
400 			ed_asic_outb(sc, ED_WD_MSR + 1,
401 			    ((pmem >> 8) & 0xe0) | 4);
402 			ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f));
403 			ed_asic_outb(sc, ED_WD_MSR,
404 			    ED_WD_MSR_MENB | ED_WD_MSR_POW);
405 		} else {
406 			ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) &
407 			    ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
408 		}
409 		sc->cr_proto = ED_CR_RD2;
410 	} else {
411 		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB);
412 		ed_asic_outb(sc, ED_WD790_HWR,
413 		    (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH));
414 		ed_asic_outb(sc, ED_WD790_RAR,
415 		    ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) |
416 		     (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0));
417 		ed_asic_outb(sc, ED_WD790_HWR,
418 		    (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH));
419 		sc->cr_proto = 0;
420 	}
421 
422 	/*
423 	 * Disable 16bit access to shared memory - we leave it
424 	 * disabled so that 1) machines reboot properly when the board
425 	 * is set 16 bit mode and there are conflicting 8bit
426 	 * devices/ROMS in the same 128k address space as this boards
427 	 * shared memory. and 2) so that other 8 bit devices with
428 	 * shared memory can be used in this 128k region, too.
429 	 */
430 	error = ed_clear_memory(dev);
431 	ed_disable_16bit_access(sc);
432 	sc->sc_write_mbufs = ed_shmem_write_mbufs;
433 	return (error);
434 }
435 
436 int
ed_probe_WD80x3(device_t dev,int port_rid,int flags)437 ed_probe_WD80x3(device_t dev, int port_rid, int flags)
438 {
439 	struct ed_softc *sc = device_get_softc(dev);
440 	int	error;
441 	static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val};
442 
443 	error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS);
444 	if (error)
445 		return (error);
446 
447 	sc->asic_offset = ED_WD_ASIC_OFFSET;
448 	sc->nic_offset  = ED_WD_NIC_OFFSET;
449 
450 	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
451 }
452