]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/ed/if_ed_3c503.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / ed / if_ed_3c503.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 #ifdef ED_3C503
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 static void ed_3c503_mediachg(struct ed_softc *sc);
64
65 /*
66  * Probe and vendor-specific initialization routine for 3Com 3c503 boards
67  */
68 int
69 ed_probe_3Com(device_t dev, int port_rid, int flags)
70 {
71         struct ed_softc *sc = device_get_softc(dev);
72         int     error;
73         int     i;
74         u_int   memsize;
75         u_char  isa16bit;
76         u_long  conf_maddr, conf_msize, irq, junk, pmem;
77
78         error = ed_alloc_port(dev, 0, ED_3COM_IO_PORTS);
79         if (error)
80                 return (error);
81
82         sc->asic_offset = ED_3COM_ASIC_OFFSET;
83         sc->nic_offset  = ED_3COM_NIC_OFFSET;
84
85         /*
86          * Verify that the kernel configured I/O address matches the board
87          * configured address
88          */
89         switch (ed_asic_inb(sc, ED_3COM_BCFR)) {
90         case ED_3COM_BCFR_300:
91                 if (rman_get_start(sc->port_res) != 0x300)
92                         return (ENXIO);
93                 break;
94         case ED_3COM_BCFR_310:
95                 if (rman_get_start(sc->port_res) != 0x310)
96                         return (ENXIO);
97                 break;
98         case ED_3COM_BCFR_330:
99                 if (rman_get_start(sc->port_res) != 0x330)
100                         return (ENXIO);
101                 break;
102         case ED_3COM_BCFR_350:
103                 if (rman_get_start(sc->port_res) != 0x350)
104                         return (ENXIO);
105                 break;
106         case ED_3COM_BCFR_250:
107                 if (rman_get_start(sc->port_res) != 0x250)
108                         return (ENXIO);
109                 break;
110         case ED_3COM_BCFR_280:
111                 if (rman_get_start(sc->port_res) != 0x280)
112                         return (ENXIO);
113                 break;
114         case ED_3COM_BCFR_2A0:
115                 if (rman_get_start(sc->port_res) != 0x2a0)
116                         return (ENXIO);
117                 break;
118         case ED_3COM_BCFR_2E0:
119                 if (rman_get_start(sc->port_res) != 0x2e0)
120                         return (ENXIO);
121                 break;
122         default:
123                 return (ENXIO);
124         }
125
126         error = bus_get_resource(dev, SYS_RES_MEMORY, 0,
127                                  &conf_maddr, &conf_msize);
128         if (error)
129                 return (error);
130
131         /*
132          * Verify that the kernel shared memory address matches the board
133          * configured address.
134          */
135         switch (ed_asic_inb(sc, ED_3COM_PCFR)) {
136         case ED_3COM_PCFR_DC000:
137                 if (conf_maddr != 0xdc000)
138                         return (ENXIO);
139                 break;
140         case ED_3COM_PCFR_D8000:
141                 if (conf_maddr != 0xd8000)
142                         return (ENXIO);
143                 break;
144         case ED_3COM_PCFR_CC000:
145                 if (conf_maddr != 0xcc000)
146                         return (ENXIO);
147                 break;
148         case ED_3COM_PCFR_C8000:
149                 if (conf_maddr != 0xc8000)
150                         return (ENXIO);
151                 break;
152         default:
153                 return (ENXIO);
154         }
155
156
157         /*
158          * Reset NIC and ASIC. Enable on-board transceiver throughout reset
159          * sequence because it'll lock up if the cable isn't connected if we
160          * don't.
161          */
162         ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
163
164         /*
165          * Wait for a while, then un-reset it
166          */
167         DELAY(50);
168
169         /*
170          * The 3Com ASIC defaults to rather strange settings for the CR after
171          * a reset - it's important to set it again after the following outb
172          * (this is done when we map the PROM below).
173          */
174         ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL);
175
176         /*
177          * Wait a bit for the NIC to recover from the reset
178          */
179         DELAY(5000);
180
181         sc->vendor = ED_VENDOR_3COM;
182         sc->type_str = "3c503";
183         sc->mem_shared = 1;
184         sc->cr_proto = ED_CR_RD2;
185
186         /*
187          * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window
188          * to it.
189          */
190         memsize = 8192;
191
192         /*
193          * Get station address from on-board ROM
194          */
195
196         /*
197          * First, map ethernet address PROM over the top of where the NIC
198          * registers normally appear.
199          */
200         ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
201
202         for (i = 0; i < ETHER_ADDR_LEN; ++i)
203                 sc->enaddr[i] = ed_nic_inb(sc, i);
204
205         /*
206          * Unmap PROM - select NIC registers. The proper setting of the
207          * tranceiver is set in ed_init so that the attach code is given a
208          * chance to set the default based on a compile-time config option
209          */
210         ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL);
211
212         /*
213          * Determine if this is an 8bit or 16bit board
214          */
215
216         /*
217          * select page 0 registers
218          */
219         ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
220
221         /*
222          * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit
223          * board.
224          */
225         ed_nic_outb(sc, ED_P0_DCR, 0);
226
227         /*
228          * select page 2 registers
229          */
230         ed_nic_outb(sc, ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP);
231
232         /*
233          * The 3c503 forces the WTS bit to a one if this is a 16bit board
234          */
235         if (ed_nic_inb(sc, ED_P2_DCR) & ED_DCR_WTS)
236                 isa16bit = 1;
237         else
238                 isa16bit = 0;
239
240         /*
241          * select page 0 registers
242          */
243         ed_nic_outb(sc, ED_P2_CR, ED_CR_RD2 | ED_CR_STP);
244
245         error = ed_alloc_memory(dev, 0, memsize);
246         if (error)
247                 return (error);
248
249         pmem = rman_get_start(sc->mem_res);
250         error = ed_isa_mem_ok(dev, pmem, memsize);
251         if (error)
252                 return (error);
253
254         sc->mem_start = 0;
255         sc->mem_size = memsize;
256         sc->mem_end = sc->mem_start + memsize;
257
258         /*
259          * We have an entire 8k window to put the transmit buffers on the
260          * 16bit boards. But since the 16bit 3c503's shared memory is only
261          * fast enough to overlap the loading of one full-size packet, trying
262          * to load more than 2 buffers can actually leave the transmitter idle
263          * during the load. So 2 seems the best value. (Although a mix of
264          * variable-sized packets might change this assumption. Nonetheless,
265          * we optimize for linear transfers of same-size packets.)
266          */
267         if (isa16bit) {
268                 if (flags & ED_FLAGS_NO_MULTI_BUFFERING)
269                         sc->txb_cnt = 1;
270                 else
271                         sc->txb_cnt = 2;
272
273                 sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
274                 sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
275                 sc->rec_page_stop = memsize / ED_PAGE_SIZE +
276                     ED_3COM_RX_PAGE_OFFSET_16BIT;
277                 sc->mem_ring = sc->mem_start;
278         } else {
279                 sc->txb_cnt = 1;
280                 sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
281                 sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
282                 sc->rec_page_stop = memsize / ED_PAGE_SIZE +
283                     ED_3COM_TX_PAGE_OFFSET_8BIT;
284                 sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
285         }
286
287         sc->isa16bit = isa16bit;
288
289         /*
290          * Initialize GA page start/stop registers. Probably only needed if
291          * doing DMA, but what the hell.
292          */
293         ed_asic_outb(sc, ED_3COM_PSTR, sc->rec_page_start);
294         ed_asic_outb(sc, ED_3COM_PSPR, sc->rec_page_stop);
295
296         /*
297          * Set IRQ. 3c503 only allows a choice of irq 2-5.
298          */
299         error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
300         if (error)
301                 return (error);
302
303         switch (irq) {
304         case 2:
305         case 9:
306                 ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
307                 break;
308         case 3:
309                 ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
310                 break;
311         case 4:
312                 ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
313                 break;
314         case 5:
315                 ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
316                 break;
317         default:
318                 device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n",
319                               irq);
320                 return (ENXIO);
321         }
322
323         /*
324          * Initialize GA configuration register. Set bank and enable shared
325          * mem.
326          */
327         ed_asic_outb(sc, ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
328             ED_3COM_GACFR_MBS0);
329
330         /*
331          * Initialize "Vector Pointer" registers. These gawd-awful things are
332          * compared to 20 bits of the address on ISA, and if they match, the
333          * shared memory is disabled. We set them to 0xffff0...allegedly the
334          * reset vector.
335          */
336         ed_asic_outb(sc, ED_3COM_VPTR2, 0xff);
337         ed_asic_outb(sc, ED_3COM_VPTR1, 0xff);
338         ed_asic_outb(sc, ED_3COM_VPTR0, 0x00);
339
340         error = ed_clear_memory(dev);
341         if (error == 0) {
342                 sc->sc_mediachg = ed_3c503_mediachg;
343                 sc->sc_write_mbufs = ed_shmem_write_mbufs;
344         }
345         return (error);
346 }
347
348 static void
349 ed_3c503_mediachg(struct ed_softc *sc)
350 {
351         struct ifnet *ifp = sc->ifp;
352
353         /*
354          * If this is a 3Com board, the tranceiver must be software enabled
355          * (there is no settable hardware default).
356          */
357         if (ifp->if_flags & IFF_LINK2)
358                 ed_asic_outb(sc, ED_3COM_CR, 0);
359         else
360                 ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL);
361 }
362
363 #endif /* ED_3C503 */