xref: /freebsd/sys/dev/le/if_le_isa.c (revision 1669d8afc64812c8d2d1d147ae1fd42ff441e1b1)
1 /*	$NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9  * Simulation Facility, NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*-
41  * Copyright (c) 1992, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * This code is derived from software contributed to Berkeley by
45  * Ralph Campbell and Rick Macklem.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  *
71  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
72  */
73 
74 #include <sys/cdefs.h>
75 __FBSDID("$FreeBSD$");
76 
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/bus.h>
80 #include <sys/endian.h>
81 #include <sys/kernel.h>
82 #include <sys/lock.h>
83 #include <sys/module.h>
84 #include <sys/mutex.h>
85 #include <sys/resource.h>
86 #include <sys/rman.h>
87 #include <sys/socket.h>
88 
89 #include <net/ethernet.h>
90 #include <net/if.h>
91 #include <net/if_media.h>
92 
93 #include <machine/bus.h>
94 #include <machine/resource.h>
95 
96 #include <isa/isavar.h>
97 
98 #include <dev/le/lancereg.h>
99 #include <dev/le/lancevar.h>
100 #include <dev/le/am7990var.h>
101 
102 #define	LE_ISA_MEMSIZE	(16*1024)
103 #define	PCNET_RDP	0x10
104 #define	PCNET_RAP	0x12
105 
106 struct le_isa_softc {
107 	struct am7990_softc	sc_am7990;	/* glue to MI code */
108 
109 	bus_size_t		sc_rap;		/* offsets to LANCE... */
110 	bus_size_t		sc_rdp;		/* ...registers */
111 
112 	int			sc_rrid;
113 	struct resource		*sc_rres;
114 	bus_space_tag_t		sc_regt;
115 	bus_space_handle_t	sc_regh;
116 
117 	int			sc_drid;
118 	struct resource		*sc_dres;
119 
120 	int			sc_irid;
121 	struct resource		*sc_ires;
122 	void			*sc_ih;
123 
124 	bus_dma_tag_t		sc_pdmat;
125 	bus_dma_tag_t		sc_dmat;
126 	bus_dmamap_t		sc_dmam;
127 };
128 
129 static device_probe_t le_isa_probe;
130 static device_attach_t le_isa_attach;
131 static device_detach_t le_isa_detach;
132 static device_resume_t le_isa_resume;
133 static device_suspend_t le_isa_suspend;
134 
135 static device_method_t le_isa_methods[] = {
136 	/* Device interface */
137 	DEVMETHOD(device_probe,		le_isa_probe),
138 	DEVMETHOD(device_attach,	le_isa_attach),
139 	DEVMETHOD(device_detach,	le_isa_detach),
140 	/* We can just use the suspend method here. */
141 	DEVMETHOD(device_shutdown,	le_isa_suspend),
142 	DEVMETHOD(device_suspend,	le_isa_suspend),
143 	DEVMETHOD(device_resume,	le_isa_resume),
144 
145 	{ 0, 0 }
146 };
147 
148 DEFINE_CLASS_0(le, le_isa_driver, le_isa_methods, sizeof(struct le_isa_softc));
149 DRIVER_MODULE(le, isa, le_isa_driver, le_devclass, 0, 0);
150 MODULE_DEPEND(le, ether, 1, 1, 1);
151 
152 struct le_isa_param {
153 	const char	*name;
154 	u_long		iosize;
155 	bus_size_t	rap;
156 	bus_size_t	rdp;
157 	bus_size_t	macstart;
158 	int		macstride;
159 } static const le_isa_params[] = {
160 	{ "BICC Isolan", 24, 0xe, 0xc, 0, 2 },
161 	{ "Novell NE2100", 16, 0x12, 0x10, 0, 1 }
162 };
163 
164 static struct isa_pnp_id le_isa_ids[] = {
165 	{ 0x0322690e, "Cabletron E2200 Single Chip" },	/* CSI2203 */
166 	{ 0x0110490a, "Boca LANCard Combo" },		/* BRI1001 */
167 	{ 0x0100a60a, "Melco Inc. LGY-IV" },		/* BUF0001 */
168 	{ 0xd880d041, "Novell NE2100" },		/* PNP80D8 */
169 	{ 0x0082d041, "Cabletron E2100 Series DNI" },	/* PNP8200 */
170 	{ 0x3182d041, "AMD AM1500T/AM2100" },		/* PNP8231 */
171 	{ 0x8c82d041, "AMD PCnet-ISA" },		/* PNP828C */
172 	{ 0x8d82d041, "AMD PCnet-32" },			/* PNP828D */
173 	{ 0xcefaedfe, "Racal InterLan EtherBlaster" },	/* _WMFACE */
174 	{ 0, NULL }
175 };
176 
177 static void le_isa_wrcsr(struct lance_softc *, uint16_t, uint16_t);
178 static uint16_t le_isa_rdcsr(struct lance_softc *, uint16_t);
179 static bus_dmamap_callback_t le_isa_dma_callback;
180 static int le_isa_probe_legacy(device_t, const struct le_isa_param *);
181 
182 static void
183 le_isa_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
184 {
185 	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
186 
187 	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, port);
188 	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, 2,
189 	    BUS_SPACE_BARRIER_WRITE);
190 	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rdp, val);
191 }
192 
193 static uint16_t
194 le_isa_rdcsr(struct lance_softc *sc, uint16_t port)
195 {
196 	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
197 
198 	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, port);
199 	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, 2,
200 	    BUS_SPACE_BARRIER_WRITE);
201 	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rdp));
202 }
203 
204 static void
205 le_isa_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
206 {
207 	struct lance_softc *sc = (struct lance_softc *)xsc;
208 
209 	if (error != 0)
210 		return;
211 	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
212 	sc->sc_addr = segs[0].ds_addr;
213 }
214 
215 static int
216 le_isa_probe_legacy(device_t dev, const struct le_isa_param *leip)
217 {
218 	struct le_isa_softc *lesc;
219 	struct lance_softc *sc;
220 	int error;
221 
222 	lesc = device_get_softc(dev);
223 	sc = &lesc->sc_am7990.lsc;
224 
225 	lesc->sc_rrid = 0;
226 	lesc->sc_rres = bus_alloc_resource(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
227 	    0, ~0, leip->iosize, RF_ACTIVE);
228 	if (lesc->sc_rres == NULL)
229 		return (ENXIO);
230 	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
231 	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
232 	lesc->sc_rap = leip->rap;
233 	lesc->sc_rdp = leip->rdp;
234 
235 	/* Stop the chip and put it in a known state. */
236 	le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
237 	DELAY(100);
238 	if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
239 		error = ENXIO;
240 		goto fail;
241 	}
242 	le_isa_wrcsr(sc, LE_CSR3, 0);
243 	error = 0;
244 
245  fail:
246 	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
247 	return (error);
248 }
249 
250 static int
251 le_isa_probe(device_t dev)
252 {
253 	int i;
254 
255 	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
256 	case 0:
257 		return (BUS_PROBE_DEFAULT);
258 	case ENOENT:
259 		for (i = 0; i < sizeof(le_isa_params) /
260 		    sizeof(le_isa_params[0]); i++) {
261 			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
262 				device_set_desc(dev, le_isa_params[i].name);
263 				return (BUS_PROBE_DEFAULT);
264 			}
265 		}
266 		/* FALLTHROUGH */
267 	case ENXIO:
268 	default:
269 		return (ENXIO);
270 	}
271 }
272 
273 static int
274 le_isa_attach(device_t dev)
275 {
276 	struct le_isa_softc *lesc;
277 	struct lance_softc *sc;
278 	bus_size_t macstart, rap, rdp;
279 	int error, i, macstride;
280 
281 	lesc = device_get_softc(dev);
282 	sc = &lesc->sc_am7990.lsc;
283 
284 	LE_LOCK_INIT(sc, device_get_nameunit(dev));
285 
286 	lesc->sc_rrid = 0;
287 	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
288 	case 0:
289 		lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
290 		    &lesc->sc_rrid, RF_ACTIVE);
291 		rap = PCNET_RAP;
292 		rdp = PCNET_RDP;
293 		macstart = 0;
294 		macstride = 1;
295 		break;
296 	case ENOENT:
297 		for (i = 0; i < sizeof(le_isa_params) /
298 		    sizeof(le_isa_params[0]); i++) {
299 			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
300 				lesc->sc_rres = bus_alloc_resource(dev,
301 				    SYS_RES_IOPORT, &lesc->sc_rrid, 0, ~0,
302 				    le_isa_params[i].iosize, RF_ACTIVE);
303 				rap = le_isa_params[i].rap;
304 				rdp = le_isa_params[i].rdp;
305 				macstart = le_isa_params[i].macstart;
306 				macstride = le_isa_params[i].macstride;
307 				goto found;
308 			}
309 		}
310 		/* FALLTHROUGH */
311 	case ENXIO:
312 	default:
313 		device_printf(dev, "cannot determine chip\n");
314 		error = ENXIO;
315 		goto fail_mtx;
316 	}
317 
318  found:
319 	if (lesc->sc_rres == NULL) {
320 		device_printf(dev, "cannot allocate registers\n");
321 		error = ENXIO;
322 		goto fail_mtx;
323 	}
324 	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
325 	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
326 	lesc->sc_rap = rap;
327 	lesc->sc_rdp = rdp;
328 
329 	lesc->sc_drid = 0;
330 	if ((lesc->sc_dres = bus_alloc_resource_any(dev, SYS_RES_DRQ,
331 	    &lesc->sc_drid, RF_ACTIVE)) == NULL) {
332 		device_printf(dev, "cannot allocate DMA channel\n");
333 		error = ENXIO;
334 		goto fail_rres;
335 	}
336 
337 	lesc->sc_irid = 0;
338 	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
339 	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
340 		device_printf(dev, "cannot allocate interrupt\n");
341 		error = ENXIO;
342 		goto fail_dres;
343 	}
344 
345 	error = bus_dma_tag_create(
346 	    bus_get_dma_tag(dev),	/* parent */
347 	    1, 0,			/* alignment, boundary */
348 	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
349 	    BUS_SPACE_MAXADDR,		/* highaddr */
350 	    NULL, NULL,			/* filter, filterarg */
351 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
352 	    0,				/* nsegments */
353 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
354 	    0,				/* flags */
355 	    NULL, NULL,			/* lockfunc, lockarg */
356 	    &lesc->sc_pdmat);
357 	if (error != 0) {
358 		device_printf(dev, "cannot allocate parent DMA tag\n");
359 		goto fail_ires;
360 	}
361 
362 	sc->sc_memsize = LE_ISA_MEMSIZE;
363 	/*
364 	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
365 	 * aligned and the ring descriptors must be 8-byte aligned.
366 	 */
367 	error = bus_dma_tag_create(
368 	    lesc->sc_pdmat,		/* parent */
369 	    8, 0,			/* alignment, boundary */
370 	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
371 	    BUS_SPACE_MAXADDR,		/* highaddr */
372 	    NULL, NULL,			/* filter, filterarg */
373 	    sc->sc_memsize,		/* maxsize */
374 	    1,				/* nsegments */
375 	    sc->sc_memsize,		/* maxsegsize */
376 	    0,				/* flags */
377 	    NULL, NULL,			/* lockfunc, lockarg */
378 	    &lesc->sc_dmat);
379 	if (error != 0) {
380 		device_printf(dev, "cannot allocate buffer DMA tag\n");
381 		goto fail_pdtag;
382 	}
383 
384 	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
385 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
386 	if (error != 0) {
387 		device_printf(dev, "cannot allocate DMA buffer memory\n");
388 		goto fail_dtag;
389 	}
390 
391 	sc->sc_addr = 0;
392 	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
393 	    sc->sc_memsize, le_isa_dma_callback, sc, 0);
394 	if (error != 0 || sc->sc_addr == 0) {
395                 device_printf(dev, "cannot load DMA buffer map\n");
396 		goto fail_dmem;
397 	}
398 
399 	isa_dmacascade(rman_get_start(lesc->sc_dres));
400 
401 	sc->sc_flags = 0;
402 	sc->sc_conf3 = 0;
403 
404 	/*
405 	 * Extract the physical MAC address from the ROM.
406 	 */
407 	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
408 		sc->sc_enaddr[i] =  bus_space_read_1(lesc->sc_regt,
409 		    lesc->sc_regh, macstart + i * macstride);
410 
411 	sc->sc_copytodesc = lance_copytobuf_contig;
412 	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
413 	sc->sc_copytobuf = lance_copytobuf_contig;
414 	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
415 	sc->sc_zerobuf = lance_zerobuf_contig;
416 
417 	sc->sc_rdcsr = le_isa_rdcsr;
418 	sc->sc_wrcsr = le_isa_wrcsr;
419 	sc->sc_hwreset = NULL;
420 	sc->sc_hwinit = NULL;
421 	sc->sc_hwintr = NULL;
422 	sc->sc_nocarrier = NULL;
423 	sc->sc_mediachange = NULL;
424 	sc->sc_mediastatus = NULL;
425 	sc->sc_supmedia = NULL;
426 
427 	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
428 	    device_get_unit(dev));
429 	if (error != 0) {
430 		device_printf(dev, "cannot attach Am7990\n");
431 		goto fail_dmap;
432 	}
433 
434 	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
435 	    NULL, am7990_intr, sc, &lesc->sc_ih);
436 	if (error != 0) {
437 		device_printf(dev, "cannot set up interrupt\n");
438 		goto fail_am7990;
439 	}
440 
441 	return (0);
442 
443  fail_am7990:
444 	am7990_detach(&lesc->sc_am7990);
445  fail_dmap:
446 	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
447  fail_dmem:
448 	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
449  fail_dtag:
450 	bus_dma_tag_destroy(lesc->sc_dmat);
451  fail_pdtag:
452 	bus_dma_tag_destroy(lesc->sc_pdmat);
453  fail_ires:
454 	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
455  fail_dres:
456 	bus_release_resource(dev, SYS_RES_DRQ, lesc->sc_drid, lesc->sc_dres);
457  fail_rres:
458 	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
459  fail_mtx:
460 	LE_LOCK_DESTROY(sc);
461 	return (error);
462 }
463 
464 static int
465 le_isa_detach(device_t dev)
466 {
467 	struct le_isa_softc *lesc;
468 	struct lance_softc *sc;
469 
470 	lesc = device_get_softc(dev);
471 	sc = &lesc->sc_am7990.lsc;
472 
473 	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
474 	am7990_detach(&lesc->sc_am7990);
475 	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
476 	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
477 	bus_dma_tag_destroy(lesc->sc_dmat);
478 	bus_dma_tag_destroy(lesc->sc_pdmat);
479 	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
480 	bus_release_resource(dev, SYS_RES_DRQ, lesc->sc_drid, lesc->sc_dres);
481 	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
482 	LE_LOCK_DESTROY(sc);
483 
484 	return (0);
485 }
486 
487 static int
488 le_isa_suspend(device_t dev)
489 {
490 	struct le_isa_softc *lesc;
491 
492 	lesc = device_get_softc(dev);
493 
494 	lance_suspend(&lesc->sc_am7990.lsc);
495 
496 	return (0);
497 }
498 
499 static int
500 le_isa_resume(device_t dev)
501 {
502 	struct le_isa_softc *lesc;
503 
504 	lesc = device_get_softc(dev);
505 
506 	lance_resume(&lesc->sc_am7990.lsc);
507 
508 	return (0);
509 }
510