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