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 *
20155093Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21155093Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22155093Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23155093Smarius * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24155093Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25155093Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26155093Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27155093Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28155093Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29155093Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30155093Smarius * POSSIBILITY OF SUCH DAMAGE.
31155093Smarius */
32155093Smarius
33155093Smarius#include <sys/cdefs.h>
34155093Smarius__FBSDID("$FreeBSD$");
35155093Smarius
36155093Smarius#include <sys/param.h>
37155093Smarius#include <sys/systm.h>
38155093Smarius#include <sys/bus.h>
39155093Smarius#include <sys/endian.h>
40155093Smarius#include <sys/kernel.h>
41155093Smarius#include <sys/lock.h>
42155093Smarius#include <sys/module.h>
43155093Smarius#include <sys/mutex.h>
44155093Smarius#include <sys/resource.h>
45155093Smarius#include <sys/rman.h>
46155093Smarius#include <sys/socket.h>
47155093Smarius
48155093Smarius#include <dev/ofw/ofw_bus.h>
49155093Smarius
50155093Smarius#include <machine/bus.h>
51155093Smarius#include <machine/ofw_machdep.h>
52155093Smarius#include <machine/resource.h>
53155093Smarius
54155093Smarius#include <net/ethernet.h>
55155093Smarius#include <net/if.h>
56257290Sglebius#include <net/if_var.h>
57155093Smarius#include <net/if_media.h>
58155093Smarius
59155093Smarius#include <sparc64/sbus/lsi64854reg.h>
60155093Smarius#include <sparc64/sbus/lsi64854var.h>
61155093Smarius
62155093Smarius#include <dev/le/lancereg.h>
63155093Smarius#include <dev/le/lancevar.h>
64155093Smarius#include <dev/le/am7990var.h>
65155093Smarius
66158663Smarius#define	LEDMA_ALIGNMENT	8		/* ring desc. alignmet for NCR92C990 */
67155093Smarius#define	LEDMA_BOUNDARY	(16*1024*1024)	/* must not cross 16MB boundary */
68155093Smarius#define	LEDMA_MEMSIZE	(16*1024)	/* LANCE memory size */
69155093Smarius#define	LEREG1_RDP	0		/* Register Data Port */
70155093Smarius#define	LEREG1_RAP	2		/* Register Address Port */
71155093Smarius
72155093Smariusstruct le_dma_softc {
73155093Smarius	struct am7990_softc	sc_am7990;	/* glue to MI code */
74155093Smarius
75155093Smarius	struct resource		*sc_rres;
76155093Smarius
77155093Smarius	struct resource		*sc_ires;
78155093Smarius	void			*sc_ih;
79155093Smarius
80155093Smarius	bus_dma_tag_t		sc_dmat;
81155093Smarius	bus_dmamap_t		sc_dmam;
82155093Smarius	bus_addr_t		sc_laddr;	/* LANCE DMA address */
83155093Smarius
84155093Smarius	struct lsi64854_softc	*sc_dma;	/* pointer to DMA engine */
85155093Smarius};
86155093Smarius
87155093Smariusstatic device_probe_t le_dma_probe;
88155093Smariusstatic device_attach_t le_dma_attach;
89155093Smariusstatic device_detach_t le_dma_detach;
90155093Smariusstatic device_resume_t le_dma_resume;
91155093Smariusstatic device_suspend_t le_dma_suspend;
92155093Smarius
93155093Smariusstatic device_method_t le_dma_methods[] = {
94155093Smarius	/* Device interface */
95155093Smarius	DEVMETHOD(device_probe,		le_dma_probe),
96155093Smarius	DEVMETHOD(device_attach,	le_dma_attach),
97155093Smarius	DEVMETHOD(device_detach,	le_dma_detach),
98155093Smarius	/* We can just use the suspend method here. */
99155093Smarius	DEVMETHOD(device_shutdown,	le_dma_suspend),
100155093Smarius	DEVMETHOD(device_suspend,	le_dma_suspend),
101155093Smarius	DEVMETHOD(device_resume,	le_dma_resume),
102155093Smarius
103155093Smarius	{ 0, 0 }
104155093Smarius};
105155093Smarius
106155093SmariusDEFINE_CLASS_0(le, le_dma_driver, le_dma_methods, sizeof(struct le_dma_softc));
107155093SmariusDRIVER_MODULE(le, dma, le_dma_driver, le_devclass, 0, 0);
108182876SmariusMODULE_DEPEND(le, dma, 1, 1, 1);
109155093SmariusMODULE_DEPEND(le, ether, 1, 1, 1);
110155093Smarius
111155093Smarius/*
112155093Smarius * Media types supported
113155093Smarius */
114155093Smariusstatic const int le_dma_supmedia[] = {
115155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0),
116155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0),
117155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0)
118155093Smarius};
119155093Smarius
120155093Smariusstatic void le_dma_wrcsr(struct lance_softc *, uint16_t, uint16_t);
121155093Smariusstatic uint16_t le_dma_rdcsr(struct lance_softc *, uint16_t);
122155093Smariusstatic void le_dma_setutp(struct lance_softc *);
123155093Smariusstatic void le_dma_setaui(struct lance_softc *);
124155093Smariusstatic int le_dma_supmediachange(struct lance_softc *);
125155093Smariusstatic void le_dma_supmediastatus(struct lance_softc *, struct ifmediareq *);
126155093Smariusstatic void le_dma_hwreset(struct lance_softc *);
127155093Smariusstatic int le_dma_hwintr(struct lance_softc *);
128155093Smariusstatic void le_dma_nocarrier(struct lance_softc *);
129155093Smariusstatic bus_dmamap_callback_t le_dma_dma_callback;
130155093Smarius
131155093Smariusstatic void
132155093Smariusle_dma_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
133155093Smarius{
134155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
135155093Smarius
136182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RAP, port);
137182876Smarius	bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE);
138182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RDP, val);
139155093Smarius}
140155093Smarius
141155093Smariusstatic uint16_t
142155093Smariusle_dma_rdcsr(struct lance_softc *sc, uint16_t port)
143155093Smarius{
144155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
145155093Smarius
146182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RAP, port);
147182876Smarius	bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE);
148182876Smarius	return (bus_read_2(lesc->sc_rres, LEREG1_RDP));
149155093Smarius}
150155093Smarius
151155093Smariusstatic void
152155093Smariusle_dma_setutp(struct lance_softc *sc)
153155093Smarius{
154155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
155155093Smarius
156155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) | E_TP_AUI);
157155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
158155093Smarius}
159155093Smarius
160155093Smariusstatic void
161155093Smariusle_dma_setaui(struct lance_softc *sc)
162155093Smarius{
163155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
164155093Smarius
165155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) & ~E_TP_AUI);
166155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
167155093Smarius}
168155093Smarius
169155093Smariusstatic int
170155093Smariusle_dma_supmediachange(struct lance_softc *sc)
171155093Smarius{
172155093Smarius	struct ifmedia *ifm = &sc->sc_media;
173155093Smarius
174155093Smarius	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
175155093Smarius		return (EINVAL);
176155093Smarius
177155093Smarius	/*
178155093Smarius	 * Switch to the selected media. If autoselect is set, we don't
179155093Smarius	 * really have to do anything. We'll switch to the other media
180155093Smarius	 * when we detect loss of carrier.
181155093Smarius	 */
182155093Smarius	switch (IFM_SUBTYPE(ifm->ifm_media)) {
183155093Smarius	case IFM_10_T:
184155093Smarius		le_dma_setutp(sc);
185155093Smarius		break;
186155093Smarius
187155093Smarius	case IFM_10_5:
188155093Smarius		le_dma_setaui(sc);
189155093Smarius		break;
190155093Smarius
191155093Smarius	case IFM_AUTO:
192155093Smarius		break;
193155093Smarius
194155093Smarius	default:
195155093Smarius		return (EINVAL);
196155093Smarius	}
197155093Smarius
198155093Smarius	return (0);
199155093Smarius}
200155093Smarius
201155093Smariusstatic void
202155093Smariusle_dma_supmediastatus(struct lance_softc *sc, struct ifmediareq *ifmr)
203155093Smarius{
204155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
205155093Smarius
206155093Smarius	/*
207155093Smarius	 * Notify the world which media we're currently using.
208155093Smarius	 */
209155093Smarius	if (L64854_GCSR(dma) & E_TP_AUI)
210155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
211155093Smarius	else
212155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0);
213155093Smarius}
214155093Smarius
215155093Smariusstatic void
216155093Smariusle_dma_hwreset(struct lance_softc *sc)
217155093Smarius{
218155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
219155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
220155093Smarius	uint32_t aui_bit, csr;
221155093Smarius
222155093Smarius	/*
223155093Smarius	 * Reset DMA channel.
224155093Smarius	 */
225155093Smarius	csr = L64854_GCSR(dma);
226155093Smarius	aui_bit = csr & E_TP_AUI;
227155093Smarius	DMA_RESET(dma);
228155093Smarius
229155093Smarius	/* Write bits 24-31 of Lance address. */
230182876Smarius	bus_write_4(dma->sc_res, L64854_REG_ENBAR,
231155093Smarius	    lesc->sc_laddr & 0xff000000);
232155093Smarius
233155093Smarius	DMA_ENINTR(dma);
234155093Smarius
235155093Smarius	/*
236155093Smarius	 * Disable E-cache invalidates on chip writes.
237155093Smarius	 * Retain previous cable selection bit.
238155093Smarius	 */
239155093Smarius	csr = L64854_GCSR(dma);
240155093Smarius	csr |= (E_DSBL_WR_INVAL | aui_bit);
241155093Smarius	L64854_SCSR(dma, csr);
242155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
243155093Smarius}
244155093Smarius
245155093Smariusstatic int
246155093Smariusle_dma_hwintr(struct lance_softc *sc)
247155093Smarius{
248155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
249155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
250155093Smarius
251155093Smarius	return (DMA_INTR(dma));
252155093Smarius}
253155093Smarius
254155093Smariusstatic void
255155093Smariusle_dma_nocarrier(struct lance_softc *sc)
256155093Smarius{
257155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
258155093Smarius
259155093Smarius	/*
260155093Smarius	 * Check if the user has requested a certain cable type, and
261155093Smarius	 * if so, honor that request.
262155093Smarius	 */
263155093Smarius
264155093Smarius	if (L64854_GCSR(lesc->sc_dma) & E_TP_AUI) {
265155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
266155093Smarius		case IFM_10_5:
267155093Smarius		case IFM_AUTO:
268155093Smarius			if_printf(sc->sc_ifp, "lost carrier on UTP port, "
269155093Smarius			    "switching to AUI port\n");
270155093Smarius			le_dma_setaui(sc);
271155093Smarius		}
272155093Smarius	} else {
273155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
274155093Smarius		case IFM_10_T:
275155093Smarius		case IFM_AUTO:
276155093Smarius			if_printf(sc->sc_ifp, "lost carrier on AUI port, "
277155093Smarius			    "switching to UTP port\n");
278155093Smarius			le_dma_setutp(sc);
279155093Smarius		}
280155093Smarius	}
281155093Smarius}
282155093Smarius
283155093Smariusstatic void
284155093Smariusle_dma_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
285155093Smarius{
286155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)xsc;
287155093Smarius
288155093Smarius	if (error != 0)
289155093Smarius		return;
290155093Smarius	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
291155093Smarius	lesc->sc_laddr = segs[0].ds_addr;
292155093Smarius}
293155093Smarius
294155093Smariusstatic int
295155093Smariusle_dma_probe(device_t dev)
296155093Smarius{
297155093Smarius
298155093Smarius	if (strcmp(ofw_bus_get_name(dev), "le") == 0) {
299155093Smarius		device_set_desc(dev, "LANCE Ethernet");
300155093Smarius		return (BUS_PROBE_DEFAULT);
301155093Smarius	}
302155093Smarius	return (ENXIO);
303155093Smarius}
304155093Smarius
305155093Smariusstatic int
306155093Smariusle_dma_attach(device_t dev)
307155093Smarius{
308155093Smarius	struct le_dma_softc *lesc;
309155093Smarius	struct lsi64854_softc *dma;
310155093Smarius	struct lance_softc *sc;
311182876Smarius	int error, i;
312155093Smarius
313155093Smarius	lesc = device_get_softc(dev);
314155093Smarius	sc = &lesc->sc_am7990.lsc;
315155093Smarius
316155093Smarius	LE_LOCK_INIT(sc, device_get_nameunit(dev));
317155093Smarius
318155093Smarius	/*
319155093Smarius	 * Establish link to `ledma' device.
320155093Smarius	 * XXX hackery.
321155093Smarius	 */
322155093Smarius	dma = (struct lsi64854_softc *)device_get_softc(device_get_parent(dev));
323155093Smarius	lesc->sc_dma = dma;
324155093Smarius	lesc->sc_dma->sc_client = lesc;
325155093Smarius
326182876Smarius	i = 0;
327155093Smarius	lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
328182876Smarius	    &i, RF_ACTIVE);
329155093Smarius	if (lesc->sc_rres == NULL) {
330155093Smarius		device_printf(dev, "cannot allocate registers\n");
331155093Smarius		error = ENXIO;
332155093Smarius		goto fail_mtx;
333155093Smarius	}
334155093Smarius
335182876Smarius	i = 0;
336155093Smarius	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
337182876Smarius	    &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
338155093Smarius		device_printf(dev, "cannot allocate interrupt\n");
339155093Smarius		error = ENXIO;
340155093Smarius		goto fail_rres;
341155093Smarius	}
342155093Smarius
343182876Smarius	/* Attach the DMA engine. */
344182876Smarius	error = lsi64854_attach(dma);
345182876Smarius	if (error != 0) {
346182876Smarius		device_printf(dev, "lsi64854_attach failed\n");
347182876Smarius		goto fail_ires;
348182876Smarius	}
349182876Smarius
350155093Smarius	sc->sc_memsize = LEDMA_MEMSIZE;
351155093Smarius	error = bus_dma_tag_create(
352155093Smarius	    dma->sc_parent_dmat,	/* parent */
353158663Smarius	    LEDMA_ALIGNMENT,		/* alignment */
354158663Smarius	    LEDMA_BOUNDARY,		/* boundary */
355155093Smarius	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
356155093Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
357155093Smarius	    NULL, NULL,			/* filter, filterarg */
358155093Smarius	    sc->sc_memsize,		/* maxsize */
359155093Smarius	    1,				/* nsegments */
360155093Smarius	    sc->sc_memsize,		/* maxsegsize */
361166148Smarius	    0,				/* flags */
362155093Smarius	    NULL, NULL,			/* lockfunc, lockarg */
363155093Smarius	    &lesc->sc_dmat);
364155093Smarius	if (error != 0) {
365155093Smarius		device_printf(dev, "cannot allocate buffer DMA tag\n");
366182876Smarius		goto fail_lsi;
367155093Smarius	}
368155093Smarius
369155093Smarius	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
370155093Smarius	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
371155093Smarius	if (error != 0) {
372155093Smarius		device_printf(dev, "cannot allocate DMA buffer memory\n");
373155093Smarius		goto fail_dtag;
374155093Smarius	}
375155093Smarius
376155093Smarius	lesc->sc_laddr = 0;
377155093Smarius	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
378155093Smarius	    sc->sc_memsize, le_dma_dma_callback, lesc, 0);
379155093Smarius	if (error != 0 || lesc->sc_laddr == 0) {
380182876Smarius		device_printf(dev, "cannot load DMA buffer map\n");
381155093Smarius		goto fail_dmem;
382155093Smarius	}
383155093Smarius
384155093Smarius	sc->sc_addr = lesc->sc_laddr & 0xffffff;
385155093Smarius	sc->sc_flags = 0;
386155093Smarius	sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
387155093Smarius
388155093Smarius	sc->sc_mediachange = le_dma_supmediachange;
389155093Smarius	sc->sc_mediastatus = le_dma_supmediastatus;
390155093Smarius	sc->sc_supmedia = le_dma_supmedia;
391298431Spfg	sc->sc_nsupmedia = nitems(le_dma_supmedia);
392155093Smarius	sc->sc_defaultmedia = le_dma_supmedia[0];
393155093Smarius
394155093Smarius	OF_getetheraddr(dev, sc->sc_enaddr);
395155093Smarius
396155093Smarius	sc->sc_copytodesc = lance_copytobuf_contig;
397155093Smarius	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
398155093Smarius	sc->sc_copytobuf = lance_copytobuf_contig;
399155093Smarius	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
400155093Smarius	sc->sc_zerobuf = lance_zerobuf_contig;
401155093Smarius
402155093Smarius	sc->sc_rdcsr = le_dma_rdcsr;
403155093Smarius	sc->sc_wrcsr = le_dma_wrcsr;
404155093Smarius	sc->sc_hwreset = le_dma_hwreset;
405155093Smarius	sc->sc_hwintr = le_dma_hwintr;
406158663Smarius	sc->sc_nocarrier = le_dma_nocarrier;
407155093Smarius
408155093Smarius	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
409155093Smarius	    device_get_unit(dev));
410155093Smarius	if (error != 0) {
411158663Smarius		device_printf(dev, "cannot attach Am7990\n");
412155093Smarius		goto fail_dmap;
413155093Smarius	}
414155093Smarius
415155093Smarius	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
416166901Spiso	    NULL, am7990_intr, sc, &lesc->sc_ih);
417155093Smarius	if (error != 0) {
418155093Smarius		device_printf(dev, "cannot set up interrupt\n");
419155093Smarius		goto fail_am7990;
420155093Smarius	}
421155093Smarius
422155093Smarius	return (0);
423155093Smarius
424155093Smarius fail_am7990:
425155093Smarius	am7990_detach(&lesc->sc_am7990);
426155093Smarius fail_dmap:
427155093Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
428155093Smarius fail_dmem:
429155093Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
430155093Smarius fail_dtag:
431155093Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
432182876Smarius fail_lsi:
433182876Smarius	lsi64854_detach(dma);
434155093Smarius fail_ires:
435182876Smarius	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires),
436182876Smarius	    lesc->sc_ires);
437155093Smarius fail_rres:
438182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres),
439182876Smarius	    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;
450182876Smarius	int error;
451155093Smarius
452155093Smarius	lesc = device_get_softc(dev);
453155093Smarius	sc = &lesc->sc_am7990.lsc;
454155093Smarius
455155093Smarius	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
456155093Smarius	am7990_detach(&lesc->sc_am7990);
457155093Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
458155093Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
459155093Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
460182876Smarius	error = lsi64854_detach(lesc->sc_dma);
461182876Smarius	if (error != 0)
462182876Smarius		return (error);
463182876Smarius	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires),
464182876Smarius	    lesc->sc_ires);
465182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres),
466182876Smarius	    lesc->sc_rres);
467155093Smarius	LE_LOCK_DESTROY(sc);
468155093Smarius
469155093Smarius	return (0);
470155093Smarius}
471155093Smarius
472155093Smariusstatic int
473155093Smariusle_dma_suspend(device_t dev)
474155093Smarius{
475155093Smarius	struct le_dma_softc *lesc;
476155093Smarius
477155093Smarius	lesc = device_get_softc(dev);
478155093Smarius
479155093Smarius	lance_suspend(&lesc->sc_am7990.lsc);
480155093Smarius
481155093Smarius	return (0);
482155093Smarius}
483155093Smarius
484155093Smariusstatic int
485155093Smariusle_dma_resume(device_t dev)
486155093Smarius{
487155093Smarius	struct le_dma_softc *lesc;
488155093Smarius
489155093Smarius	lesc = device_get_softc(dev);
490155093Smarius
491155093Smarius	lance_resume(&lesc->sc_am7990.lsc);
492155093Smarius
493155093Smarius	return (0);
494155093Smarius}
495