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