Deleted Added
sdiff udiff text old ( 149558 ) new ( 154924 )
full compact
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: head/sys/dev/ed/if_ed_wd80x3.c 149558 2005-08-28 23:56:25Z 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 */
64static 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 */
78static 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 */
92int
93ed_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 /*
124 * Checksum is invalid. This often happens with cheap WD8003E
125 * clones. In this case, the checksum byte (the eighth byte)
126 * seems to always be zero.
127 */
128 if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
129 ed_asic_inb(sc, ED_WD_PROM + 7) != 0)
130 return (ENXIO);
131 }
132 /* reset card to force it into a known state. */
133 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER)
134 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
135 else
136 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST);
137
138 DELAY(100);
139 ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST);
140 /* wait in the case this card is reading its EEROM */
141 DELAY(5000);
142
143 sc->vendor = ED_VENDOR_WD_SMC;
144 sc->type = ed_asic_inb(sc, ED_WD_CARD_ID);
145
146 /*
147 * Set initial values for width/size.
148 */
149 memsize = 8192;
150 isa16bit = 0;
151 switch (sc->type) {
152 case ED_TYPE_WD8003S:
153 sc->type_str = "WD8003S";
154 break;
155 case ED_TYPE_WD8003E:
156 sc->type_str = "WD8003E";
157 break;
158 case ED_TYPE_WD8003EB:
159 sc->type_str = "WD8003EB";
160 break;
161 case ED_TYPE_WD8003W:
162 sc->type_str = "WD8003W";
163 break;
164 case ED_TYPE_WD8013EBT:
165 sc->type_str = "WD8013EBT";
166 memsize = 16384;
167 isa16bit = 1;
168 break;
169 case ED_TYPE_WD8013W:
170 sc->type_str = "WD8013W";
171 memsize = 16384;
172 isa16bit = 1;
173 break;
174 case ED_TYPE_WD8013EP: /* also WD8003EP */
175 if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) {
176 isa16bit = 1;
177 memsize = 16384;
178 sc->type_str = "WD8013EP";
179 } else
180 sc->type_str = "WD8003EP";
181 break;
182 case ED_TYPE_WD8013WC:
183 sc->type_str = "WD8013WC";
184 memsize = 16384;
185 isa16bit = 1;
186 break;
187 case ED_TYPE_WD8013EBP:
188 sc->type_str = "WD8013EBP";
189 memsize = 16384;
190 isa16bit = 1;
191 break;
192 case ED_TYPE_WD8013EPC:
193 sc->type_str = "WD8013EPC";
194 memsize = 16384;
195 isa16bit = 1;
196 break;
197 case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */
198 case ED_TYPE_SMC8216T:
199 if (sc->type == ED_TYPE_SMC8216C)
200 sc->type_str = "SMC8216/SMC8216C";
201 else
202 sc->type_str = "SMC8216T";
203
204 ed_asic_outb(sc, ED_WD790_HWR,
205 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
206 switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) {
207 case ED_WD790_RAR_SZ64:
208 memsize = 65536;
209 break;
210 case ED_WD790_RAR_SZ32:
211 memsize = 32768;
212 break;
213 case ED_WD790_RAR_SZ16:
214 memsize = 16384;
215 break;
216 case ED_WD790_RAR_SZ8:
217 /* 8216 has 16K shared mem -- 8416 has 8K */
218 if (sc->type == ED_TYPE_SMC8216C)
219 sc->type_str = "SMC8416C/SMC8416BT";
220 else
221 sc->type_str = "SMC8416T";
222 memsize = 8192;
223 break;
224 }
225 ed_asic_outb(sc, ED_WD790_HWR,
226 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
227
228 isa16bit = 1;
229 sc->chip_type = ED_CHIP_TYPE_WD790;
230 break;
231 case ED_TYPE_TOSHIBA1:
232 sc->type_str = "Toshiba1";
233 memsize = 32768;
234 isa16bit = 1;
235 break;
236 case ED_TYPE_TOSHIBA4:
237 sc->type_str = "Toshiba4";
238 memsize = 32768;
239 isa16bit = 1;
240 break;
241 default:
242 sc->type_str = "";
243 break;
244 }
245
246 /*
247 * Make some adjustments to initial values depending on what is found
248 * in the ICR.
249 */
250 if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
251 && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
252 && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
253 isa16bit = 0;
254 memsize = 8192;
255 }
256
257 /* Override memsize? XXX */
258 error = ed_alloc_memory(dev, 0, memsize);
259 if (error)
260 return (error);
261 sc->mem_start = 0;
262
263#ifdef ED_DEBUG
264 printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n",
265 sc->type, sc->type_str, isa16bit, memsize,
266 rman_get_size(sc->mem_res));
267 for (i = 0; i < 8; i++)
268 printf("%x -> %x\n", i, ed_asic_inb(sc, i));
269#endif
270 pmem = rman_get_start(sc->mem_res);
271 error = ed_isa_mem_ok(dev, pmem, memsize);
272 if (error)
273 return (error);
274
275 /*
276 * (note that if the user specifies both of the following flags that
277 * '8bit' mode intentionally has precedence)
278 */
279 if (flags & ED_FLAGS_FORCE_16BIT_MODE)
280 isa16bit = 1;
281 if (flags & ED_FLAGS_FORCE_8BIT_MODE)
282 isa16bit = 0;
283
284 /*
285 * If possible, get the assigned interrupt number from the card and
286 * use it.
287 */
288 if ((sc->type & ED_WD_SOFTCONFIG) &&
289 (sc->chip_type != ED_CHIP_TYPE_WD790)) {
290
291 /*
292 * Assemble together the encoded interrupt number.
293 */
294 iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) |
295 ((ed_asic_inb(sc, ED_WD_IRR) &
296 (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
297
298 /*
299 * If no interrupt specified (or "?"), use what the board tells us.
300 */
301 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
302 if (error && intr_vals[0] != NULL)
303 error = bus_set_resource(dev, SYS_RES_IRQ, 0,
304 intr_vals[0][iptr], 1);
305 if (error)
306 return (error);
307
308 /*
309 * Enable the interrupt.
310 */
311 ed_asic_outb(sc, ED_WD_IRR,
312 ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN);
313 }
314 if (sc->chip_type == ED_CHIP_TYPE_WD790) {
315 ed_asic_outb(sc, ED_WD790_HWR,
316 ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH);
317 iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
318 (ed_asic_inb(sc, ED_WD790_GCR) &
319 (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2);
320 ed_asic_outb(sc, ED_WD790_HWR,
321 ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
322
323 /*
324 * If no interrupt specified (or "?"), use what the board tells us.
325 */
326 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
327 if (error && intr_vals[1] != NULL)
328 error = bus_set_resource(dev, SYS_RES_IRQ, 0,
329 intr_vals[1][iptr], 1);
330 if (error)
331 return (error);
332
333 /*
334 * Enable interrupts.
335 */
336 ed_asic_outb(sc, ED_WD790_ICR,
337 ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL);
338 }
339 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
340 if (error) {
341 device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n",
342 sc->type_str);
343 return (ENXIO);
344 }
345 sc->isa16bit = isa16bit;
346 sc->mem_shared = 1;
347
348 /*
349 * allocate one xmit buffer if < 16k, two buffers otherwise
350 */
351 if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
352 sc->txb_cnt = 1;
353 else
354 sc->txb_cnt = 2;
355 sc->tx_page_start = ED_WD_PAGE_OFFSET;
356 sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt;
357 sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE;
358 sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start);
359 sc->mem_size = memsize;
360 sc->mem_end = sc->mem_start + memsize;
361
362 /*
363 * Get station address from on-board ROM
364 */
365 for (i = 0; i < ETHER_ADDR_LEN; ++i)
366 sc->enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i);
367
368 /*
369 * Set upper address bits and 8/16 bit access to shared memory.
370 */
371 if (isa16bit) {
372 if (sc->chip_type == ED_CHIP_TYPE_WD790)
373 sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR);
374 else
375 sc->wd_laar_proto = ED_WD_LAAR_L16EN |
376 ((pmem >> 19) & ED_WD_LAAR_ADDRHI);
377 /*
378 * Enable 16bit access
379 */
380 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto |
381 ED_WD_LAAR_M16EN);
382 } else {
383 if (((sc->type & ED_WD_SOFTCONFIG) ||
384 (sc->type == ED_TYPE_TOSHIBA1) ||
385 (sc->type == ED_TYPE_TOSHIBA4) ||
386 (sc->type == ED_TYPE_WD8013EBT)) &&
387 (sc->chip_type != ED_CHIP_TYPE_WD790)) {
388 sc->wd_laar_proto = (pmem >> 19) &
389 ED_WD_LAAR_ADDRHI;
390 ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto);
391 }
392 }
393
394 /*
395 * Set address and enable interface shared memory.
396 */
397 if (sc->chip_type != ED_CHIP_TYPE_WD790) {
398 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) {
399 ed_asic_outb(sc, ED_WD_MSR + 1,
400 ((pmem >> 8) & 0xe0) | 4);
401 ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f));
402 ed_asic_outb(sc, ED_WD_MSR,
403 ED_WD_MSR_MENB | ED_WD_MSR_POW);
404 } else {
405 ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) &
406 ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
407 }
408 sc->cr_proto = ED_CR_RD2;
409 } else {
410 ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB);
411 ed_asic_outb(sc, ED_WD790_HWR,
412 (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH));
413 ed_asic_outb(sc, ED_WD790_RAR,
414 ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) |
415 (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0));
416 ed_asic_outb(sc, ED_WD790_HWR,
417 (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH));
418 sc->cr_proto = 0;
419 }
420
421 /*
422 * Disable 16bit access to shared memory - we leave it
423 * disabled so that 1) machines reboot properly when the board
424 * is set 16 bit mode and there are conflicting 8bit
425 * devices/ROMS in the same 128k address space as this boards
426 * shared memory. and 2) so that other 8 bit devices with
427 * shared memory can be used in this 128k region, too.
428 */
429 error = ed_clear_memory(dev);
430 ed_disable_16bit_access(sc);
431 return (error);
432}
433
434int
435ed_probe_WD80x3(device_t dev, int port_rid, int flags)
436{
437 struct ed_softc *sc = device_get_softc(dev);
438 int error;
439 static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val};
440
441 error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS);
442 if (error)
443 return (error);
444
445 sc->asic_offset = ED_WD_ASIC_OFFSET;
446 sc->nic_offset = ED_WD_NIC_OFFSET;
447
448 return ed_probe_WD80x3_generic(dev, flags, intr_vals);
449}