if_ex_isa.c revision 147256
1/*-
2 * Copyright (c) 2000 Matthew N. Dodd
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/ex/if_ex_isa.c 147256 2005-06-10 16:49:24Z brooks $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/socket.h>
35
36#include <sys/module.h>
37#include <sys/bus.h>
38
39#include <machine/bus.h>
40#include <machine/resource.h>
41#include <sys/rman.h>
42
43#include <net/if.h>
44#include <net/if_arp.h>
45#include <net/if_media.h>
46
47
48#include <isa/isavar.h>
49#include <isa/pnpvar.h>
50
51#include <dev/ex/if_exreg.h>
52#include <dev/ex/if_exvar.h>
53
54/* Bus Front End Functions */
55static void	ex_isa_identify(driver_t *, device_t);
56static int	ex_isa_probe(device_t);
57static int	ex_isa_attach(device_t);
58
59static int	ex_look_for_card(struct ex_softc *);
60
61#if 0
62static	void	ex_pnp_wakeup(void *);
63
64SYSINIT(ex_pnpwakeup, SI_SUB_CPU, SI_ORDER_ANY, ex_pnp_wakeup, NULL);
65#endif
66
67static device_method_t ex_isa_methods[] = {
68	/* Device interface */
69	DEVMETHOD(device_identify,	ex_isa_identify),
70	DEVMETHOD(device_probe,		ex_isa_probe),
71	DEVMETHOD(device_attach,	ex_isa_attach),
72	DEVMETHOD(device_detach,	ex_detach),
73
74	{ 0, 0 }
75};
76
77static driver_t ex_isa_driver = {
78	"ex",
79	ex_isa_methods,
80	sizeof(struct ex_softc),
81};
82
83DRIVER_MODULE(ex, isa, ex_isa_driver, ex_devclass, 0, 0);
84
85static struct isa_pnp_id ex_ids[] = {
86	{ 0x3110d425,	NULL },	/* INT1031 */
87	{ 0x3010d425,	NULL },	/* INT1030 */
88	{ 0,		NULL },
89};
90
91#if 0
92#define EX_PNP_WAKE		0x279
93
94static uint8_t ex_pnp_wake_seq[] =
95			{ 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
96			  0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
97			  0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
98			  0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43 };
99
100static void
101ex_pnp_wakeup (void * dummy)
102{
103	int	tmp;
104
105	if (bootverbose)
106		printf("ex_pnp_wakeup()\n");
107
108	outb(EX_PNP_WAKE, 0);
109	outb(EX_PNP_WAKE, 0);
110	for (tmp = 0; tmp < 32; tmp++) {
111		outb(EX_PNP_WAKE, ex_pnp_wake_seq[tmp]);
112	}
113}
114#endif
115
116/*
117 * Non-destructive identify.
118 */
119static void
120ex_isa_identify(driver_t *driver, device_t parent)
121{
122	device_t	child;
123	bus_addr_t	ioport;
124	u_char 		enaddr[6];
125	u_int		irq;
126	int		tmp;
127	const char *	desc;
128	struct ex_softc sc;
129	struct resource *res;
130	int		rid;
131
132	if (bootverbose)
133		printf("ex_isa_identify()\n");
134
135	for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) {
136		rid = 0;
137		res = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid,
138		    ioport, ioport, 0x10, RF_ACTIVE);
139		if (res == NULL)
140			continue;
141		sc.bst = rman_get_bustag(res);
142		sc.bsh = rman_get_bushandle(res);
143
144		/* No board found at address */
145		if (!ex_look_for_card(&sc)) {
146			bus_release_resource(parent, SYS_RES_IOPORT, rid, res);
147			continue;
148		}
149
150		if (bootverbose)
151			printf("ex: Found card at 0x%03lx!\n", (unsigned long)ioport);
152
153		/* Board in PnP mode */
154		if (ex_eeprom_read(&sc, EE_W0) & EE_W0_PNP) {
155			/* Reset the card. */
156			CSR_WRITE_1(&sc, CMD_REG, Reset_CMD);
157			DELAY(500);
158			if (bootverbose)
159				printf("ex: card at 0x%03lx in PnP mode!\n", (unsigned long)ioport);
160			bus_release_resource(parent, SYS_RES_IOPORT, rid, res);
161			continue;
162		}
163
164		bzero(enaddr, sizeof(enaddr));
165
166		/* Reset the card. */
167		CSR_WRITE_1(&sc, CMD_REG, Reset_CMD);
168		DELAY(400);
169
170		ex_get_address(&sc, enaddr);
171		tmp = ex_eeprom_read(&sc, EE_W1) & EE_W1_INT_SEL;
172
173		/* work out which set of irq <-> internal tables to use */
174		if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
175			irq  = plus_ee2irqmap[tmp];
176			desc = "Intel Pro/10+";
177		} else {
178			irq = ee2irqmap[tmp];
179			desc = "Intel Pro/10";
180		}
181
182		bus_release_resource(parent, SYS_RES_IOPORT, rid, res);
183		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1);
184		device_set_desc_copy(child, desc);
185		device_set_driver(child, driver);
186		bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
187		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE);
188		if (bootverbose)
189			printf("ex: Adding board at 0x%03lx, irq %d\n",
190			   (unsigned long)ioport, irq);
191	}
192
193	return;
194}
195
196static int
197ex_isa_probe(device_t dev)
198{
199	bus_addr_t	iobase;
200	u_int		irq;
201	char *		irq2ee;
202	u_char *	ee2irq;
203	u_char 		enaddr[6];
204	int		tmp;
205	int		error;
206	struct ex_softc *sc = device_get_softc(dev);
207
208	/* Check isapnp ids */
209	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids);
210
211	/* If the card had a PnP ID that didn't match any we know about */
212	if (error == ENXIO)
213		return(error);
214
215	/* If we had some other problem. */
216	if (!(error == 0 || error == ENOENT))
217		return(error);
218
219	error = ex_alloc_resources(dev);
220	if (error != 0)
221		goto bad;
222	iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
223	if (!ex_look_for_card(sc)) {
224		if (bootverbose)
225			printf("ex: no card found at 0x%03lx.\n", (unsigned long)iobase);
226		error = ENXIO;
227		goto bad;
228	}
229	if (bootverbose)
230		printf("ex: ex_isa_probe() found card at 0x%03lx\n", (unsigned long)iobase);
231
232	/*
233	 * Reset the card.
234	 */
235	CSR_WRITE_1(sc, CMD_REG, Reset_CMD);
236	DELAY(800);
237
238	ex_get_address(sc, enaddr);
239
240	/* work out which set of irq <-> internal tables to use */
241	if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
242		irq2ee = plus_irq2eemap;
243		ee2irq = plus_ee2irqmap;
244	} else {
245		irq2ee = irq2eemap;
246		ee2irq = ee2irqmap;
247	}
248
249	tmp = ex_eeprom_read(sc, EE_W1) & EE_W1_INT_SEL;
250	irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
251
252	if (irq > 0) {
253		/* This will happen if board is in PnP mode. */
254		if (ee2irq[tmp] != irq) {
255			printf("ex: WARNING: board's EEPROM is configured"
256				" for IRQ %d, using %d\n",
257				ee2irq[tmp], irq);
258		}
259	} else {
260		irq = ee2irq[tmp];
261		bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
262	}
263
264	if (irq == 0) {
265		printf("ex: invalid IRQ.\n");
266		error = ENXIO;
267	}
268
269bad:;
270	ex_release_resources(dev);
271	return(error);
272}
273
274static int
275ex_isa_attach(device_t dev)
276{
277	struct ex_softc *	sc = device_get_softc(dev);
278	int			error = 0;
279	uint16_t		temp;
280
281	sc->dev = dev;
282	sc->ioport_rid = 0;
283	sc->irq_rid = 0;
284
285	if ((error = ex_alloc_resources(dev)) != 0) {
286		device_printf(dev, "ex_alloc_resources() failed!\n");
287		goto bad;
288	}
289
290	/*
291	 * Fill in several fields of the softc structure:
292	 *	- I/O base address.
293	 *	- Hardware Ethernet address.
294	 *	- IRQ number (if not supplied in config file, read it from EEPROM).
295	 *	- Connector type.
296	 */
297	sc->irq_no = rman_get_start(sc->irq);
298
299	ex_get_address(sc, sc->enaddr);
300
301	temp = ex_eeprom_read(sc, EE_W0);
302	device_printf(sc->dev, "%s config, %s bus, ",
303		(temp & EE_W0_PNP) ? "PnP" : "Manual",
304		(temp & EE_W0_BUS16) ? "16-bit" : "8-bit");
305
306	temp = ex_eeprom_read(sc, EE_W6);
307	printf("board id 0x%03x, stepping 0x%01x\n",
308		(temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT,
309		temp & EE_W6_STEP_MASK);
310
311	if ((error = ex_attach(dev)) != 0) {
312		device_printf(dev, "ex_attach() failed!\n");
313		goto bad;
314	}
315
316	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
317				ex_intr, (void *)sc, &sc->ih);
318	if (error) {
319		device_printf(dev, "bus_setup_intr() failed!\n");
320		goto bad;
321	}
322
323	return(0);
324bad:
325	ex_release_resources(dev);
326	return (error);
327}
328
329static int
330ex_look_for_card(struct ex_softc *sc)
331{
332	int count1, count2;
333
334	/*
335	 * Check for the i82595 signature, and check that the round robin
336	 * counter actually advances.
337	 */
338	if (((count1 = CSR_READ_1(sc, ID_REG)) & Id_Mask) != Id_Sig)
339		return(0);
340	count2 = CSR_READ_1(sc, ID_REG);
341	count2 = CSR_READ_1(sc, ID_REG);
342	count2 = CSR_READ_1(sc, ID_REG);
343
344	return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
345}
346