]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ed/if_ed_wd80x3.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / ed / if_ed_wd80x3.c
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$");
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
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                 /*
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         sc->sc_write_mbufs = ed_shmem_write_mbufs;
432         return (error);
433 }
434
435 int
436 ed_probe_WD80x3(device_t dev, int port_rid, int flags)
437 {
438         struct ed_softc *sc = device_get_softc(dev);
439         int     error;
440         static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val};
441
442         error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS);
443         if (error)
444                 return (error);
445
446         sc->asic_offset = ED_WD_ASIC_OFFSET;
447         sc->nic_offset  = ED_WD_NIC_OFFSET;
448
449         return ed_probe_WD80x3_generic(dev, flags, intr_vals);
450 }