if_le_ledma.c revision 155093
1155093Smarius/*	$NetBSD: if_le_ledma.c,v 1.26 2005/12/11 12:23:44 christos Exp $	*/
2155093Smarius
3155093Smarius/*-
4155093Smarius * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5155093Smarius * All rights reserved.
6155093Smarius *
7155093Smarius * This code is derived from software contributed to The NetBSD Foundation
8155093Smarius * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
9155093Smarius * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
10155093Smarius *
11155093Smarius * Redistribution and use in source and binary forms, with or without
12155093Smarius * modification, are permitted provided that the following conditions
13155093Smarius * are met:
14155093Smarius * 1. Redistributions of source code must retain the above copyright
15155093Smarius *    notice, this list of conditions and the following disclaimer.
16155093Smarius * 2. Redistributions in binary form must reproduce the above copyright
17155093Smarius *    notice, this list of conditions and the following disclaimer in the
18155093Smarius *    documentation and/or other materials provided with the distribution.
19155093Smarius * 3. All advertising materials mentioning features or use of this software
20155093Smarius *    must display the following acknowledgement:
21155093Smarius *	This product includes software developed by the NetBSD
22155093Smarius *	Foundation, Inc. and its contributors.
23155093Smarius * 4. Neither the name of The NetBSD Foundation nor the names of its
24155093Smarius *    contributors may be used to endorse or promote products derived
25155093Smarius *    from this software without specific prior written permission.
26155093Smarius *
27155093Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28155093Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29155093Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30155093Smarius * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31155093Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32155093Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33155093Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34155093Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35155093Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36155093Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37155093Smarius * POSSIBILITY OF SUCH DAMAGE.
38155093Smarius */
39155093Smarius
40155093Smarius#include <sys/cdefs.h>
41155093Smarius__FBSDID("$FreeBSD: head/sys/dev/le/if_le_ledma.c 155093 2006-01-31 14:48:58Z marius $");
42155093Smarius
43155093Smarius#include <sys/param.h>
44155093Smarius#include <sys/systm.h>
45155093Smarius#include <sys/bus.h>
46155093Smarius#include <sys/endian.h>
47155093Smarius#include <sys/kernel.h>
48155093Smarius#include <sys/lock.h>
49155093Smarius#include <sys/module.h>
50155093Smarius#include <sys/mutex.h>
51155093Smarius#include <sys/resource.h>
52155093Smarius#include <sys/rman.h>
53155093Smarius#include <sys/socket.h>
54155093Smarius
55155093Smarius#include <dev/ofw/ofw_bus.h>
56155093Smarius
57155093Smarius#include <machine/bus.h>
58155093Smarius#include <machine/ofw_machdep.h>
59155093Smarius#include <machine/resource.h>
60155093Smarius
61155093Smarius#include <net/ethernet.h>
62155093Smarius#include <net/if.h>
63155093Smarius#include <net/if_media.h>
64155093Smarius
65155093Smarius#include <sparc64/sbus/lsi64854reg.h>
66155093Smarius#include <sparc64/sbus/lsi64854var.h>
67155093Smarius
68155093Smarius#include <dev/le/lancereg.h>
69155093Smarius#include <dev/le/lancevar.h>
70155093Smarius#include <dev/le/am7990var.h>
71155093Smarius
72155093Smarius#define	LEDMA_BOUNDARY	(16*1024*1024)	/* must not cross 16MB boundary */
73155093Smarius#define	LEDMA_MEMSIZE	(16*1024)	/* LANCE memory size */
74155093Smarius#define	LEREG1_RDP	0		/* Register Data Port */
75155093Smarius#define	LEREG1_RAP	2		/* Register Address Port */
76155093Smarius
77155093Smariusstruct le_dma_softc {
78155093Smarius	struct am7990_softc	sc_am7990;	/* glue to MI code */
79155093Smarius
80155093Smarius	int			sc_rrid;
81155093Smarius	struct resource		*sc_rres;
82155093Smarius	bus_space_tag_t		sc_regt;
83155093Smarius	bus_space_handle_t	sc_regh;
84155093Smarius
85155093Smarius	int			sc_irid;
86155093Smarius	struct resource		*sc_ires;
87155093Smarius	void			*sc_ih;
88155093Smarius
89155093Smarius	bus_dma_tag_t		sc_dmat;
90155093Smarius	bus_dmamap_t		sc_dmam;
91155093Smarius	bus_addr_t		sc_laddr;	/* LANCE DMA address */
92155093Smarius
93155093Smarius	struct lsi64854_softc	*sc_dma;	/* pointer to DMA engine */
94155093Smarius};
95155093Smarius
96155093Smariusstatic device_probe_t le_dma_probe;
97155093Smariusstatic device_attach_t le_dma_attach;
98155093Smariusstatic device_detach_t le_dma_detach;
99155093Smariusstatic device_resume_t le_dma_resume;
100155093Smariusstatic device_suspend_t le_dma_suspend;
101155093Smarius
102155093Smariusstatic device_method_t le_dma_methods[] = {
103155093Smarius	/* Device interface */
104155093Smarius	DEVMETHOD(device_probe,		le_dma_probe),
105155093Smarius	DEVMETHOD(device_attach,	le_dma_attach),
106155093Smarius	DEVMETHOD(device_detach,	le_dma_detach),
107155093Smarius	/* We can just use the suspend method here. */
108155093Smarius	DEVMETHOD(device_shutdown,	le_dma_suspend),
109155093Smarius	DEVMETHOD(device_suspend,	le_dma_suspend),
110155093Smarius	DEVMETHOD(device_resume,	le_dma_resume),
111155093Smarius
112155093Smarius	{ 0, 0 }
113155093Smarius};
114155093Smarius
115155093SmariusDEFINE_CLASS_0(le, le_dma_driver, le_dma_methods, sizeof(struct le_dma_softc));
116155093SmariusDRIVER_MODULE(le, dma, le_dma_driver, le_devclass, 0, 0);
117155093SmariusMODULE_DEPEND(le, ether, 1, 1, 1);
118155093Smarius
119155093Smarius/*
120155093Smarius * Media types supported
121155093Smarius */
122155093Smariusstatic const int le_dma_supmedia[] = {
123155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0),
124155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0),
125155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0)
126155093Smarius};
127155093Smarius
128155093Smariusstatic void le_dma_wrcsr(struct lance_softc *, uint16_t, uint16_t);
129155093Smariusstatic uint16_t le_dma_rdcsr(struct lance_softc *, uint16_t);
130155093Smariusstatic void le_dma_setutp(struct lance_softc *);
131155093Smariusstatic void le_dma_setaui(struct lance_softc *);
132155093Smariusstatic int le_dma_supmediachange(struct lance_softc *);
133155093Smariusstatic void le_dma_supmediastatus(struct lance_softc *, struct ifmediareq *);
134155093Smariusstatic void le_dma_hwreset(struct lance_softc *);
135155093Smariusstatic int le_dma_hwintr(struct lance_softc *);
136155093Smariusstatic void le_dma_nocarrier(struct lance_softc *);
137155093Smariusstatic bus_dmamap_callback_t le_dma_dma_callback;
138155093Smarius
139155093Smariusstatic void
140155093Smariusle_dma_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
141155093Smarius{
142155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
143155093Smarius
144155093Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port);
145155093Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2,
146155093Smarius	    BUS_SPACE_BARRIER_WRITE);
147155093Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP, val);
148155093Smarius}
149155093Smarius
150155093Smariusstatic uint16_t
151155093Smariusle_dma_rdcsr(struct lance_softc *sc, uint16_t port)
152155093Smarius{
153155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
154155093Smarius
155155093Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port);
156155093Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2,
157155093Smarius	    BUS_SPACE_BARRIER_WRITE);
158155093Smarius	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP));
159155093Smarius}
160155093Smarius
161155093Smariusstatic void
162155093Smariusle_dma_setutp(struct lance_softc *sc)
163155093Smarius{
164155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
165155093Smarius
166155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) | E_TP_AUI);
167155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
168155093Smarius}
169155093Smarius
170155093Smariusstatic void
171155093Smariusle_dma_setaui(struct lance_softc *sc)
172155093Smarius{
173155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
174155093Smarius
175155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) & ~E_TP_AUI);
176155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
177155093Smarius}
178155093Smarius
179155093Smariusstatic int
180155093Smariusle_dma_supmediachange(struct lance_softc *sc)
181155093Smarius{
182155093Smarius	struct ifmedia *ifm = &sc->sc_media;
183155093Smarius
184155093Smarius	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
185155093Smarius		return (EINVAL);
186155093Smarius
187155093Smarius	/*
188155093Smarius	 * Switch to the selected media. If autoselect is set, we don't
189155093Smarius	 * really have to do anything. We'll switch to the other media
190155093Smarius	 * when we detect loss of carrier.
191155093Smarius	 */
192155093Smarius	switch (IFM_SUBTYPE(ifm->ifm_media)) {
193155093Smarius	case IFM_10_T:
194155093Smarius		le_dma_setutp(sc);
195155093Smarius		break;
196155093Smarius
197155093Smarius	case IFM_10_5:
198155093Smarius		le_dma_setaui(sc);
199155093Smarius		break;
200155093Smarius
201155093Smarius	case IFM_AUTO:
202155093Smarius		break;
203155093Smarius
204155093Smarius	default:
205155093Smarius		return (EINVAL);
206155093Smarius	}
207155093Smarius
208155093Smarius	return (0);
209155093Smarius}
210155093Smarius
211155093Smariusstatic void
212155093Smariusle_dma_supmediastatus(struct lance_softc *sc, struct ifmediareq *ifmr)
213155093Smarius{
214155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
215155093Smarius
216155093Smarius	/*
217155093Smarius	 * Notify the world which media we're currently using.
218155093Smarius	 */
219155093Smarius	if (L64854_GCSR(dma) & E_TP_AUI)
220155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
221155093Smarius	else
222155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0);
223155093Smarius}
224155093Smarius
225155093Smariusstatic void
226155093Smariusle_dma_hwreset(struct lance_softc *sc)
227155093Smarius{
228155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
229155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
230155093Smarius	uint32_t aui_bit, csr;
231155093Smarius
232155093Smarius	/*
233155093Smarius	 * Reset DMA channel.
234155093Smarius	 */
235155093Smarius	csr = L64854_GCSR(dma);
236155093Smarius	aui_bit = csr & E_TP_AUI;
237155093Smarius	DMA_RESET(dma);
238155093Smarius
239155093Smarius	/* Write bits 24-31 of Lance address. */
240155093Smarius	bus_space_write_4(dma->sc_regt, dma->sc_regh, L64854_REG_ENBAR,
241155093Smarius	    lesc->sc_laddr & 0xff000000);
242155093Smarius
243155093Smarius	DMA_ENINTR(dma);
244155093Smarius
245155093Smarius	/*
246155093Smarius	 * Disable E-cache invalidates on chip writes.
247155093Smarius	 * Retain previous cable selection bit.
248155093Smarius	 */
249155093Smarius	csr = L64854_GCSR(dma);
250155093Smarius	csr |= (E_DSBL_WR_INVAL | aui_bit);
251155093Smarius	L64854_SCSR(dma, csr);
252155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
253155093Smarius}
254155093Smarius
255155093Smariusstatic int
256155093Smariusle_dma_hwintr(struct lance_softc *sc)
257155093Smarius{
258155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
259155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
260155093Smarius
261155093Smarius	return (DMA_INTR(dma));
262155093Smarius}
263155093Smarius
264155093Smariusstatic void
265155093Smariusle_dma_nocarrier(struct lance_softc *sc)
266155093Smarius{
267155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
268155093Smarius
269155093Smarius	/*
270155093Smarius	 * Check if the user has requested a certain cable type, and
271155093Smarius	 * if so, honor that request.
272155093Smarius	 */
273155093Smarius
274155093Smarius	if (L64854_GCSR(lesc->sc_dma) & E_TP_AUI) {
275155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
276155093Smarius		case IFM_10_5:
277155093Smarius		case IFM_AUTO:
278155093Smarius			if_printf(sc->sc_ifp, "lost carrier on UTP port, "
279155093Smarius			    "switching to AUI port\n");
280155093Smarius			le_dma_setaui(sc);
281155093Smarius		}
282155093Smarius	} else {
283155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
284155093Smarius		case IFM_10_T:
285155093Smarius		case IFM_AUTO:
286155093Smarius			if_printf(sc->sc_ifp, "lost carrier on AUI port, "
287155093Smarius			    "switching to UTP port\n");
288155093Smarius			le_dma_setutp(sc);
289155093Smarius		}
290155093Smarius	}
291155093Smarius}
292155093Smarius
293155093Smariusstatic void
294155093Smariusle_dma_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
295155093Smarius{
296155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)xsc;
297155093Smarius
298155093Smarius	if (error != 0)
299155093Smarius		return;
300155093Smarius	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
301155093Smarius	lesc->sc_laddr = segs[0].ds_addr;
302155093Smarius}
303155093Smarius
304155093Smariusstatic int
305155093Smariusle_dma_probe(device_t dev)
306155093Smarius{
307155093Smarius
308155093Smarius	if (strcmp(ofw_bus_get_name(dev), "le") == 0) {
309155093Smarius		device_set_desc(dev, "LANCE Ethernet");
310155093Smarius		return (BUS_PROBE_DEFAULT);
311155093Smarius	}
312155093Smarius	return (ENXIO);
313155093Smarius}
314155093Smarius
315155093Smariusstatic int
316155093Smariusle_dma_attach(device_t dev)
317155093Smarius{
318155093Smarius	struct le_dma_softc *lesc;
319155093Smarius	struct lsi64854_softc *dma;
320155093Smarius	struct lance_softc *sc;
321155093Smarius	int error;
322155093Smarius
323155093Smarius	lesc = device_get_softc(dev);
324155093Smarius	sc = &lesc->sc_am7990.lsc;
325155093Smarius
326155093Smarius	LE_LOCK_INIT(sc, device_get_nameunit(dev));
327155093Smarius
328155093Smarius	/*
329155093Smarius	 * Establish link to `ledma' device.
330155093Smarius	 * XXX hackery.
331155093Smarius	 */
332155093Smarius	dma = (struct lsi64854_softc *)device_get_softc(device_get_parent(dev));
333155093Smarius	lesc->sc_dma = dma;
334155093Smarius	lesc->sc_dma->sc_client = lesc;
335155093Smarius
336155093Smarius	lesc->sc_rrid = 0;
337155093Smarius	lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
338155093Smarius	    &lesc->sc_rrid, RF_ACTIVE);
339155093Smarius	if (lesc->sc_rres == NULL) {
340155093Smarius		device_printf(dev, "cannot allocate registers\n");
341155093Smarius		error = ENXIO;
342155093Smarius		goto fail_mtx;
343155093Smarius	}
344155093Smarius	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
345155093Smarius	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
346155093Smarius
347155093Smarius	lesc->sc_irid = 0;
348155093Smarius	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
349155093Smarius	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
350155093Smarius		device_printf(dev, "cannot allocate interrupt\n");
351155093Smarius		error = ENXIO;
352155093Smarius		goto fail_rres;
353155093Smarius	}
354155093Smarius
355155093Smarius	sc->sc_memsize = LEDMA_MEMSIZE;
356155093Smarius	error = bus_dma_tag_create(
357155093Smarius	    dma->sc_parent_dmat,	/* parent */
358155093Smarius	    1, LEDMA_BOUNDARY,		/* alignment, boundary */
359155093Smarius	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
360155093Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
361155093Smarius	    NULL, NULL,			/* filter, filterarg */
362155093Smarius	    sc->sc_memsize,		/* maxsize */
363155093Smarius	    1,				/* nsegments */
364155093Smarius	    sc->sc_memsize,		/* maxsegsize */
365155093Smarius	    BUS_DMA_WAITOK,		/* flags */
366155093Smarius	    NULL, NULL,			/* lockfunc, lockarg */
367155093Smarius	    &lesc->sc_dmat);
368155093Smarius	if (error != 0) {
369155093Smarius		device_printf(dev, "cannot allocate buffer DMA tag\n");
370155093Smarius		goto fail_ires;
371155093Smarius	}
372155093Smarius
373155093Smarius	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
374155093Smarius	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
375155093Smarius	if (error != 0) {
376155093Smarius		device_printf(dev, "cannot allocate DMA buffer memory\n");
377155093Smarius		goto fail_dtag;
378155093Smarius	}
379155093Smarius
380155093Smarius	lesc->sc_laddr = 0;
381155093Smarius	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
382155093Smarius	    sc->sc_memsize, le_dma_dma_callback, lesc, 0);
383155093Smarius	if (error != 0 || lesc->sc_laddr == 0) {
384155093Smarius                device_printf(dev, "cannot load DMA buffer map\n");
385155093Smarius		goto fail_dmem;
386155093Smarius	}
387155093Smarius
388155093Smarius	sc->sc_addr = lesc->sc_laddr & 0xffffff;
389155093Smarius	sc->sc_flags = 0;
390155093Smarius	sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
391155093Smarius
392155093Smarius	sc->sc_mediachange = le_dma_supmediachange;
393155093Smarius	sc->sc_mediastatus = le_dma_supmediastatus;
394155093Smarius	sc->sc_supmedia = le_dma_supmedia;
395155093Smarius	sc->sc_nsupmedia = sizeof(le_dma_supmedia) / sizeof(le_dma_supmedia[0]);
396155093Smarius	sc->sc_defaultmedia = le_dma_supmedia[0];
397155093Smarius
398155093Smarius	OF_getetheraddr(dev, sc->sc_enaddr);
399155093Smarius
400155093Smarius	sc->sc_copytodesc = lance_copytobuf_contig;
401155093Smarius	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
402155093Smarius	sc->sc_copytobuf = lance_copytobuf_contig;
403155093Smarius	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
404155093Smarius	sc->sc_zerobuf = lance_zerobuf_contig;
405155093Smarius
406155093Smarius	sc->sc_rdcsr = le_dma_rdcsr;
407155093Smarius	sc->sc_wrcsr = le_dma_wrcsr;
408155093Smarius	sc->sc_nocarrier = le_dma_nocarrier;
409155093Smarius	sc->sc_hwreset = le_dma_hwreset;
410155093Smarius	sc->sc_hwintr = le_dma_hwintr;
411155093Smarius
412155093Smarius	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
413155093Smarius	    device_get_unit(dev));
414155093Smarius	if (error != 0) {
415155093Smarius		device_printf(dev, "cannot attach AM7990\n");
416155093Smarius		goto fail_dmap;
417155093Smarius	}
418155093Smarius
419155093Smarius	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
420155093Smarius	    am7990_intr, sc, &lesc->sc_ih);
421155093Smarius	if (error != 0) {
422155093Smarius		device_printf(dev, "cannot set up interrupt\n");
423155093Smarius		goto fail_am7990;
424155093Smarius	}
425155093Smarius
426155093Smarius	return (0);
427155093Smarius
428155093Smarius fail_am7990:
429155093Smarius	am7990_detach(&lesc->sc_am7990);
430155093Smarius fail_dmap:
431155093Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
432155093Smarius fail_dmem:
433155093Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
434155093Smarius fail_dtag:
435155093Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
436155093Smarius fail_ires:
437155093Smarius	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
438155093Smarius fail_rres:
439155093Smarius	bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres);
440155093Smarius fail_mtx:
441155093Smarius	LE_LOCK_DESTROY(sc);
442155093Smarius	return (error);
443155093Smarius}
444155093Smarius
445155093Smariusstatic int
446155093Smariusle_dma_detach(device_t dev)
447155093Smarius{
448155093Smarius	struct le_dma_softc *lesc;
449155093Smarius	struct lance_softc *sc;
450155093Smarius
451155093Smarius	lesc = device_get_softc(dev);
452155093Smarius	sc = &lesc->sc_am7990.lsc;
453155093Smarius
454155093Smarius	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
455155093Smarius	am7990_detach(&lesc->sc_am7990);
456155093Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
457155093Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
458155093Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
459155093Smarius	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
460155093Smarius	bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres);
461155093Smarius	LE_LOCK_DESTROY(sc);
462155093Smarius
463155093Smarius	return (0);
464155093Smarius}
465155093Smarius
466155093Smariusstatic int
467155093Smariusle_dma_suspend(device_t dev)
468155093Smarius{
469155093Smarius	struct le_dma_softc *lesc;
470155093Smarius
471155093Smarius	lesc = device_get_softc(dev);
472155093Smarius
473155093Smarius	lance_suspend(&lesc->sc_am7990.lsc);
474155093Smarius
475155093Smarius	return (0);
476155093Smarius}
477155093Smarius
478155093Smariusstatic int
479155093Smariusle_dma_resume(device_t dev)
480155093Smarius{
481155093Smarius	struct le_dma_softc *lesc;
482155093Smarius
483155093Smarius	lesc = device_get_softc(dev);
484155093Smarius
485155093Smarius	lance_resume(&lesc->sc_am7990.lsc);
486155093Smarius
487155093Smarius	return (0);
488155093Smarius}
489