1141586Simp/*-
2141586Simp * Copyright (c) 2005, M. Warner Losh
3141586Simp * All rights reserved.
4141586Simp * Copyright (c) 1995, David Greenman
5141586Simp * All rights reserved.
6141586Simp *
7141586Simp * Redistribution and use in source and binary forms, with or without
8141586Simp * modification, are permitted provided that the following conditions
9141586Simp * are met:
10141586Simp * 1. Redistributions of source code must retain the above copyright
11141586Simp *    notice unmodified, this list of conditions, and the following
12141586Simp *    disclaimer.
13141586Simp * 2. Redistributions in binary form must reproduce the above copyright
14141586Simp *    notice, this list of conditions and the following disclaimer in the
15141586Simp *    documentation and/or other materials provided with the distribution.
16141586Simp *
17141586Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18141586Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19141586Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20141586Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21141586Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22141586Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23141586Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24141586Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25141586Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26141586Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27141586Simp * SUCH DAMAGE.
28141586Simp */
29141586Simp
30141586Simp#include <sys/cdefs.h>
31141586Simp__FBSDID("$FreeBSD$");
32141586Simp
33141586Simp#include "opt_ed.h"
34141586Simp
35141586Simp#include <sys/param.h>
36141586Simp#include <sys/systm.h>
37141586Simp#include <sys/sockio.h>
38141586Simp#include <sys/mbuf.h>
39141586Simp#include <sys/kernel.h>
40141586Simp#include <sys/socket.h>
41141586Simp#include <sys/syslog.h>
42141586Simp
43141586Simp#include <sys/bus.h>
44141586Simp
45141586Simp#include <machine/bus.h>
46141586Simp#include <sys/rman.h>
47141586Simp#include <machine/resource.h>
48141586Simp
49141586Simp#include <net/ethernet.h>
50141586Simp#include <net/if.h>
51141586Simp#include <net/if_arp.h>
52141586Simp#include <net/if_dl.h>
53141586Simp#include <net/if_mib.h>
54141586Simp#include <net/if_media.h>
55141586Simp
56141586Simp#include <net/bpf.h>
57141586Simp
58141586Simp#include <dev/ed/if_edreg.h>
59141586Simp#include <dev/ed/if_edvar.h>
60141586Simp
61141586Simp/*
62141586Simp * Interrupt conversion table for WD/SMC ASIC/83C584
63141586Simp */
64141586Simpstatic uint16_t ed_intr_val[] = {
65141586Simp	9,
66141586Simp	3,
67141586Simp	5,
68141586Simp	7,
69141586Simp	10,
70141586Simp	11,
71141586Simp	15,
72141586Simp	4
73141586Simp};
74141586Simp
75141586Simp/*
76141586Simp * Interrupt conversion table for 83C790
77141586Simp */
78141586Simpstatic uint16_t ed_790_intr_val[] = {
79141586Simp	0,
80141586Simp	9,
81141586Simp	3,
82141586Simp	5,
83141586Simp	7,
84141586Simp	10,
85141586Simp	11,
86141586Simp	15
87141586Simp};
88141586Simp
89141586Simp/*
90141586Simp * Probe and vendor-specific initialization routine for SMC/WD80x3 boards
91141586Simp */
92141586Simpint
93141586Simped_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[])
94141586Simp{
95141586Simp	struct ed_softc *sc = device_get_softc(dev);
96141586Simp	int	error;
97141586Simp	int     i;
98141586Simp	u_int   memsize;
99141586Simp	u_char  iptr, isa16bit, sum, totalsum;
100141586Simp	u_long	irq, junk, pmem;
101141586Simp
102141586Simp	sc->chip_type = ED_CHIP_TYPE_DP8390;
103141586Simp
104141586Simp	if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) {
105141586Simp		totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER;
106141586Simp		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW);
107141586Simp		DELAY(10000);
108141586Simp	}
109141586Simp	else
110141586Simp		totalsum = ED_WD_ROM_CHECKSUM_TOTAL;
111141586Simp
112141586Simp	/*
113141586Simp	 * Attempt to do a checksum over the station address PROM. If it
114141586Simp	 * fails, it's probably not a SMC/WD board. There is a problem with
115141586Simp	 * this, though: some clone WD boards don't pass the checksum test.
116141586Simp	 * Danpex boards for one.
117141586Simp	 */
118141586Simp	for (sum = 0, i = 0; i < 8; ++i)
119141586Simp		sum += ed_asic_inb(sc, ED_WD_PROM + i);
120141586Simp
121141586Simp	if (sum != totalsum) {
122141586Simp		/*
123141586Simp		 * Checksum is invalid. This often happens with cheap WD8003E
124141586Simp		 * clones.  In this case, the checksum byte (the eighth byte)
125141586Simp		 * seems to always be zero.
126141586Simp		 */
127141586Simp		if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
128141586Simp		    ed_asic_inb(sc, ED_WD_PROM + 7) != 0)
129141586Simp			return (ENXIO);
130141586Simp	}
131141586Simp	/* reset card to force it into a known state. */
132141586Simp	if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER)
133141586Simp		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
134141586Simp	else
135141586Simp		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST);
136141586Simp
137141586Simp	DELAY(100);
138141586Simp	ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST);
139141586Simp	/* wait in the case this card is reading its EEROM */
140141586Simp	DELAY(5000);
141141586Simp
142141586Simp	sc->vendor = ED_VENDOR_WD_SMC;
143141586Simp	sc->type = ed_asic_inb(sc, ED_WD_CARD_ID);
144141586Simp
145141586Simp	/*
146141586Simp	 * Set initial values for width/size.
147141586Simp	 */
148141586Simp	memsize = 8192;
149141586Simp	isa16bit = 0;
150141586Simp	switch (sc->type) {
151141586Simp	case ED_TYPE_WD8003S:
152141586Simp		sc->type_str = "WD8003S";
153141586Simp		break;
154141586Simp	case ED_TYPE_WD8003E:
155141586Simp		sc->type_str = "WD8003E";
156141586Simp		break;
157141586Simp	case ED_TYPE_WD8003EB:
158141586Simp		sc->type_str = "WD8003EB";
159141586Simp		break;
160141586Simp	case ED_TYPE_WD8003W:
161141586Simp		sc->type_str = "WD8003W";
162141586Simp		break;
163141586Simp	case ED_TYPE_WD8013EBT:
164141586Simp		sc->type_str = "WD8013EBT";
165141586Simp		memsize = 16384;
166141586Simp		isa16bit = 1;
167141586Simp		break;
168141586Simp	case ED_TYPE_WD8013W:
169141586Simp		sc->type_str = "WD8013W";
170141586Simp		memsize = 16384;
171141586Simp		isa16bit = 1;
172141586Simp		break;
173141586Simp	case ED_TYPE_WD8013EP:	/* also WD8003EP */
174141586Simp		if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) {
175141586Simp			isa16bit = 1;
176141586Simp			memsize = 16384;
177141586Simp			sc->type_str = "WD8013EP";
178141586Simp		} else
179141586Simp			sc->type_str = "WD8003EP";
180141586Simp		break;
181141586Simp	case ED_TYPE_WD8013WC:
182141586Simp		sc->type_str = "WD8013WC";
183141586Simp		memsize = 16384;
184141586Simp		isa16bit = 1;
185141586Simp		break;
186141586Simp	case ED_TYPE_WD8013EBP:
187141586Simp		sc->type_str = "WD8013EBP";
188141586Simp		memsize = 16384;
189141586Simp		isa16bit = 1;
190141586Simp		break;
191141586Simp	case ED_TYPE_WD8013EPC:
192141586Simp		sc->type_str = "WD8013EPC";
193141586Simp		memsize = 16384;
194141586Simp		isa16bit = 1;
195141586Simp		break;
196141586Simp	case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */
197141586Simp	case ED_TYPE_SMC8216T:
198141586Simp		if (sc->type == ED_TYPE_SMC8216C)
199141586Simp			sc->type_str = "SMC8216/SMC8216C";
200141586Simp		else
201141586Simp			sc->type_str = "SMC8216T";
202141586Simp
203141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
204141586Simp		    ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
205141586Simp		switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) {
206141586Simp		case ED_WD790_RAR_SZ64:
207141586Simp			memsize = 65536;
208141586Simp			break;
209141586Simp		case ED_WD790_RAR_SZ32:
210141586Simp			memsize = 32768;
211141586Simp			break;
212141586Simp		case ED_WD790_RAR_SZ16:
213141586Simp			memsize = 16384;
214141586Simp			break;
215141586Simp		case ED_WD790_RAR_SZ8:
216141586Simp			/* 8216 has 16K shared mem -- 8416 has 8K */
217141586Simp			if (sc->type == ED_TYPE_SMC8216C)
218141586Simp				sc->type_str = "SMC8416C/SMC8416BT";
219141586Simp			else
220141586Simp				sc->type_str = "SMC8416T";
221141586Simp			memsize = 8192;
222141586Simp			break;
223141586Simp		}
224141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
225141586Simp		    ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
226141586Simp
227141586Simp		isa16bit = 1;
228141586Simp		sc->chip_type = ED_CHIP_TYPE_WD790;
229141586Simp		break;
230141586Simp	case ED_TYPE_TOSHIBA1:
231141586Simp		sc->type_str = "Toshiba1";
232141586Simp		memsize = 32768;
233141586Simp		isa16bit = 1;
234141586Simp		break;
235141586Simp	case ED_TYPE_TOSHIBA4:
236141586Simp		sc->type_str = "Toshiba4";
237141586Simp		memsize = 32768;
238141586Simp		isa16bit = 1;
239141586Simp		break;
240141586Simp	default:
241141586Simp		sc->type_str = "";
242141586Simp		break;
243141586Simp	}
244141586Simp
245141586Simp	/*
246141586Simp	 * Make some adjustments to initial values depending on what is found
247141586Simp	 * in the ICR.
248141586Simp	 */
249141586Simp	if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
250141586Simp	  && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
251141586Simp	    && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
252141586Simp		isa16bit = 0;
253141586Simp		memsize = 8192;
254141586Simp	}
255141586Simp
256141586Simp	/* Override memsize? XXX */
257141586Simp	error = ed_alloc_memory(dev, 0, memsize);
258141586Simp	if (error)
259141586Simp		return (error);
260149558Simp	sc->mem_start = 0;
261141586Simp
262141586Simp#ifdef ED_DEBUG
263141586Simp	printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n",
264141586Simp	    sc->type, sc->type_str, isa16bit, memsize,
265141586Simp	    rman_get_size(sc->mem_res));
266141586Simp	for (i = 0; i < 8; i++)
267141586Simp		printf("%x -> %x\n", i, ed_asic_inb(sc, i));
268141586Simp#endif
269141586Simp	pmem = rman_get_start(sc->mem_res);
270190483Simp	if (!(flags & ED_FLAGS_PCCARD)) {
271190483Simp		error = ed_isa_mem_ok(dev, pmem, memsize);
272190483Simp		if (error)
273190483Simp			return (error);
274190483Simp	}
275141586Simp
276141586Simp	/*
277141586Simp	 * (note that if the user specifies both of the following flags that
278141586Simp	 * '8bit' mode intentionally has precedence)
279141586Simp	 */
280141586Simp	if (flags & ED_FLAGS_FORCE_16BIT_MODE)
281141586Simp		isa16bit = 1;
282141586Simp	if (flags & ED_FLAGS_FORCE_8BIT_MODE)
283141586Simp		isa16bit = 0;
284141586Simp
285141586Simp	/*
286141586Simp	 * If possible, get the assigned interrupt number from the card and
287141586Simp	 * use it.
288141586Simp	 */
289141586Simp	if ((sc->type & ED_WD_SOFTCONFIG) &&
290141586Simp	    (sc->chip_type != ED_CHIP_TYPE_WD790)) {
291141586Simp
292141586Simp		/*
293141586Simp		 * Assemble together the encoded interrupt number.
294141586Simp		 */
295141586Simp		iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) |
296141586Simp		    ((ed_asic_inb(sc, ED_WD_IRR) &
297141586Simp		      (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
298141586Simp
299141586Simp		/*
300141586Simp		 * If no interrupt specified (or "?"), use what the board tells us.
301141586Simp		 */
302141586Simp		error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
303141586Simp		if (error && intr_vals[0] != NULL)
304141586Simp			error = bus_set_resource(dev, SYS_RES_IRQ, 0,
305141586Simp			    intr_vals[0][iptr], 1);
306141586Simp		if (error)
307141586Simp			return (error);
308141586Simp
309141586Simp		/*
310141586Simp		 * Enable the interrupt.
311141586Simp		 */
312141586Simp		ed_asic_outb(sc, ED_WD_IRR,
313141586Simp		     ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN);
314141586Simp	}
315141586Simp	if (sc->chip_type == ED_CHIP_TYPE_WD790) {
316141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
317141586Simp		  ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
318141586Simp		iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
319141586Simp			(ed_asic_inb(sc, ED_WD790_GCR) &
320141586Simp			 (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2);
321141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
322141586Simp		    ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
323141586Simp
324141586Simp		/*
325141586Simp		 * If no interrupt specified (or "?"), use what the board tells us.
326141586Simp		 */
327141586Simp		error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
328141586Simp		if (error && intr_vals[1] != NULL)
329141586Simp			error = bus_set_resource(dev, SYS_RES_IRQ, 0,
330141586Simp			  intr_vals[1][iptr], 1);
331141586Simp		if (error)
332141586Simp			return (error);
333141586Simp
334141586Simp		/*
335141586Simp		 * Enable interrupts.
336141586Simp		 */
337141586Simp		ed_asic_outb(sc, ED_WD790_ICR,
338141586Simp		  ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL);
339141586Simp	}
340141586Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
341141586Simp	if (error) {
342141586Simp		device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n",
343141586Simp			      sc->type_str);
344141586Simp		return (ENXIO);
345141586Simp	}
346141586Simp	sc->isa16bit = isa16bit;
347141586Simp	sc->mem_shared = 1;
348141586Simp
349141586Simp	/*
350141586Simp	 * allocate one xmit buffer if < 16k, two buffers otherwise
351141586Simp	 */
352141586Simp	if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
353141586Simp		sc->txb_cnt = 1;
354141586Simp	else
355141586Simp		sc->txb_cnt = 2;
356141586Simp	sc->tx_page_start = ED_WD_PAGE_OFFSET;
357141586Simp	sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt;
358141586Simp	sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE;
359141586Simp	sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start);
360141586Simp	sc->mem_size = memsize;
361141586Simp	sc->mem_end = sc->mem_start + memsize;
362141586Simp
363141586Simp	/*
364141586Simp	 * Get station address from on-board ROM
365141586Simp	 */
366141586Simp	for (i = 0; i < ETHER_ADDR_LEN; ++i)
367147256Sbrooks		sc->enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i);
368141586Simp
369141586Simp	/*
370141586Simp	 * Set upper address bits and 8/16 bit access to shared memory.
371141586Simp	 */
372141586Simp	if (isa16bit) {
373141586Simp		if (sc->chip_type == ED_CHIP_TYPE_WD790)
374141586Simp			sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR);
375141586Simp		else
376141586Simp			sc->wd_laar_proto = ED_WD_LAAR_L16EN |
377141586Simp			    ((pmem >> 19) & ED_WD_LAAR_ADDRHI);
378141586Simp		/*
379141586Simp		 * Enable 16bit access
380141586Simp		 */
381141586Simp		ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto |
382141586Simp		    ED_WD_LAAR_M16EN);
383141586Simp	} else {
384141586Simp		if (((sc->type & ED_WD_SOFTCONFIG) ||
385141586Simp		     (sc->type == ED_TYPE_TOSHIBA1) ||
386141586Simp		     (sc->type == ED_TYPE_TOSHIBA4) ||
387141586Simp		     (sc->type == ED_TYPE_WD8013EBT)) &&
388141586Simp		    (sc->chip_type != ED_CHIP_TYPE_WD790)) {
389141586Simp			sc->wd_laar_proto = (pmem >> 19) &
390141586Simp			    ED_WD_LAAR_ADDRHI;
391141586Simp			ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto);
392141586Simp		}
393141586Simp	}
394141586Simp
395141586Simp	/*
396141586Simp	 * Set address and enable interface shared memory.
397141586Simp	 */
398141586Simp	if (sc->chip_type != ED_CHIP_TYPE_WD790) {
399141586Simp		if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) {
400141586Simp			ed_asic_outb(sc, ED_WD_MSR + 1,
401141586Simp			    ((pmem >> 8) & 0xe0) | 4);
402141586Simp			ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f));
403141586Simp			ed_asic_outb(sc, ED_WD_MSR,
404141586Simp			    ED_WD_MSR_MENB | ED_WD_MSR_POW);
405141586Simp		} else {
406141586Simp			ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) &
407141586Simp			    ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
408141586Simp		}
409141586Simp		sc->cr_proto = ED_CR_RD2;
410141586Simp	} else {
411141586Simp		ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB);
412141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
413141586Simp		    (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH));
414141586Simp		ed_asic_outb(sc, ED_WD790_RAR,
415141586Simp		    ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) |
416141586Simp		     (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0));
417141586Simp		ed_asic_outb(sc, ED_WD790_HWR,
418141586Simp		    (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH));
419141586Simp		sc->cr_proto = 0;
420141586Simp	}
421141586Simp
422141586Simp	/*
423141586Simp	 * Disable 16bit access to shared memory - we leave it
424141586Simp	 * disabled so that 1) machines reboot properly when the board
425141586Simp	 * is set 16 bit mode and there are conflicting 8bit
426141586Simp	 * devices/ROMS in the same 128k address space as this boards
427141586Simp	 * shared memory. and 2) so that other 8 bit devices with
428141586Simp	 * shared memory can be used in this 128k region, too.
429141586Simp	 */
430142200Simp	error = ed_clear_memory(dev);
431141586Simp	ed_disable_16bit_access(sc);
432154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
433142200Simp	return (error);
434141586Simp}
435141586Simp
436141586Simpint
437141586Simped_probe_WD80x3(device_t dev, int port_rid, int flags)
438141586Simp{
439141586Simp	struct ed_softc *sc = device_get_softc(dev);
440141586Simp	int	error;
441141586Simp	static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val};
442141586Simp
443141586Simp	error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS);
444141586Simp	if (error)
445141586Simp		return (error);
446141586Simp
447141586Simp	sc->asic_offset = ED_WD_ASIC_OFFSET;
448141586Simp	sc->nic_offset  = ED_WD_NIC_OFFSET;
449141586Simp
450141586Simp	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
451141586Simp}
452