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>
56155093Smarius#include <net/if_media.h>
57155093Smarius
58155093Smarius#include <sparc64/sbus/lsi64854reg.h>
59155093Smarius#include <sparc64/sbus/lsi64854var.h>
60155093Smarius
61155093Smarius#include <dev/le/lancereg.h>
62155093Smarius#include <dev/le/lancevar.h>
63155093Smarius#include <dev/le/am7990var.h>
64155093Smarius
65158663Smarius#define	LEDMA_ALIGNMENT	8		/* ring desc. alignmet for NCR92C990 */
66155093Smarius#define	LEDMA_BOUNDARY	(16*1024*1024)	/* must not cross 16MB boundary */
67155093Smarius#define	LEDMA_MEMSIZE	(16*1024)	/* LANCE memory size */
68155093Smarius#define	LEREG1_RDP	0		/* Register Data Port */
69155093Smarius#define	LEREG1_RAP	2		/* Register Address Port */
70155093Smarius
71155093Smariusstruct le_dma_softc {
72155093Smarius	struct am7990_softc	sc_am7990;	/* glue to MI code */
73155093Smarius
74155093Smarius	struct resource		*sc_rres;
75155093Smarius
76155093Smarius	struct resource		*sc_ires;
77155093Smarius	void			*sc_ih;
78155093Smarius
79155093Smarius	bus_dma_tag_t		sc_dmat;
80155093Smarius	bus_dmamap_t		sc_dmam;
81155093Smarius	bus_addr_t		sc_laddr;	/* LANCE DMA address */
82155093Smarius
83155093Smarius	struct lsi64854_softc	*sc_dma;	/* pointer to DMA engine */
84155093Smarius};
85155093Smarius
86155093Smariusstatic device_probe_t le_dma_probe;
87155093Smariusstatic device_attach_t le_dma_attach;
88155093Smariusstatic device_detach_t le_dma_detach;
89155093Smariusstatic device_resume_t le_dma_resume;
90155093Smariusstatic device_suspend_t le_dma_suspend;
91155093Smarius
92155093Smariusstatic device_method_t le_dma_methods[] = {
93155093Smarius	/* Device interface */
94155093Smarius	DEVMETHOD(device_probe,		le_dma_probe),
95155093Smarius	DEVMETHOD(device_attach,	le_dma_attach),
96155093Smarius	DEVMETHOD(device_detach,	le_dma_detach),
97155093Smarius	/* We can just use the suspend method here. */
98155093Smarius	DEVMETHOD(device_shutdown,	le_dma_suspend),
99155093Smarius	DEVMETHOD(device_suspend,	le_dma_suspend),
100155093Smarius	DEVMETHOD(device_resume,	le_dma_resume),
101155093Smarius
102155093Smarius	{ 0, 0 }
103155093Smarius};
104155093Smarius
105155093SmariusDEFINE_CLASS_0(le, le_dma_driver, le_dma_methods, sizeof(struct le_dma_softc));
106155093SmariusDRIVER_MODULE(le, dma, le_dma_driver, le_devclass, 0, 0);
107182876SmariusMODULE_DEPEND(le, dma, 1, 1, 1);
108155093SmariusMODULE_DEPEND(le, ether, 1, 1, 1);
109155093Smarius
110155093Smarius/*
111155093Smarius * Media types supported
112155093Smarius */
113155093Smariusstatic const int le_dma_supmedia[] = {
114155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0),
115155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0),
116155093Smarius	IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0)
117155093Smarius};
118155093Smarius
119155093Smariusstatic void le_dma_wrcsr(struct lance_softc *, uint16_t, uint16_t);
120155093Smariusstatic uint16_t le_dma_rdcsr(struct lance_softc *, uint16_t);
121155093Smariusstatic void le_dma_setutp(struct lance_softc *);
122155093Smariusstatic void le_dma_setaui(struct lance_softc *);
123155093Smariusstatic int le_dma_supmediachange(struct lance_softc *);
124155093Smariusstatic void le_dma_supmediastatus(struct lance_softc *, struct ifmediareq *);
125155093Smariusstatic void le_dma_hwreset(struct lance_softc *);
126155093Smariusstatic int le_dma_hwintr(struct lance_softc *);
127155093Smariusstatic void le_dma_nocarrier(struct lance_softc *);
128155093Smariusstatic bus_dmamap_callback_t le_dma_dma_callback;
129155093Smarius
130155093Smariusstatic void
131155093Smariusle_dma_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
132155093Smarius{
133155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
134155093Smarius
135182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RAP, port);
136182876Smarius	bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE);
137182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RDP, val);
138155093Smarius}
139155093Smarius
140155093Smariusstatic uint16_t
141155093Smariusle_dma_rdcsr(struct lance_softc *sc, uint16_t port)
142155093Smarius{
143155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
144155093Smarius
145182876Smarius	bus_write_2(lesc->sc_rres, LEREG1_RAP, port);
146182876Smarius	bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE);
147182876Smarius	return (bus_read_2(lesc->sc_rres, LEREG1_RDP));
148155093Smarius}
149155093Smarius
150155093Smariusstatic void
151155093Smariusle_dma_setutp(struct lance_softc *sc)
152155093Smarius{
153155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
154155093Smarius
155155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) | E_TP_AUI);
156155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
157155093Smarius}
158155093Smarius
159155093Smariusstatic void
160155093Smariusle_dma_setaui(struct lance_softc *sc)
161155093Smarius{
162155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
163155093Smarius
164155093Smarius	L64854_SCSR(dma, L64854_GCSR(dma) & ~E_TP_AUI);
165155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
166155093Smarius}
167155093Smarius
168155093Smariusstatic int
169155093Smariusle_dma_supmediachange(struct lance_softc *sc)
170155093Smarius{
171155093Smarius	struct ifmedia *ifm = &sc->sc_media;
172155093Smarius
173155093Smarius	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
174155093Smarius		return (EINVAL);
175155093Smarius
176155093Smarius	/*
177155093Smarius	 * Switch to the selected media. If autoselect is set, we don't
178155093Smarius	 * really have to do anything. We'll switch to the other media
179155093Smarius	 * when we detect loss of carrier.
180155093Smarius	 */
181155093Smarius	switch (IFM_SUBTYPE(ifm->ifm_media)) {
182155093Smarius	case IFM_10_T:
183155093Smarius		le_dma_setutp(sc);
184155093Smarius		break;
185155093Smarius
186155093Smarius	case IFM_10_5:
187155093Smarius		le_dma_setaui(sc);
188155093Smarius		break;
189155093Smarius
190155093Smarius	case IFM_AUTO:
191155093Smarius		break;
192155093Smarius
193155093Smarius	default:
194155093Smarius		return (EINVAL);
195155093Smarius	}
196155093Smarius
197155093Smarius	return (0);
198155093Smarius}
199155093Smarius
200155093Smariusstatic void
201155093Smariusle_dma_supmediastatus(struct lance_softc *sc, struct ifmediareq *ifmr)
202155093Smarius{
203155093Smarius	struct lsi64854_softc *dma = ((struct le_dma_softc *)sc)->sc_dma;
204155093Smarius
205155093Smarius	/*
206155093Smarius	 * Notify the world which media we're currently using.
207155093Smarius	 */
208155093Smarius	if (L64854_GCSR(dma) & E_TP_AUI)
209155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
210155093Smarius	else
211155093Smarius		ifmr->ifm_active = IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0);
212155093Smarius}
213155093Smarius
214155093Smariusstatic void
215155093Smariusle_dma_hwreset(struct lance_softc *sc)
216155093Smarius{
217155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
218155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
219155093Smarius	uint32_t aui_bit, csr;
220155093Smarius
221155093Smarius	/*
222155093Smarius	 * Reset DMA channel.
223155093Smarius	 */
224155093Smarius	csr = L64854_GCSR(dma);
225155093Smarius	aui_bit = csr & E_TP_AUI;
226155093Smarius	DMA_RESET(dma);
227155093Smarius
228155093Smarius	/* Write bits 24-31 of Lance address. */
229182876Smarius	bus_write_4(dma->sc_res, L64854_REG_ENBAR,
230155093Smarius	    lesc->sc_laddr & 0xff000000);
231155093Smarius
232155093Smarius	DMA_ENINTR(dma);
233155093Smarius
234155093Smarius	/*
235155093Smarius	 * Disable E-cache invalidates on chip writes.
236155093Smarius	 * Retain previous cable selection bit.
237155093Smarius	 */
238155093Smarius	csr = L64854_GCSR(dma);
239155093Smarius	csr |= (E_DSBL_WR_INVAL | aui_bit);
240155093Smarius	L64854_SCSR(dma, csr);
241155093Smarius	DELAY(20000);	/* We must not touch the LANCE chip for 20ms. */
242155093Smarius}
243155093Smarius
244155093Smariusstatic int
245155093Smariusle_dma_hwintr(struct lance_softc *sc)
246155093Smarius{
247155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
248155093Smarius	struct lsi64854_softc *dma = lesc->sc_dma;
249155093Smarius
250155093Smarius	return (DMA_INTR(dma));
251155093Smarius}
252155093Smarius
253155093Smariusstatic void
254155093Smariusle_dma_nocarrier(struct lance_softc *sc)
255155093Smarius{
256155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
257155093Smarius
258155093Smarius	/*
259155093Smarius	 * Check if the user has requested a certain cable type, and
260155093Smarius	 * if so, honor that request.
261155093Smarius	 */
262155093Smarius
263155093Smarius	if (L64854_GCSR(lesc->sc_dma) & E_TP_AUI) {
264155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
265155093Smarius		case IFM_10_5:
266155093Smarius		case IFM_AUTO:
267155093Smarius			if_printf(sc->sc_ifp, "lost carrier on UTP port, "
268155093Smarius			    "switching to AUI port\n");
269155093Smarius			le_dma_setaui(sc);
270155093Smarius		}
271155093Smarius	} else {
272155093Smarius		switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) {
273155093Smarius		case IFM_10_T:
274155093Smarius		case IFM_AUTO:
275155093Smarius			if_printf(sc->sc_ifp, "lost carrier on AUI port, "
276155093Smarius			    "switching to UTP port\n");
277155093Smarius			le_dma_setutp(sc);
278155093Smarius		}
279155093Smarius	}
280155093Smarius}
281155093Smarius
282155093Smariusstatic void
283155093Smariusle_dma_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
284155093Smarius{
285155093Smarius	struct le_dma_softc *lesc = (struct le_dma_softc *)xsc;
286155093Smarius
287155093Smarius	if (error != 0)
288155093Smarius		return;
289155093Smarius	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
290155093Smarius	lesc->sc_laddr = segs[0].ds_addr;
291155093Smarius}
292155093Smarius
293155093Smariusstatic int
294155093Smariusle_dma_probe(device_t dev)
295155093Smarius{
296155093Smarius
297155093Smarius	if (strcmp(ofw_bus_get_name(dev), "le") == 0) {
298155093Smarius		device_set_desc(dev, "LANCE Ethernet");
299155093Smarius		return (BUS_PROBE_DEFAULT);
300155093Smarius	}
301155093Smarius	return (ENXIO);
302155093Smarius}
303155093Smarius
304155093Smariusstatic int
305155093Smariusle_dma_attach(device_t dev)
306155093Smarius{
307155093Smarius	struct le_dma_softc *lesc;
308155093Smarius	struct lsi64854_softc *dma;
309155093Smarius	struct lance_softc *sc;
310182876Smarius	int error, i;
311155093Smarius
312155093Smarius	lesc = device_get_softc(dev);
313155093Smarius	sc = &lesc->sc_am7990.lsc;
314155093Smarius
315155093Smarius	LE_LOCK_INIT(sc, device_get_nameunit(dev));
316155093Smarius
317155093Smarius	/*
318155093Smarius	 * Establish link to `ledma' device.
319155093Smarius	 * XXX hackery.
320155093Smarius	 */
321155093Smarius	dma = (struct lsi64854_softc *)device_get_softc(device_get_parent(dev));
322155093Smarius	lesc->sc_dma = dma;
323155093Smarius	lesc->sc_dma->sc_client = lesc;
324155093Smarius
325182876Smarius	i = 0;
326155093Smarius	lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
327182876Smarius	    &i, RF_ACTIVE);
328155093Smarius	if (lesc->sc_rres == NULL) {
329155093Smarius		device_printf(dev, "cannot allocate registers\n");
330155093Smarius		error = ENXIO;
331155093Smarius		goto fail_mtx;
332155093Smarius	}
333155093Smarius
334182876Smarius	i = 0;
335155093Smarius	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
336182876Smarius	    &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
337155093Smarius		device_printf(dev, "cannot allocate interrupt\n");
338155093Smarius		error = ENXIO;
339155093Smarius		goto fail_rres;
340155093Smarius	}
341155093Smarius
342182876Smarius	/* Attach the DMA engine. */
343182876Smarius	error = lsi64854_attach(dma);
344182876Smarius	if (error != 0) {
345182876Smarius		device_printf(dev, "lsi64854_attach failed\n");
346182876Smarius		goto fail_ires;
347182876Smarius	}
348182876Smarius
349155093Smarius	sc->sc_memsize = LEDMA_MEMSIZE;
350155093Smarius	error = bus_dma_tag_create(
351155093Smarius	    dma->sc_parent_dmat,	/* parent */
352158663Smarius	    LEDMA_ALIGNMENT,		/* alignment */
353158663Smarius	    LEDMA_BOUNDARY,		/* boundary */
354155093Smarius	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
355155093Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
356155093Smarius	    NULL, NULL,			/* filter, filterarg */
357155093Smarius	    sc->sc_memsize,		/* maxsize */
358155093Smarius	    1,				/* nsegments */
359155093Smarius	    sc->sc_memsize,		/* maxsegsize */
360166148Smarius	    0,				/* flags */
361155093Smarius	    NULL, NULL,			/* lockfunc, lockarg */
362155093Smarius	    &lesc->sc_dmat);
363155093Smarius	if (error != 0) {
364155093Smarius		device_printf(dev, "cannot allocate buffer DMA tag\n");
365182876Smarius		goto fail_lsi;
366155093Smarius	}
367155093Smarius
368155093Smarius	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
369155093Smarius	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
370155093Smarius	if (error != 0) {
371155093Smarius		device_printf(dev, "cannot allocate DMA buffer memory\n");
372155093Smarius		goto fail_dtag;
373155093Smarius	}
374155093Smarius
375155093Smarius	lesc->sc_laddr = 0;
376155093Smarius	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
377155093Smarius	    sc->sc_memsize, le_dma_dma_callback, lesc, 0);
378155093Smarius	if (error != 0 || lesc->sc_laddr == 0) {
379182876Smarius		device_printf(dev, "cannot load DMA buffer map\n");
380155093Smarius		goto fail_dmem;
381155093Smarius	}
382155093Smarius
383155093Smarius	sc->sc_addr = lesc->sc_laddr & 0xffffff;
384155093Smarius	sc->sc_flags = 0;
385155093Smarius	sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
386155093Smarius
387155093Smarius	sc->sc_mediachange = le_dma_supmediachange;
388155093Smarius	sc->sc_mediastatus = le_dma_supmediastatus;
389155093Smarius	sc->sc_supmedia = le_dma_supmedia;
390155093Smarius	sc->sc_nsupmedia = sizeof(le_dma_supmedia) / sizeof(le_dma_supmedia[0]);
391155093Smarius	sc->sc_defaultmedia = le_dma_supmedia[0];
392155093Smarius
393155093Smarius	OF_getetheraddr(dev, sc->sc_enaddr);
394155093Smarius
395155093Smarius	sc->sc_copytodesc = lance_copytobuf_contig;
396155093Smarius	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
397155093Smarius	sc->sc_copytobuf = lance_copytobuf_contig;
398155093Smarius	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
399155093Smarius	sc->sc_zerobuf = lance_zerobuf_contig;
400155093Smarius
401155093Smarius	sc->sc_rdcsr = le_dma_rdcsr;
402155093Smarius	sc->sc_wrcsr = le_dma_wrcsr;
403155093Smarius	sc->sc_hwreset = le_dma_hwreset;
404155093Smarius	sc->sc_hwintr = le_dma_hwintr;
405158663Smarius	sc->sc_nocarrier = le_dma_nocarrier;
406155093Smarius
407155093Smarius	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
408155093Smarius	    device_get_unit(dev));
409155093Smarius	if (error != 0) {
410158663Smarius		device_printf(dev, "cannot attach Am7990\n");
411155093Smarius		goto fail_dmap;
412155093Smarius	}
413155093Smarius
414155093Smarius	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
415166901Spiso	    NULL, am7990_intr, sc, &lesc->sc_ih);
416155093Smarius	if (error != 0) {
417155093Smarius		device_printf(dev, "cannot set up interrupt\n");
418155093Smarius		goto fail_am7990;
419155093Smarius	}
420155093Smarius
421155093Smarius	return (0);
422155093Smarius
423155093Smarius fail_am7990:
424155093Smarius	am7990_detach(&lesc->sc_am7990);
425155093Smarius fail_dmap:
426155093Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
427155093Smarius fail_dmem:
428155093Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
429155093Smarius fail_dtag:
430155093Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
431182876Smarius fail_lsi:
432182876Smarius	lsi64854_detach(dma);
433155093Smarius fail_ires:
434182876Smarius	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires),
435182876Smarius	    lesc->sc_ires);
436155093Smarius fail_rres:
437182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres),
438182876Smarius	    lesc->sc_rres);
439155093Smarius fail_mtx:
440155093Smarius	LE_LOCK_DESTROY(sc);
441155093Smarius	return (error);
442155093Smarius}
443155093Smarius
444155093Smariusstatic int
445155093Smariusle_dma_detach(device_t dev)
446155093Smarius{
447155093Smarius	struct le_dma_softc *lesc;
448155093Smarius	struct lance_softc *sc;
449182876Smarius	int error;
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);
459182876Smarius	error = lsi64854_detach(lesc->sc_dma);
460182876Smarius	if (error != 0)
461182876Smarius		return (error);
462182876Smarius	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires),
463182876Smarius	    lesc->sc_ires);
464182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres),
465182876Smarius	    lesc->sc_rres);
466155093Smarius	LE_LOCK_DESTROY(sc);
467155093Smarius
468155093Smarius	return (0);
469155093Smarius}
470155093Smarius
471155093Smariusstatic int
472155093Smariusle_dma_suspend(device_t dev)
473155093Smarius{
474155093Smarius	struct le_dma_softc *lesc;
475155093Smarius
476155093Smarius	lesc = device_get_softc(dev);
477155093Smarius
478155093Smarius	lance_suspend(&lesc->sc_am7990.lsc);
479155093Smarius
480155093Smarius	return (0);
481155093Smarius}
482155093Smarius
483155093Smariusstatic int
484155093Smariusle_dma_resume(device_t dev)
485155093Smarius{
486155093Smarius	struct le_dma_softc *lesc;
487155093Smarius
488155093Smarius	lesc = device_get_softc(dev);
489155093Smarius
490155093Smarius	lance_resume(&lesc->sc_am7990.lsc);
491155093Smarius
492155093Smarius	return (0);
493155093Smarius}
494