if_le_cbus.c revision 166901
1158712Smarius/*-
2158712Smarius * Copyright (c) 1994-2000
3158712Smarius *	Paul Richards. All rights reserved.
4158712Smarius *
5158712Smarius * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
6158712Smarius *
7158712Smarius * Redistribution and use in source and binary forms, with or without
8158712Smarius * modification, are permitted provided that the following conditions
9158712Smarius * are met:
10158712Smarius * 1. Redistributions of source code must retain the above copyright
11158712Smarius *    notice, this list of conditions and the following disclaimer,
12158712Smarius *    verbatim and that no modifications are made prior to this
13158712Smarius *    point in the file.
14158712Smarius * 2. Redistributions in binary form must reproduce the above copyright
15158712Smarius *    notice, this list of conditions and the following disclaimer in the
16158712Smarius *    documentation and/or other materials provided with the distribution.
17158712Smarius * 3. The name Paul Richards may not be used to endorse or promote products
18158712Smarius *    derived from this software without specific prior written permission.
19158712Smarius *
20158712Smarius * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
21158712Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22158712Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23158712Smarius * ARE DISCLAIMED.  IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
24158712Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25158712Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26158712Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27158712Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28158712Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29158712Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30158712Smarius * SUCH DAMAGE.
31158712Smarius *
32158712Smarius *	from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
33158712Smarius */
34158712Smarius
35158712Smarius#include <sys/cdefs.h>
36158712Smarius__FBSDID("$FreeBSD: head/sys/dev/le/if_le_cbus.c 166901 2007-02-23 12:19:07Z piso $");
37158712Smarius
38158712Smarius#include <sys/param.h>
39158712Smarius#include <sys/systm.h>
40158712Smarius#include <sys/bus.h>
41158712Smarius#include <sys/endian.h>
42158712Smarius#include <sys/kernel.h>
43158712Smarius#include <sys/lock.h>
44158712Smarius#include <sys/module.h>
45158712Smarius#include <sys/mutex.h>
46158712Smarius#include <sys/resource.h>
47158712Smarius#include <sys/rman.h>
48158712Smarius#include <sys/socket.h>
49158712Smarius
50158712Smarius#include <net/ethernet.h>
51158712Smarius#include <net/if.h>
52158712Smarius#include <net/if_media.h>
53158712Smarius
54158712Smarius#include <machine/bus.h>
55158712Smarius#include <machine/resource.h>
56158712Smarius
57158712Smarius#include <isa/isavar.h>
58158712Smarius
59158712Smarius#include <dev/le/lancereg.h>
60158712Smarius#include <dev/le/lancevar.h>
61158712Smarius#include <dev/le/am7990var.h>
62158712Smarius
63158712Smarius#define	LE_CBUS_MEMSIZE	(16*1024)
64158712Smarius#define	CNET98S_IOSIZE	32
65158712Smarius#define	CNET98S_RDP	0x10
66158712Smarius#define	CNET98S_RAP	0x12
67158712Smarius#define	CNET98S_RESET	0x14
68158712Smarius#define	CNET98S_BDP	0x16
69158712Smarius
70158712Smariusstruct le_cbus_softc {
71158712Smarius	struct am7990_softc	sc_am7990;	/* glue to MI code */
72158712Smarius
73158712Smarius	int			sc_rrid;
74158712Smarius	struct resource		*sc_rres;
75158712Smarius	bus_space_tag_t		sc_regt;
76158712Smarius	bus_space_handle_t	sc_regh;
77158712Smarius
78158712Smarius	int			sc_irid;
79158712Smarius	struct resource		*sc_ires;
80158712Smarius	void			*sc_ih;
81158712Smarius
82158712Smarius	bus_dma_tag_t		sc_pdmat;
83158712Smarius	bus_dma_tag_t		sc_dmat;
84158712Smarius	bus_dmamap_t		sc_dmam;
85158712Smarius};
86158712Smarius
87158712Smariusstatic device_probe_t le_cbus_probe;
88158712Smariusstatic device_attach_t le_cbus_attach;
89158712Smariusstatic device_detach_t le_cbus_detach;
90158712Smariusstatic device_resume_t le_cbus_resume;
91158712Smariusstatic device_suspend_t le_cbus_suspend;
92158712Smarius
93158712Smariusstatic device_method_t le_cbus_methods[] = {
94158712Smarius	/* Device interface */
95158712Smarius	DEVMETHOD(device_probe,		le_cbus_probe),
96158712Smarius	DEVMETHOD(device_attach,	le_cbus_attach),
97158712Smarius	DEVMETHOD(device_detach,	le_cbus_detach),
98158712Smarius	/* We can just use the suspend method here. */
99158712Smarius	DEVMETHOD(device_shutdown,	le_cbus_suspend),
100158712Smarius	DEVMETHOD(device_suspend,	le_cbus_suspend),
101158712Smarius	DEVMETHOD(device_resume,	le_cbus_resume),
102158712Smarius
103158712Smarius	{ 0, 0 }
104158712Smarius};
105158712Smarius
106158712SmariusDEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
107158829SnyanDRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
108158712SmariusMODULE_DEPEND(le, ether, 1, 1, 1);
109158712Smarius
110158712Smariusstatic bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = {
111158712Smarius	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
112158712Smarius	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
113158712Smarius	0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
114158712Smarius	0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
115158712Smarius};
116158712Smarius
117158712Smariusstatic void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
118158712Smarius#ifdef LEDEBUG
119158712Smariusstatic uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
120158712Smarius#endif
121158712Smariusstatic void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
122158712Smariusstatic uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
123158712Smariusstatic void le_cbus_hwreset(struct lance_softc *);
124158712Smariusstatic bus_dmamap_callback_t le_cbus_dma_callback;
125158712Smarius
126158712Smariusstatic void
127158712Smariusle_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
128158712Smarius{
129158712Smarius	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
130158712Smarius
131158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
132158712Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
133158712Smarius	    BUS_SPACE_BARRIER_WRITE);
134158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP, val);
135158712Smarius}
136158712Smarius
137158712Smarius#ifdef LEDEBUG
138158712Smariusstatic uint16_t
139158712Smariusle_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
140158712Smarius{
141158712Smarius	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
142158712Smarius
143158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
144158712Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
145158712Smarius	    BUS_SPACE_BARRIER_WRITE);
146158712Smarius	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP));
147158712Smarius}
148158712Smarius#endif
149158712Smarius
150158712Smariusstatic void
151158712Smariusle_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
152158712Smarius{
153158712Smarius	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
154158712Smarius
155158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
156158712Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
157158712Smarius	    BUS_SPACE_BARRIER_WRITE);
158158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP, val);
159158712Smarius}
160158712Smarius
161158712Smariusstatic uint16_t
162158712Smariusle_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
163158712Smarius{
164158712Smarius	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
165158712Smarius
166158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
167158712Smarius	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
168158712Smarius	    BUS_SPACE_BARRIER_WRITE);
169158712Smarius	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP));
170158712Smarius}
171158712Smarius
172158712Smariusstatic void
173158712Smariusle_cbus_hwreset(struct lance_softc *sc)
174158712Smarius{
175158712Smarius	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
176158712Smarius
177158712Smarius	/*
178158712Smarius	 * NB: These are Contec C-NET(98)S only.
179158712Smarius	 */
180158712Smarius
181158712Smarius	/* Reset the chip. */
182158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
183158712Smarius	    bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
184158712Smarius	DELAY(500);
185158712Smarius
186158712Smarius	/* ISA bus configuration */
187158712Smarius	/* ISACSR0 - set Master Mode Read Active time to 300ns. */
188158712Smarius    	le_cbus_wrbcr(sc, LE_BCR0, 0x0006);
189158712Smarius	/* ISACSR1 - set Master Mode Write Active time to 300ns. */
190158712Smarius    	le_cbus_wrbcr(sc, LE_BCR1, 0x0006);
191158712Smarius#ifdef LEDEBUG
192158712Smarius	device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2));
193158712Smarius#endif
194158712Smarius	/* ISACSR5 - LED1 */
195158712Smarius	le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE);
196158712Smarius	/* ISACSR6 - LED2 */
197158712Smarius	le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE);
198158712Smarius	/* ISACSR7 - LED3 */
199158712Smarius	le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE);
200158712Smarius}
201158712Smarius
202158712Smariusstatic void
203158712Smariusle_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
204158712Smarius{
205158712Smarius	struct lance_softc *sc = (struct lance_softc *)xsc;
206158712Smarius
207158712Smarius	if (error != 0)
208158712Smarius		return;
209158712Smarius	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
210158712Smarius	sc->sc_addr = segs[0].ds_addr;
211158712Smarius}
212158712Smarius
213158712Smariusstatic int
214158712Smariusle_cbus_probe(device_t dev)
215158712Smarius{
216158712Smarius	struct le_cbus_softc *lesc;
217158712Smarius	struct lance_softc *sc;
218158712Smarius	int error;
219158712Smarius
220158829Snyan	/*
221158829Snyan	 * Skip PnP devices as some wedge when trying to probe them as
222158829Snyan	 * C-NET(98)S.
223158829Snyan	 */
224158829Snyan	if (isa_get_vendorid(dev))
225158829Snyan		return (ENXIO);
226158829Snyan
227158712Smarius	lesc = device_get_softc(dev);
228158712Smarius	sc = &lesc->sc_am7990.lsc;
229158712Smarius
230158712Smarius	lesc->sc_rrid = 0;
231158712Smarius	lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
232158712Smarius	    le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
233158712Smarius	if (lesc->sc_rres == NULL)
234158712Smarius		return (ENXIO);
235158712Smarius	isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
236158712Smarius	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
237158712Smarius	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
238158712Smarius
239158712Smarius	/* Reset the chip. */
240158712Smarius	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
241158712Smarius	    bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
242158712Smarius	DELAY(500);
243158712Smarius
244158712Smarius	/* Stop the chip and put it in a known state. */
245158712Smarius	le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP);
246158712Smarius	DELAY(100);
247158712Smarius	if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
248158712Smarius		error = ENXIO;
249158712Smarius		goto fail;
250158712Smarius	}
251158712Smarius	le_cbus_wrcsr(sc, LE_CSR3, 0);
252158712Smarius	device_set_desc(dev, "C-NET(98)S");
253158712Smarius	error = BUS_PROBE_DEFAULT;
254158712Smarius
255158712Smarius fail:
256158712Smarius	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
257158712Smarius	return (error);
258158712Smarius}
259158712Smarius
260158712Smariusstatic int
261158712Smariusle_cbus_attach(device_t dev)
262158712Smarius{
263158712Smarius	struct le_cbus_softc *lesc;
264158712Smarius	struct lance_softc *sc;
265158712Smarius	int error, i;
266158712Smarius
267158712Smarius	lesc = device_get_softc(dev);
268158712Smarius	sc = &lesc->sc_am7990.lsc;
269158712Smarius
270158712Smarius	LE_LOCK_INIT(sc, device_get_nameunit(dev));
271158712Smarius
272158712Smarius	lesc->sc_rrid = 0;
273158712Smarius	lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
274158712Smarius	    le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
275158712Smarius	if (lesc->sc_rres == NULL) {
276158712Smarius		device_printf(dev, "cannot allocate registers\n");
277158712Smarius		error = ENXIO;
278158712Smarius		goto fail_mtx;
279158712Smarius	}
280158712Smarius	isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
281158712Smarius	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
282158712Smarius	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
283158712Smarius
284158712Smarius	lesc->sc_irid = 0;
285158712Smarius	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
286158712Smarius	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
287158712Smarius		device_printf(dev, "cannot allocate interrupt\n");
288158712Smarius		error = ENXIO;
289158712Smarius		goto fail_rres;
290158712Smarius	}
291158712Smarius
292158712Smarius	error = bus_dma_tag_create(
293166138Smarius	    bus_get_dma_tag(dev),	/* parent */
294158712Smarius	    1, 0,			/* alignment, boundary */
295158712Smarius	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
296158712Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
297158712Smarius	    NULL, NULL,			/* filter, filterarg */
298158712Smarius	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
299158712Smarius	    0,				/* nsegments */
300158712Smarius	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
301166148Smarius	    0,				/* flags */
302158712Smarius	    NULL, NULL,			/* lockfunc, lockarg */
303158712Smarius	    &lesc->sc_pdmat);
304158712Smarius	if (error != 0) {
305158712Smarius		device_printf(dev, "cannot allocate parent DMA tag\n");
306158712Smarius		goto fail_ires;
307158712Smarius	}
308158712Smarius
309158712Smarius	sc->sc_memsize = LE_CBUS_MEMSIZE;
310158712Smarius	/*
311158712Smarius	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
312158712Smarius	 * aligned and the ring descriptors must be 8-byte aligned.
313158712Smarius	 */
314158712Smarius	error = bus_dma_tag_create(
315158712Smarius	    lesc->sc_pdmat,		/* parent */
316158712Smarius	    8, 0,			/* alignment, boundary */
317158712Smarius	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
318158712Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
319158712Smarius	    NULL, NULL,			/* filter, filterarg */
320158712Smarius	    sc->sc_memsize,		/* maxsize */
321158712Smarius	    1,				/* nsegments */
322158712Smarius	    sc->sc_memsize,		/* maxsegsize */
323166148Smarius	    0,				/* flags */
324158712Smarius	    NULL, NULL,			/* lockfunc, lockarg */
325158712Smarius	    &lesc->sc_dmat);
326158712Smarius	if (error != 0) {
327158712Smarius		device_printf(dev, "cannot allocate buffer DMA tag\n");
328158712Smarius		goto fail_pdtag;
329158712Smarius	}
330158712Smarius
331158712Smarius	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
332158712Smarius	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
333158712Smarius	if (error != 0) {
334158712Smarius		device_printf(dev, "cannot allocate DMA buffer memory\n");
335158712Smarius		goto fail_dtag;
336158712Smarius	}
337158712Smarius
338158712Smarius	sc->sc_addr = 0;
339158712Smarius	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
340158712Smarius	    sc->sc_memsize, le_cbus_dma_callback, sc, 0);
341158712Smarius	if (error != 0 || sc->sc_addr == 0) {
342158712Smarius                device_printf(dev, "cannot load DMA buffer map\n");
343158712Smarius		goto fail_dmem;
344158712Smarius	}
345158712Smarius
346158712Smarius	sc->sc_flags = 0;
347158712Smarius	sc->sc_conf3 = 0;
348158712Smarius
349158712Smarius	/*
350158712Smarius	 * Extract the physical MAC address from the ROM.
351158712Smarius	 */
352158712Smarius	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
353158712Smarius		sc->sc_enaddr[i] =  bus_space_read_1(lesc->sc_regt,
354158712Smarius		    lesc->sc_regh, i * 2);
355158712Smarius
356158712Smarius	sc->sc_copytodesc = lance_copytobuf_contig;
357158712Smarius	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
358158712Smarius	sc->sc_copytobuf = lance_copytobuf_contig;
359158712Smarius	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
360158712Smarius	sc->sc_zerobuf = lance_zerobuf_contig;
361158712Smarius
362158712Smarius	sc->sc_rdcsr = le_cbus_rdcsr;
363158712Smarius	sc->sc_wrcsr = le_cbus_wrcsr;
364158712Smarius	sc->sc_hwreset = le_cbus_hwreset;
365158712Smarius	sc->sc_hwinit = NULL;
366158712Smarius	sc->sc_hwintr = NULL;
367158712Smarius	sc->sc_nocarrier = NULL;
368158712Smarius	sc->sc_mediachange = NULL;
369158712Smarius	sc->sc_mediastatus = NULL;
370158712Smarius	sc->sc_supmedia = NULL;
371158712Smarius
372158712Smarius	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
373158712Smarius	    device_get_unit(dev));
374158712Smarius	if (error != 0) {
375158712Smarius		device_printf(dev, "cannot attach Am7990\n");
376158712Smarius		goto fail_dmap;
377158712Smarius	}
378158712Smarius
379158712Smarius	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
380166901Spiso	    NULL, am7990_intr, sc, &lesc->sc_ih);
381158712Smarius	if (error != 0) {
382158712Smarius		device_printf(dev, "cannot set up interrupt\n");
383158712Smarius		goto fail_am7990;
384158712Smarius	}
385158712Smarius
386158712Smarius	return (0);
387158712Smarius
388158712Smarius fail_am7990:
389158712Smarius	am7990_detach(&lesc->sc_am7990);
390158712Smarius fail_dmap:
391158712Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
392158712Smarius fail_dmem:
393158712Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
394158712Smarius fail_dtag:
395158712Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
396158712Smarius fail_pdtag:
397158712Smarius	bus_dma_tag_destroy(lesc->sc_pdmat);
398158712Smarius fail_ires:
399158712Smarius	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
400158712Smarius fail_rres:
401158712Smarius	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
402158712Smarius fail_mtx:
403158712Smarius	LE_LOCK_DESTROY(sc);
404158712Smarius	return (error);
405158712Smarius}
406158712Smarius
407158712Smariusstatic int
408158712Smariusle_cbus_detach(device_t dev)
409158712Smarius{
410158712Smarius	struct le_cbus_softc *lesc;
411158712Smarius	struct lance_softc *sc;
412158712Smarius
413158712Smarius	lesc = device_get_softc(dev);
414158712Smarius	sc = &lesc->sc_am7990.lsc;
415158712Smarius
416158712Smarius	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
417158712Smarius	am7990_detach(&lesc->sc_am7990);
418158712Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
419158712Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
420158712Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
421158712Smarius	bus_dma_tag_destroy(lesc->sc_pdmat);
422158712Smarius	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
423158712Smarius	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
424158712Smarius	LE_LOCK_DESTROY(sc);
425158712Smarius
426158712Smarius	return (0);
427158712Smarius}
428158712Smarius
429158712Smariusstatic int
430158712Smariusle_cbus_suspend(device_t dev)
431158712Smarius{
432158712Smarius	struct le_cbus_softc *lesc;
433158712Smarius
434158712Smarius	lesc = device_get_softc(dev);
435158712Smarius
436158712Smarius	lance_suspend(&lesc->sc_am7990.lsc);
437158712Smarius
438158712Smarius	return (0);
439158712Smarius}
440158712Smarius
441158712Smariusstatic int
442158712Smariusle_cbus_resume(device_t dev)
443158712Smarius{
444158712Smarius	struct le_cbus_softc *lesc;
445158712Smarius
446158712Smarius	lesc = device_get_softc(dev);
447158712Smarius
448158712Smarius	lance_resume(&lesc->sc_am7990.lsc);
449158712Smarius
450158712Smarius	return (0);
451158712Smarius}
452