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