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