xref: /freebsd-src/sys/dev/le/if_le_isa.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1136eda1dSMarius Strobl /*	$NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $	*/
2136eda1dSMarius Strobl 
3136eda1dSMarius Strobl /*-
4*b61a5730SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause
5718cf2ccSPedro F. Giffuni  *
6136eda1dSMarius Strobl  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7136eda1dSMarius Strobl  * All rights reserved.
8136eda1dSMarius Strobl  *
9136eda1dSMarius Strobl  * This code is derived from software contributed to The NetBSD Foundation
10136eda1dSMarius Strobl  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
11136eda1dSMarius Strobl  * Simulation Facility, NASA Ames Research Center.
12136eda1dSMarius Strobl  *
13136eda1dSMarius Strobl  * Redistribution and use in source and binary forms, with or without
14136eda1dSMarius Strobl  * modification, are permitted provided that the following conditions
15136eda1dSMarius Strobl  * are met:
16136eda1dSMarius Strobl  * 1. Redistributions of source code must retain the above copyright
17136eda1dSMarius Strobl  *    notice, this list of conditions and the following disclaimer.
18136eda1dSMarius Strobl  * 2. Redistributions in binary form must reproduce the above copyright
19136eda1dSMarius Strobl  *    notice, this list of conditions and the following disclaimer in the
20136eda1dSMarius Strobl  *    documentation and/or other materials provided with the distribution.
21136eda1dSMarius Strobl  *
22136eda1dSMarius Strobl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23136eda1dSMarius Strobl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24136eda1dSMarius Strobl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25136eda1dSMarius Strobl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26136eda1dSMarius Strobl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27136eda1dSMarius Strobl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28136eda1dSMarius Strobl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29136eda1dSMarius Strobl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30136eda1dSMarius Strobl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31136eda1dSMarius Strobl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32136eda1dSMarius Strobl  * POSSIBILITY OF SUCH DAMAGE.
33136eda1dSMarius Strobl  */
34136eda1dSMarius Strobl 
35136eda1dSMarius Strobl /*-
36136eda1dSMarius Strobl  * Copyright (c) 1992, 1993
37136eda1dSMarius Strobl  *	The Regents of the University of California.  All rights reserved.
38136eda1dSMarius Strobl  *
39136eda1dSMarius Strobl  * This code is derived from software contributed to Berkeley by
40136eda1dSMarius Strobl  * Ralph Campbell and Rick Macklem.
41136eda1dSMarius Strobl  *
42136eda1dSMarius Strobl  * Redistribution and use in source and binary forms, with or without
43136eda1dSMarius Strobl  * modification, are permitted provided that the following conditions
44136eda1dSMarius Strobl  * are met:
45136eda1dSMarius Strobl  * 1. Redistributions of source code must retain the above copyright
46136eda1dSMarius Strobl  *    notice, this list of conditions and the following disclaimer.
47136eda1dSMarius Strobl  * 2. Redistributions in binary form must reproduce the above copyright
48136eda1dSMarius Strobl  *    notice, this list of conditions and the following disclaimer in the
49136eda1dSMarius Strobl  *    documentation and/or other materials provided with the distribution.
50136eda1dSMarius Strobl  * 3. Neither the name of the University nor the names of its contributors
51136eda1dSMarius Strobl  *    may be used to endorse or promote products derived from this software
52136eda1dSMarius Strobl  *    without specific prior written permission.
53136eda1dSMarius Strobl  *
54136eda1dSMarius Strobl  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55136eda1dSMarius Strobl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56136eda1dSMarius Strobl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57136eda1dSMarius Strobl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58136eda1dSMarius Strobl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59136eda1dSMarius Strobl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60136eda1dSMarius Strobl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61136eda1dSMarius Strobl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62136eda1dSMarius Strobl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63136eda1dSMarius Strobl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64136eda1dSMarius Strobl  * SUCH DAMAGE.
65136eda1dSMarius Strobl  */
66136eda1dSMarius Strobl 
67136eda1dSMarius Strobl #include <sys/param.h>
68136eda1dSMarius Strobl #include <sys/systm.h>
69136eda1dSMarius Strobl #include <sys/bus.h>
70136eda1dSMarius Strobl #include <sys/endian.h>
71136eda1dSMarius Strobl #include <sys/kernel.h>
72136eda1dSMarius Strobl #include <sys/lock.h>
73136eda1dSMarius Strobl #include <sys/module.h>
74136eda1dSMarius Strobl #include <sys/mutex.h>
75136eda1dSMarius Strobl #include <sys/resource.h>
76136eda1dSMarius Strobl #include <sys/rman.h>
77136eda1dSMarius Strobl #include <sys/socket.h>
78136eda1dSMarius Strobl 
79136eda1dSMarius Strobl #include <net/ethernet.h>
80136eda1dSMarius Strobl #include <net/if.h>
81136eda1dSMarius Strobl #include <net/if_media.h>
82136eda1dSMarius Strobl 
83136eda1dSMarius Strobl #include <machine/bus.h>
84136eda1dSMarius Strobl #include <machine/resource.h>
85136eda1dSMarius Strobl 
86136eda1dSMarius Strobl #include <isa/isavar.h>
87136eda1dSMarius Strobl 
88136eda1dSMarius Strobl #include <dev/le/lancereg.h>
89136eda1dSMarius Strobl #include <dev/le/lancevar.h>
90136eda1dSMarius Strobl #include <dev/le/am7990var.h>
91136eda1dSMarius Strobl 
92136eda1dSMarius Strobl #define	LE_ISA_MEMSIZE	(16*1024)
93136eda1dSMarius Strobl #define	PCNET_RDP	0x10
94136eda1dSMarius Strobl #define	PCNET_RAP	0x12
95136eda1dSMarius Strobl 
96136eda1dSMarius Strobl struct le_isa_softc {
97136eda1dSMarius Strobl 	struct am7990_softc	sc_am7990;	/* glue to MI code */
98136eda1dSMarius Strobl 
99136eda1dSMarius Strobl 	bus_size_t		sc_rap;		/* offsets to LANCE... */
100136eda1dSMarius Strobl 	bus_size_t		sc_rdp;		/* ...registers */
101136eda1dSMarius Strobl 
102136eda1dSMarius Strobl 	struct resource		*sc_rres;
103136eda1dSMarius Strobl 
104136eda1dSMarius Strobl 	struct resource		*sc_dres;
105136eda1dSMarius Strobl 
106136eda1dSMarius Strobl 	struct resource		*sc_ires;
107136eda1dSMarius Strobl 	void			*sc_ih;
108136eda1dSMarius Strobl 
109136eda1dSMarius Strobl 	bus_dma_tag_t		sc_pdmat;
110136eda1dSMarius Strobl 	bus_dma_tag_t		sc_dmat;
111136eda1dSMarius Strobl 	bus_dmamap_t		sc_dmam;
112136eda1dSMarius Strobl };
113136eda1dSMarius Strobl 
114136eda1dSMarius Strobl static device_probe_t le_isa_probe;
115136eda1dSMarius Strobl static device_attach_t le_isa_attach;
116136eda1dSMarius Strobl static device_detach_t le_isa_detach;
117136eda1dSMarius Strobl static device_resume_t le_isa_resume;
118136eda1dSMarius Strobl static device_suspend_t le_isa_suspend;
119136eda1dSMarius Strobl 
120136eda1dSMarius Strobl static device_method_t le_isa_methods[] = {
121136eda1dSMarius Strobl 	/* Device interface */
122136eda1dSMarius Strobl 	DEVMETHOD(device_probe,		le_isa_probe),
123136eda1dSMarius Strobl 	DEVMETHOD(device_attach,	le_isa_attach),
124136eda1dSMarius Strobl 	DEVMETHOD(device_detach,	le_isa_detach),
125136eda1dSMarius Strobl 	/* We can just use the suspend method here. */
126136eda1dSMarius Strobl 	DEVMETHOD(device_shutdown,	le_isa_suspend),
127136eda1dSMarius Strobl 	DEVMETHOD(device_suspend,	le_isa_suspend),
128136eda1dSMarius Strobl 	DEVMETHOD(device_resume,	le_isa_resume),
129136eda1dSMarius Strobl 
130136eda1dSMarius Strobl 	{ 0, 0 }
131136eda1dSMarius Strobl };
132136eda1dSMarius Strobl 
133136eda1dSMarius Strobl struct le_isa_param {
134136eda1dSMarius Strobl 	const char	*name;
135136eda1dSMarius Strobl 	u_long		iosize;
136136eda1dSMarius Strobl 	bus_size_t	rap;
137136eda1dSMarius Strobl 	bus_size_t	rdp;
138136eda1dSMarius Strobl 	bus_size_t	macstart;
139136eda1dSMarius Strobl 	int		macstride;
140136eda1dSMarius Strobl } static const le_isa_params[] = {
141136eda1dSMarius Strobl 	{ "BICC Isolan", 24, 0xe, 0xc, 0, 2 },
142136eda1dSMarius Strobl 	{ "Novell NE2100", 16, 0x12, 0x10, 0, 1 }
143136eda1dSMarius Strobl };
144136eda1dSMarius Strobl 
145136eda1dSMarius Strobl static struct isa_pnp_id le_isa_ids[] = {
146136eda1dSMarius Strobl 	{ 0x0322690e, "Cabletron E2200 Single Chip" },	/* CSI2203 */
147136eda1dSMarius Strobl 	{ 0x0110490a, "Boca LANCard Combo" },		/* BRI1001 */
148136eda1dSMarius Strobl 	{ 0x0100a60a, "Melco Inc. LGY-IV" },		/* BUF0001 */
149136eda1dSMarius Strobl 	{ 0xd880d041, "Novell NE2100" },		/* PNP80D8 */
150136eda1dSMarius Strobl 	{ 0x0082d041, "Cabletron E2100 Series DNI" },	/* PNP8200 */
151136eda1dSMarius Strobl 	{ 0x3182d041, "AMD AM1500T/AM2100" },		/* PNP8231 */
152136eda1dSMarius Strobl 	{ 0x8c82d041, "AMD PCnet-ISA" },		/* PNP828C */
153136eda1dSMarius Strobl 	{ 0x8d82d041, "AMD PCnet-32" },			/* PNP828D */
154136eda1dSMarius Strobl 	{ 0xcefaedfe, "Racal InterLan EtherBlaster" },	/* _WMFACE */
155136eda1dSMarius Strobl 	{ 0, NULL }
156136eda1dSMarius Strobl };
157136eda1dSMarius Strobl 
158136eda1dSMarius Strobl static void le_isa_wrcsr(struct lance_softc *, uint16_t, uint16_t);
159136eda1dSMarius Strobl static uint16_t le_isa_rdcsr(struct lance_softc *, uint16_t);
160136eda1dSMarius Strobl static bus_dmamap_callback_t le_isa_dma_callback;
161136eda1dSMarius Strobl static int le_isa_probe_legacy(device_t, const struct le_isa_param *);
162136eda1dSMarius Strobl 
163136eda1dSMarius Strobl static void
le_isa_wrcsr(struct lance_softc * sc,uint16_t port,uint16_t val)164136eda1dSMarius Strobl le_isa_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
165136eda1dSMarius Strobl {
166136eda1dSMarius Strobl 	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
167136eda1dSMarius Strobl 
168c75c2a68SMarius Strobl 	bus_write_2(lesc->sc_rres, lesc->sc_rap, port);
169c75c2a68SMarius Strobl 	bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE);
170c75c2a68SMarius Strobl 	bus_write_2(lesc->sc_rres, lesc->sc_rdp, val);
171136eda1dSMarius Strobl }
172136eda1dSMarius Strobl 
173136eda1dSMarius Strobl static uint16_t
le_isa_rdcsr(struct lance_softc * sc,uint16_t port)174136eda1dSMarius Strobl le_isa_rdcsr(struct lance_softc *sc, uint16_t port)
175136eda1dSMarius Strobl {
176136eda1dSMarius Strobl 	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
177136eda1dSMarius Strobl 
178c75c2a68SMarius Strobl 	bus_write_2(lesc->sc_rres, lesc->sc_rap, port);
179c75c2a68SMarius Strobl 	bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE);
180c75c2a68SMarius Strobl 	return (bus_read_2(lesc->sc_rres, lesc->sc_rdp));
181136eda1dSMarius Strobl }
182136eda1dSMarius Strobl 
183136eda1dSMarius Strobl static void
le_isa_dma_callback(void * xsc,bus_dma_segment_t * segs,int nsegs,int error)184136eda1dSMarius Strobl le_isa_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
185136eda1dSMarius Strobl {
186136eda1dSMarius Strobl 	struct lance_softc *sc = (struct lance_softc *)xsc;
187136eda1dSMarius Strobl 
188136eda1dSMarius Strobl 	if (error != 0)
189136eda1dSMarius Strobl 		return;
190136eda1dSMarius Strobl 	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
191136eda1dSMarius Strobl 	sc->sc_addr = segs[0].ds_addr;
192136eda1dSMarius Strobl }
193136eda1dSMarius Strobl 
194136eda1dSMarius Strobl static int
le_isa_probe_legacy(device_t dev,const struct le_isa_param * leip)195136eda1dSMarius Strobl le_isa_probe_legacy(device_t dev, const struct le_isa_param *leip)
196136eda1dSMarius Strobl {
197136eda1dSMarius Strobl 	struct le_isa_softc *lesc;
198136eda1dSMarius Strobl 	struct lance_softc *sc;
199c75c2a68SMarius Strobl 	int error, i;
200136eda1dSMarius Strobl 
201136eda1dSMarius Strobl 	lesc = device_get_softc(dev);
202136eda1dSMarius Strobl 	sc = &lesc->sc_am7990.lsc;
203136eda1dSMarius Strobl 
204c75c2a68SMarius Strobl 	i = 0;
205c47476d7SJustin Hibbits 	lesc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &i,
206c75c2a68SMarius Strobl 	    leip->iosize, RF_ACTIVE);
207136eda1dSMarius Strobl 	if (lesc->sc_rres == NULL)
208136eda1dSMarius Strobl 		return (ENXIO);
209136eda1dSMarius Strobl 	lesc->sc_rap = leip->rap;
210136eda1dSMarius Strobl 	lesc->sc_rdp = leip->rdp;
211136eda1dSMarius Strobl 
212136eda1dSMarius Strobl 	/* Stop the chip and put it in a known state. */
213136eda1dSMarius Strobl 	le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
214136eda1dSMarius Strobl 	DELAY(100);
215136eda1dSMarius Strobl 	if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
216136eda1dSMarius Strobl 		error = ENXIO;
217136eda1dSMarius Strobl 		goto fail;
218136eda1dSMarius Strobl 	}
219136eda1dSMarius Strobl 	le_isa_wrcsr(sc, LE_CSR3, 0);
220136eda1dSMarius Strobl 	error = 0;
221136eda1dSMarius Strobl 
222136eda1dSMarius Strobl  fail:
223c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_IOPORT,
224c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
225136eda1dSMarius Strobl 	return (error);
226136eda1dSMarius Strobl }
227136eda1dSMarius Strobl 
228136eda1dSMarius Strobl static int
le_isa_probe(device_t dev)229136eda1dSMarius Strobl le_isa_probe(device_t dev)
230136eda1dSMarius Strobl {
231136eda1dSMarius Strobl 	int i;
232136eda1dSMarius Strobl 
233136eda1dSMarius Strobl 	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
234136eda1dSMarius Strobl 	case 0:
235136eda1dSMarius Strobl 		return (BUS_PROBE_DEFAULT);
236136eda1dSMarius Strobl 	case ENOENT:
237323b076eSPedro F. Giffuni 		for (i = 0; i < nitems(le_isa_params); i++) {
238136eda1dSMarius Strobl 			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
239136eda1dSMarius Strobl 				device_set_desc(dev, le_isa_params[i].name);
240136eda1dSMarius Strobl 				return (BUS_PROBE_DEFAULT);
241136eda1dSMarius Strobl 			}
242136eda1dSMarius Strobl 		}
243136eda1dSMarius Strobl 		/* FALLTHROUGH */
244136eda1dSMarius Strobl 	case ENXIO:
245136eda1dSMarius Strobl 	default:
246136eda1dSMarius Strobl 		return (ENXIO);
247136eda1dSMarius Strobl 	}
248136eda1dSMarius Strobl }
249136eda1dSMarius Strobl 
250136eda1dSMarius Strobl static int
le_isa_attach(device_t dev)251136eda1dSMarius Strobl le_isa_attach(device_t dev)
252136eda1dSMarius Strobl {
253136eda1dSMarius Strobl 	struct le_isa_softc *lesc;
254136eda1dSMarius Strobl 	struct lance_softc *sc;
255136eda1dSMarius Strobl 	bus_size_t macstart, rap, rdp;
256c75c2a68SMarius Strobl 	int error, i, j, macstride;
257136eda1dSMarius Strobl 
258136eda1dSMarius Strobl 	lesc = device_get_softc(dev);
259136eda1dSMarius Strobl 	sc = &lesc->sc_am7990.lsc;
260136eda1dSMarius Strobl 
261136eda1dSMarius Strobl 	LE_LOCK_INIT(sc, device_get_nameunit(dev));
262136eda1dSMarius Strobl 
263c75c2a68SMarius Strobl 	j = 0;
264136eda1dSMarius Strobl 	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
265136eda1dSMarius Strobl 	case 0:
266136eda1dSMarius Strobl 		lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
267c75c2a68SMarius Strobl 		    &j, RF_ACTIVE);
268136eda1dSMarius Strobl 		rap = PCNET_RAP;
269136eda1dSMarius Strobl 		rdp = PCNET_RDP;
270136eda1dSMarius Strobl 		macstart = 0;
271136eda1dSMarius Strobl 		macstride = 1;
272136eda1dSMarius Strobl 		break;
273136eda1dSMarius Strobl 	case ENOENT:
274323b076eSPedro F. Giffuni 		for (i = 0; i < nitems(le_isa_params); i++) {
275136eda1dSMarius Strobl 			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
276c47476d7SJustin Hibbits 				lesc->sc_rres = bus_alloc_resource_anywhere(dev,
277c47476d7SJustin Hibbits 				    SYS_RES_IOPORT, &j,
278136eda1dSMarius Strobl 				    le_isa_params[i].iosize, RF_ACTIVE);
279136eda1dSMarius Strobl 				rap = le_isa_params[i].rap;
280136eda1dSMarius Strobl 				rdp = le_isa_params[i].rdp;
281136eda1dSMarius Strobl 				macstart = le_isa_params[i].macstart;
282136eda1dSMarius Strobl 				macstride = le_isa_params[i].macstride;
283136eda1dSMarius Strobl 				goto found;
284136eda1dSMarius Strobl 			}
285136eda1dSMarius Strobl 		}
286136eda1dSMarius Strobl 		/* FALLTHROUGH */
287136eda1dSMarius Strobl 	case ENXIO:
288136eda1dSMarius Strobl 	default:
289136eda1dSMarius Strobl 		device_printf(dev, "cannot determine chip\n");
290136eda1dSMarius Strobl 		error = ENXIO;
291136eda1dSMarius Strobl 		goto fail_mtx;
292136eda1dSMarius Strobl 	}
293136eda1dSMarius Strobl 
294136eda1dSMarius Strobl  found:
295136eda1dSMarius Strobl 	if (lesc->sc_rres == NULL) {
296136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate registers\n");
297136eda1dSMarius Strobl 		error = ENXIO;
298136eda1dSMarius Strobl 		goto fail_mtx;
299136eda1dSMarius Strobl 	}
300136eda1dSMarius Strobl 	lesc->sc_rap = rap;
301136eda1dSMarius Strobl 	lesc->sc_rdp = rdp;
302136eda1dSMarius Strobl 
303c75c2a68SMarius Strobl 	i = 0;
304136eda1dSMarius Strobl 	if ((lesc->sc_dres = bus_alloc_resource_any(dev, SYS_RES_DRQ,
305c75c2a68SMarius Strobl 	    &i, RF_ACTIVE)) == NULL) {
306136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate DMA channel\n");
307136eda1dSMarius Strobl 		error = ENXIO;
308136eda1dSMarius Strobl 		goto fail_rres;
309136eda1dSMarius Strobl 	}
310136eda1dSMarius Strobl 
311c75c2a68SMarius Strobl 	i = 0;
312136eda1dSMarius Strobl 	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
313c75c2a68SMarius Strobl 	    &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
314136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate interrupt\n");
315136eda1dSMarius Strobl 		error = ENXIO;
316136eda1dSMarius Strobl 		goto fail_dres;
317136eda1dSMarius Strobl 	}
318136eda1dSMarius Strobl 
319136eda1dSMarius Strobl 	error = bus_dma_tag_create(
320d2255d02SMarius Strobl 	    bus_get_dma_tag(dev),	/* parent */
321136eda1dSMarius Strobl 	    1, 0,			/* alignment, boundary */
322136eda1dSMarius Strobl 	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
323136eda1dSMarius Strobl 	    BUS_SPACE_MAXADDR,		/* highaddr */
324136eda1dSMarius Strobl 	    NULL, NULL,			/* filter, filterarg */
325136eda1dSMarius Strobl 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
326136eda1dSMarius Strobl 	    0,				/* nsegments */
327136eda1dSMarius Strobl 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
3280c7d35d0SMarius Strobl 	    0,				/* flags */
329136eda1dSMarius Strobl 	    NULL, NULL,			/* lockfunc, lockarg */
330136eda1dSMarius Strobl 	    &lesc->sc_pdmat);
331136eda1dSMarius Strobl 	if (error != 0) {
332136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate parent DMA tag\n");
333136eda1dSMarius Strobl 		goto fail_ires;
334136eda1dSMarius Strobl 	}
335136eda1dSMarius Strobl 
336136eda1dSMarius Strobl 	sc->sc_memsize = LE_ISA_MEMSIZE;
337136eda1dSMarius Strobl 	/*
338136eda1dSMarius Strobl 	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
339136eda1dSMarius Strobl 	 * aligned and the ring descriptors must be 8-byte aligned.
340136eda1dSMarius Strobl 	 */
341136eda1dSMarius Strobl 	error = bus_dma_tag_create(
342136eda1dSMarius Strobl 	    lesc->sc_pdmat,		/* parent */
343136eda1dSMarius Strobl 	    8, 0,			/* alignment, boundary */
344136eda1dSMarius Strobl 	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
345136eda1dSMarius Strobl 	    BUS_SPACE_MAXADDR,		/* highaddr */
346136eda1dSMarius Strobl 	    NULL, NULL,			/* filter, filterarg */
347136eda1dSMarius Strobl 	    sc->sc_memsize,		/* maxsize */
348136eda1dSMarius Strobl 	    1,				/* nsegments */
349136eda1dSMarius Strobl 	    sc->sc_memsize,		/* maxsegsize */
3500c7d35d0SMarius Strobl 	    0,				/* flags */
351136eda1dSMarius Strobl 	    NULL, NULL,			/* lockfunc, lockarg */
352136eda1dSMarius Strobl 	    &lesc->sc_dmat);
353136eda1dSMarius Strobl 	if (error != 0) {
354136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate buffer DMA tag\n");
355136eda1dSMarius Strobl 		goto fail_pdtag;
356136eda1dSMarius Strobl 	}
357136eda1dSMarius Strobl 
358136eda1dSMarius Strobl 	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
359136eda1dSMarius Strobl 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
360136eda1dSMarius Strobl 	if (error != 0) {
361136eda1dSMarius Strobl 		device_printf(dev, "cannot allocate DMA buffer memory\n");
362136eda1dSMarius Strobl 		goto fail_dtag;
363136eda1dSMarius Strobl 	}
364136eda1dSMarius Strobl 
365136eda1dSMarius Strobl 	sc->sc_addr = 0;
366136eda1dSMarius Strobl 	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
367136eda1dSMarius Strobl 	    sc->sc_memsize, le_isa_dma_callback, sc, 0);
368136eda1dSMarius Strobl 	if (error != 0 || sc->sc_addr == 0) {
369136eda1dSMarius Strobl 		device_printf(dev, "cannot load DMA buffer map\n");
370136eda1dSMarius Strobl 		goto fail_dmem;
371136eda1dSMarius Strobl 	}
372136eda1dSMarius Strobl 
373136eda1dSMarius Strobl 	isa_dmacascade(rman_get_start(lesc->sc_dres));
374136eda1dSMarius Strobl 
375136eda1dSMarius Strobl 	sc->sc_flags = 0;
376136eda1dSMarius Strobl 	sc->sc_conf3 = 0;
377136eda1dSMarius Strobl 
378136eda1dSMarius Strobl 	/*
379136eda1dSMarius Strobl 	 * Extract the physical MAC address from the ROM.
380136eda1dSMarius Strobl 	 */
381136eda1dSMarius Strobl 	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
382c75c2a68SMarius Strobl 		sc->sc_enaddr[i] = bus_read_1(lesc->sc_rres,
383c75c2a68SMarius Strobl 		    macstart + i * macstride);
384136eda1dSMarius Strobl 
385136eda1dSMarius Strobl 	sc->sc_copytodesc = lance_copytobuf_contig;
386136eda1dSMarius Strobl 	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
387136eda1dSMarius Strobl 	sc->sc_copytobuf = lance_copytobuf_contig;
388136eda1dSMarius Strobl 	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
389136eda1dSMarius Strobl 	sc->sc_zerobuf = lance_zerobuf_contig;
390136eda1dSMarius Strobl 
391136eda1dSMarius Strobl 	sc->sc_rdcsr = le_isa_rdcsr;
392136eda1dSMarius Strobl 	sc->sc_wrcsr = le_isa_wrcsr;
393136eda1dSMarius Strobl 	sc->sc_hwreset = NULL;
394136eda1dSMarius Strobl 	sc->sc_hwinit = NULL;
395136eda1dSMarius Strobl 	sc->sc_hwintr = NULL;
396136eda1dSMarius Strobl 	sc->sc_nocarrier = NULL;
397136eda1dSMarius Strobl 	sc->sc_mediachange = NULL;
398136eda1dSMarius Strobl 	sc->sc_mediastatus = NULL;
399136eda1dSMarius Strobl 	sc->sc_supmedia = NULL;
400136eda1dSMarius Strobl 
401136eda1dSMarius Strobl 	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
402136eda1dSMarius Strobl 	    device_get_unit(dev));
403136eda1dSMarius Strobl 	if (error != 0) {
404136eda1dSMarius Strobl 		device_printf(dev, "cannot attach Am7990\n");
405136eda1dSMarius Strobl 		goto fail_dmap;
406136eda1dSMarius Strobl 	}
407136eda1dSMarius Strobl 
408136eda1dSMarius Strobl 	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
409ef544f63SPaolo Pisati 	    NULL, am7990_intr, sc, &lesc->sc_ih);
410136eda1dSMarius Strobl 	if (error != 0) {
411136eda1dSMarius Strobl 		device_printf(dev, "cannot set up interrupt\n");
412136eda1dSMarius Strobl 		goto fail_am7990;
413136eda1dSMarius Strobl 	}
414136eda1dSMarius Strobl 
415136eda1dSMarius Strobl 	return (0);
416136eda1dSMarius Strobl 
417136eda1dSMarius Strobl  fail_am7990:
418136eda1dSMarius Strobl 	am7990_detach(&lesc->sc_am7990);
419136eda1dSMarius Strobl  fail_dmap:
420136eda1dSMarius Strobl 	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
421136eda1dSMarius Strobl  fail_dmem:
422136eda1dSMarius Strobl 	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
423136eda1dSMarius Strobl  fail_dtag:
424136eda1dSMarius Strobl 	bus_dma_tag_destroy(lesc->sc_dmat);
425136eda1dSMarius Strobl  fail_pdtag:
426136eda1dSMarius Strobl 	bus_dma_tag_destroy(lesc->sc_pdmat);
427136eda1dSMarius Strobl  fail_ires:
428c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_IRQ,
429c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_ires), lesc->sc_ires);
430136eda1dSMarius Strobl  fail_dres:
431c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_DRQ,
432c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_dres), lesc->sc_dres);
433136eda1dSMarius Strobl  fail_rres:
434c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_IOPORT,
435c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
436136eda1dSMarius Strobl  fail_mtx:
437136eda1dSMarius Strobl 	LE_LOCK_DESTROY(sc);
438136eda1dSMarius Strobl 	return (error);
439136eda1dSMarius Strobl }
440136eda1dSMarius Strobl 
441136eda1dSMarius Strobl static int
le_isa_detach(device_t dev)442136eda1dSMarius Strobl le_isa_detach(device_t dev)
443136eda1dSMarius Strobl {
444136eda1dSMarius Strobl 	struct le_isa_softc *lesc;
445136eda1dSMarius Strobl 	struct lance_softc *sc;
446136eda1dSMarius Strobl 
447136eda1dSMarius Strobl 	lesc = device_get_softc(dev);
448136eda1dSMarius Strobl 	sc = &lesc->sc_am7990.lsc;
449136eda1dSMarius Strobl 
450136eda1dSMarius Strobl 	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
451136eda1dSMarius Strobl 	am7990_detach(&lesc->sc_am7990);
452136eda1dSMarius Strobl 	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
453136eda1dSMarius Strobl 	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
454136eda1dSMarius Strobl 	bus_dma_tag_destroy(lesc->sc_dmat);
455136eda1dSMarius Strobl 	bus_dma_tag_destroy(lesc->sc_pdmat);
456c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_IRQ,
457c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_ires), lesc->sc_ires);
458c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_DRQ,
459c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_dres), lesc->sc_dres);
460c75c2a68SMarius Strobl 	bus_release_resource(dev, SYS_RES_IOPORT,
461c75c2a68SMarius Strobl 	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
462136eda1dSMarius Strobl 	LE_LOCK_DESTROY(sc);
463136eda1dSMarius Strobl 
464136eda1dSMarius Strobl 	return (0);
465136eda1dSMarius Strobl }
466136eda1dSMarius Strobl 
467136eda1dSMarius Strobl static int
le_isa_suspend(device_t dev)468136eda1dSMarius Strobl le_isa_suspend(device_t dev)
469136eda1dSMarius Strobl {
470136eda1dSMarius Strobl 	struct le_isa_softc *lesc;
471136eda1dSMarius Strobl 
472136eda1dSMarius Strobl 	lesc = device_get_softc(dev);
473136eda1dSMarius Strobl 
474136eda1dSMarius Strobl 	lance_suspend(&lesc->sc_am7990.lsc);
475136eda1dSMarius Strobl 
476136eda1dSMarius Strobl 	return (0);
477136eda1dSMarius Strobl }
478136eda1dSMarius Strobl 
479136eda1dSMarius Strobl static int
le_isa_resume(device_t dev)480136eda1dSMarius Strobl le_isa_resume(device_t dev)
481136eda1dSMarius Strobl {
482136eda1dSMarius Strobl 	struct le_isa_softc *lesc;
483136eda1dSMarius Strobl 
484136eda1dSMarius Strobl 	lesc = device_get_softc(dev);
485136eda1dSMarius Strobl 
486136eda1dSMarius Strobl 	lance_resume(&lesc->sc_am7990.lsc);
487136eda1dSMarius Strobl 
488136eda1dSMarius Strobl 	return (0);
489136eda1dSMarius Strobl }
4905fe4723cSWarner Losh 
4915fe4723cSWarner Losh DEFINE_CLASS_0(le, le_isa_driver, le_isa_methods, sizeof(struct le_isa_softc));
4928e995b46SJohn Baldwin DRIVER_MODULE(le, isa, le_isa_driver, 0, 0);
4935fe4723cSWarner Losh MODULE_DEPEND(le, ether, 1, 1, 1);
4945fe4723cSWarner Losh ISA_PNP_INFO(le_isa_ids);
495