diff options
Diffstat (limited to 'bsd_eth_drivers/if_le/if_le_pci.c')
-rw-r--r-- | bsd_eth_drivers/if_le/if_le_pci.c | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/bsd_eth_drivers/if_le/if_le_pci.c b/bsd_eth_drivers/if_le/if_le_pci.c new file mode 100644 index 0000000..870ddb8 --- /dev/null +++ b/bsd_eth_drivers/if_le/if_le_pci.c @@ -0,0 +1,671 @@ +/* $NetBSD: if_le_pci.c,v 1.43 2005/12/11 12:22:49 christos Exp $ */ + +/*- + * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 + */ +#ifdef __rtems__ +#include <libbsdport.h> +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/sys/dev/le/if_le_pci.c,v 1.7 2007/02/23 12:18:45 piso Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/resource.h> +#include <sys/rman.h> +#include <sys/socket.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_media.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/le/lancereg.h> +#include <dev/le/lancevar.h> +#include <dev/le/am79900var.h> + +#ifdef __rtems__ +#include <dev/le/am79900reg.h> /* for memory size calculation */ +#include <libbsdport_post.h> +#endif + +#define AMD_VENDOR 0x1022 +#define AMD_PCNET_PCI 0x2000 +#define AMD_PCNET_HOME 0x2001 +#define PCNET_MEMSIZE (32*1024) +#define PCNET_PCI_RDP 0x10 +#define PCNET_PCI_RAP 0x12 +#define PCNET_PCI_BDP 0x16 + +struct le_pci_softc { + struct am79900_softc sc_am79900; /* glue to MI code */ + + int sc_rrid; + struct resource *sc_rres; + bus_space_tag_t sc_regt; + bus_space_handle_t sc_regh; + + int sc_irid; + struct resource *sc_ires; + void *sc_ih; + + bus_dma_tag_t sc_pdmat; + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmam; +}; + +device_probe_t le_pci_probe; +device_attach_t le_pci_attach; +static device_detach_t le_pci_detach; +#ifndef __rtems__ +static device_resume_t le_pci_resume; +static device_suspend_t le_pci_suspend; + +static device_method_t le_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, le_pci_probe), + DEVMETHOD(device_attach, le_pci_attach), + DEVMETHOD(device_detach, le_pci_detach), + /* We can just use the suspend method here. */ + DEVMETHOD(device_shutdown, le_pci_suspend), + DEVMETHOD(device_suspend, le_pci_suspend), + DEVMETHOD(device_resume, le_pci_resume), + + { 0, 0 } +}; + +DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc)); +DRIVER_MODULE(le, pci, le_pci_driver, le_devclass, 0, 0); +MODULE_DEPEND(le, ether, 1, 1, 1); + +#else +static int +le_pci_irq_check_dis(device_t d); + +static void +le_pci_irq_en(device_t d); + +static device_method_t le_pci_methods = { + probe: le_pci_probe, + attach: le_pci_attach, + shutdown: 0, + detach: le_pci_detach, + irq_check_dis: le_pci_irq_check_dis, + irq_en: le_pci_irq_en, +}; + +driver_t libbsdport_le_pci_driver = { + "le", + &le_pci_methods, + DEV_TYPE_PCI, + sizeof(struct le_pci_softc) +}; + +#endif + +static const int le_home_supmedia[] = { + IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0) +}; + +static const int le_pci_supmedia[] = { + IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), + IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FDX, 0), + IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0), + IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, 0), + IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0), + IFM_MAKEWORD(IFM_ETHER, IFM_10_5, IFM_FDX, 0) +}; + + +static void le_pci_wrbcr(struct lance_softc *, uint16_t, uint16_t); +static uint16_t le_pci_rdbcr(struct lance_softc *, uint16_t); +static void le_pci_wrcsr(struct lance_softc *, uint16_t, uint16_t); +static uint16_t le_pci_rdcsr(struct lance_softc *, uint16_t); +static int le_pci_mediachange(struct lance_softc *); +static void le_pci_hwreset(struct lance_softc *); +static bus_dmamap_callback_t le_pci_dma_callback; + +static void +le_pci_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val) +{ + struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_BDP, val); +} + +static uint16_t +le_pci_rdbcr(struct lance_softc *sc, uint16_t port) +{ + struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_BDP)); +} + +static void +le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) +{ + struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP, val); +} + +static uint16_t +le_pci_rdcsr(struct lance_softc *sc, uint16_t port) +{ + struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP)); +} + +static int +le_pci_mediachange(struct lance_softc *sc) +{ + struct ifmedia *ifm = &sc->sc_media; + uint16_t reg; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) + le_pci_wrbcr(sc, LE_BCR49, + (le_pci_rdbcr(sc, LE_BCR49) & ~LE_B49_PHYSEL) | 0x1); + else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) + le_pci_wrbcr(sc, LE_BCR2, + le_pci_rdbcr(sc, LE_BCR2) | LE_B2_ASEL); + else { + le_pci_wrbcr(sc, LE_BCR2, + le_pci_rdbcr(sc, LE_BCR2) & ~LE_B2_ASEL); + + reg = le_pci_rdcsr(sc, LE_CSR15); + reg &= ~LE_C15_PORTSEL(LE_PORTSEL_MASK); + if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) + reg |= LE_C15_PORTSEL(LE_PORTSEL_10T); + else + reg |= LE_C15_PORTSEL(LE_PORTSEL_AUI); + le_pci_wrcsr(sc, LE_CSR15, reg); + } + + reg = le_pci_rdbcr(sc, LE_BCR9); + if (IFM_OPTIONS(ifm->ifm_media) & IFM_FDX) { + reg |= LE_B9_FDEN; + /* + * Allow FDX on AUI only if explicitly chosen, + * not in autoselect mode. + */ + if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_5) + reg |= LE_B9_AUIFD; + else + reg &= ~LE_B9_AUIFD; + } else + reg &= ~LE_B9_FDEN; + le_pci_wrbcr(sc, LE_BCR9, reg); + + return (0); +} + +static void +le_pci_hwreset(struct lance_softc *sc) +{ + + /* + * Chip is stopped. Set software style to PCnet-PCI (32-bit). + * Actually, am79900.c implements ILACC support (hence its + * name) but unfortunately VMware does not. As far as this + * driver is concerned that should not make a difference + * though, as the settings used have the same meaning for + * both, ILACC and PCnet-PCI (note that there would be a + * difference for the ADD_FCS/NO_FCS bit if used). + */ + le_pci_wrbcr(sc, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2); +} + +static void +le_pci_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct lance_softc *sc = (struct lance_softc *)xsc; + + if (error != 0) + return; + KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__)); + sc->sc_addr = segs[0].ds_addr; +} + +int +le_pci_probe(device_t dev) +{ + + if (pci_get_vendor(dev) != AMD_VENDOR) + return (ENXIO); + + switch (pci_get_device(dev)) { + case AMD_PCNET_PCI: + device_set_desc(dev, "AMD PCnet-PCI"); + /* Let pcn(4) win. */ + return (BUS_PROBE_LOW_PRIORITY); + case AMD_PCNET_HOME: + device_set_desc(dev, "AMD PCnet-Home"); + /* Let pcn(4) win. */ + return (BUS_PROBE_LOW_PRIORITY); + default: + return (ENXIO); + } +} + +int +le_pci_attach(device_t dev) +{ + struct le_pci_softc *lesc; + struct lance_softc *sc; + int error, i; + + lesc = device_get_softc(dev); + sc = &lesc->sc_am79900.lsc; + + LE_LOCK_INIT(sc, device_get_nameunit(dev)); + + pci_enable_busmaster(dev); + pci_enable_io(dev, PCIM_CMD_PORTEN); + + lesc->sc_rrid = PCIR_BAR(0); + lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &lesc->sc_rrid, RF_ACTIVE); + if (lesc->sc_rres == NULL) { + device_printf(dev, "cannot allocate registers\n"); + error = ENXIO; + goto fail_mtx; + } + lesc->sc_regt = rman_get_bustag(lesc->sc_rres); + lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); + + lesc->sc_irid = 0; + if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "cannot allocate interrupt\n"); + error = ENXIO; + goto fail_rres; + } + + error = bus_dma_tag_create( + bus_get_dma_tag(dev), /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ + 0, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &lesc->sc_pdmat); + if (error != 0) { + device_printf(dev, "cannot allocate parent DMA tag\n"); + goto fail_ires; + } + + sc->sc_memsize = PCNET_MEMSIZE; + +#ifdef __rtems__ + { + int nbuf = 0; + /* Override ring sizes */ + if ( dev->ifconfig ) { + nbuf += (sc->sc_nrbuf = dev->ifconfig->rbuf_count); + nbuf += (sc->sc_ntbuf = dev->ifconfig->xbuf_count); + } + if ( nbuf ) { + /* at least one of them is set */ + if ( !sc->sc_ntbuf ) { + sc->sc_ntbuf = nbuf/4; /* default proportions as in lance.c */ + /* need at least one */ + if ( !sc->sc_ntbuf ) + sc->sc_ntbuf = 1; + } + if ( !sc->sc_nrbuf ) + sc->sc_nrbuf = nbuf*4; /* default proportions as in lance.c */ + /* It seems the driver assumes ring sizes to be powers of two; + * (look for ffs()-1). + * So we give them what they want. + */ + /* both, nrbuf / ntbuf are > 0 at this point */ + for ( nbuf = 1; nbuf < sc->sc_nrbuf; nbuf<<=1 ) + /* nothing else to do*/; + sc->sc_nrbuf = nbuf; + for ( nbuf = 1; nbuf < sc->sc_ntbuf; nbuf<<=1 ) + /* nothing else to do*/; + sc->sc_ntbuf = nbuf; + + nbuf = sc->sc_ntbuf + sc->sc_nrbuf; + + /* now override memory size; still need to override + * individual ring sizes in 'lance.c' :-( + */ + sc->sc_memsize = nbuf * (LEBLEN + sizeof(struct lermd) + sizeof(struct letmd)) ; + sc->sc_memsize+= sizeof(struct leinit); + } + } +#endif + /* + * For Am79C970A, Am79C971 and Am79C978 the init block must be 2-byte + * aligned and the ring descriptors must be 16-byte aligned when using + * a 32-bit software style. + */ + error = bus_dma_tag_create( + lesc->sc_pdmat, /* parent */ + 16, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->sc_memsize, /* maxsize */ + 1, /* nsegments */ + sc->sc_memsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &lesc->sc_dmat); + if (error != 0) { + device_printf(dev, "cannot allocate buffer DMA tag\n"); + goto fail_pdtag; + } + + error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, + BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); + if (error != 0) { + device_printf(dev, "cannot allocate DMA buffer memory\n"); + goto fail_dtag; + } + + sc->sc_addr = 0; + error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, + sc->sc_memsize, le_pci_dma_callback, sc, 0); + if (error != 0 || sc->sc_addr == 0) { + device_printf(dev, "cannot load DMA buffer map\n"); + goto fail_dmem; + } + + sc->sc_flags = LE_BSWAP; + sc->sc_conf3 = 0; + + sc->sc_mediastatus = NULL; + switch (pci_get_device(dev)) { + case AMD_PCNET_HOME: + sc->sc_mediachange = le_pci_mediachange; + sc->sc_supmedia = le_home_supmedia; + sc->sc_nsupmedia = sizeof(le_home_supmedia) / sizeof(int); + sc->sc_defaultmedia = le_home_supmedia[0]; + break; + default: + sc->sc_mediachange = le_pci_mediachange; + sc->sc_supmedia = le_pci_supmedia; + sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int); + sc->sc_defaultmedia = le_pci_supmedia[0]; + } + + /* + * Extract the physical MAC address from the ROM. + */ + for (i = 0; i < sizeof(sc->sc_enaddr); i++) + sc->sc_enaddr[i] = + bus_space_read_1(lesc->sc_regt, lesc->sc_regh, i); + + sc->sc_copytodesc = lance_copytobuf_contig; + sc->sc_copyfromdesc = lance_copyfrombuf_contig; + sc->sc_copytobuf = lance_copytobuf_contig; + sc->sc_copyfrombuf = lance_copyfrombuf_contig; + sc->sc_zerobuf = lance_zerobuf_contig; + + sc->sc_rdcsr = le_pci_rdcsr; + sc->sc_wrcsr = le_pci_wrcsr; + sc->sc_hwreset = le_pci_hwreset; + sc->sc_hwinit = NULL; + sc->sc_hwintr = NULL; + sc->sc_nocarrier = NULL; + + error = am79900_config(&lesc->sc_am79900, device_get_name(dev), + device_get_unit(dev)); + if (error != 0) { + device_printf(dev, "cannot attach Am79900\n"); + goto fail_dmap; + } + + error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, + NULL, am79900_intr, sc, &lesc->sc_ih); + if (error != 0) { + device_printf(dev, "cannot set up interrupt\n"); + goto fail_am79900; + } + + return (0); + + fail_am79900: + am79900_detach(&lesc->sc_am79900); + fail_dmap: + bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); + fail_dmem: + bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); + fail_dtag: + bus_dma_tag_destroy(lesc->sc_dmat); + fail_pdtag: + bus_dma_tag_destroy(lesc->sc_pdmat); + fail_ires: + bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); + fail_rres: + bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); + fail_mtx: + LE_LOCK_DESTROY(sc); + return (error); +} + +static int +le_pci_detach(device_t dev) +{ + struct le_pci_softc *lesc; + struct lance_softc *sc; + + lesc = device_get_softc(dev); + sc = &lesc->sc_am79900.lsc; + + bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); + am79900_detach(&lesc->sc_am79900); + bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); + bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); + bus_dma_tag_destroy(lesc->sc_dmat); + bus_dma_tag_destroy(lesc->sc_pdmat); + bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); + bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); + LE_LOCK_DESTROY(sc); + + return (0); +} + +#ifndef __rtems__ +static int +le_pci_suspend(device_t dev) +{ + struct le_pci_softc *lesc; + + lesc = device_get_softc(dev); + + lance_suspend(&lesc->sc_am79900.lsc); + + return (0); +} + +static int +le_pci_resume(device_t dev) +{ + struct le_pci_softc *lesc; + + lesc = device_get_softc(dev); + + lance_resume(&lesc->sc_am79900.lsc); + + return (0); +} +#else +static int +le_pci_irq_check_dis(device_t d) +{ +struct le_pci_softc *lesc = device_get_softc(d); +/* This can be called from IRQ context -- since all register accesses + * involve RAP we must take care to preserve it across this routine! + */ +u_int16_t rap = bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP); +u_int16_t csr; +int rval; + + csr = le_pci_rdcsr(&lesc->sc_am79900.lsc, LE_CSR0); + if ( LE_C0_INTR & csr ) { + /* must not write 1 to any bit as this might clear things */ + le_pci_wrcsr(&lesc->sc_am79900.lsc, LE_CSR0, LE_C0_INEA & ~(LE_C0_INEA)); + rval = FILTER_HANDLED; + } else { + rval = FILTER_STRAY; + } + /* restore RAP */ + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, rap); + return rval; +} + +static void +le_pci_irq_en(device_t d) +{ +struct le_pci_softc *lesc = device_get_softc(d); +/* This can be called from IRQ context -- since all register accesses + * involve RAP we must take care to preserve it across this routine! + */ +u_int16_t rap = bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP); + /* do NOT |= INTEN because writing 1es in the wrong place may clear flags */ + le_pci_wrcsr(&lesc->sc_am79900.lsc, LE_CSR0, LE_C0_INEA); + /* restore RAP */ + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, rap); +} + +u_int32_t +le_pci_read_csr(device_t d, int off) +{ +u_int32_t rval; + rtems_bsdnet_semaphore_obtain(); + rval = le_pci_rdcsr(device_get_softc(d), off); + rtems_bsdnet_semaphore_release(); + return rval; +} + +void +le_pci_write_csr(device_t d, int off, u_int16_t v) +{ + rtems_bsdnet_semaphore_obtain(); + le_pci_wrcsr(device_get_softc(d), off, v); + rtems_bsdnet_semaphore_release(); +} + + +u_int32_t +le_pci_read_bcr(device_t d, int off) +{ +u_int32_t rval; + rtems_bsdnet_semaphore_obtain(); + rval = le_pci_rdbcr(device_get_softc(d), off); + rtems_bsdnet_semaphore_release(); + return rval; +} + +void +le_pci_write_bcr(device_t d, int off, u_int16_t v) +{ + rtems_bsdnet_semaphore_obtain(); + le_pci_wrbcr(device_get_softc(d), off, v); + rtems_bsdnet_semaphore_release(); +} + + +#endif |