]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ed/if_ed_wd80x3.c
libfdt: Update to 1.4.6, switch to using libfdt for overlay support
[FreeBSD/FreeBSD.git] / sys / dev / ed / if_ed_wd80x3.c
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$");
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
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
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 }