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
64static void ed_3c503_mediachg(struct ed_softc *sc);
65
66/*
67 * Probe and vendor-specific initialization routine for 3Com 3c503 boards
68 */
69int
70ed_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	rman_res_t	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 (%jd) 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
357static void
358ed_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