1a7ee7a7dSMarius Strobl /* $NetBSD: if_le_pci.c,v 1.43 2005/12/11 12:22:49 christos Exp $ */ 2a7ee7a7dSMarius Strobl 3a7ee7a7dSMarius Strobl /*- 4a7ee7a7dSMarius Strobl * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5a7ee7a7dSMarius Strobl * All rights reserved. 6a7ee7a7dSMarius Strobl * 7a7ee7a7dSMarius Strobl * This code is derived from software contributed to The NetBSD Foundation 8a7ee7a7dSMarius Strobl * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 9a7ee7a7dSMarius Strobl * Simulation Facility, NASA Ames Research Center. 10a7ee7a7dSMarius Strobl * 11a7ee7a7dSMarius Strobl * Redistribution and use in source and binary forms, with or without 12a7ee7a7dSMarius Strobl * modification, are permitted provided that the following conditions 13a7ee7a7dSMarius Strobl * are met: 14a7ee7a7dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 15a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer. 16a7ee7a7dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 17a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 18a7ee7a7dSMarius Strobl * documentation and/or other materials provided with the distribution. 19a7ee7a7dSMarius Strobl * 3. All advertising materials mentioning features or use of this software 20a7ee7a7dSMarius Strobl * must display the following acknowledgement: 21a7ee7a7dSMarius Strobl * This product includes software developed by the NetBSD 22a7ee7a7dSMarius Strobl * Foundation, Inc. and its contributors. 23a7ee7a7dSMarius Strobl * 4. Neither the name of The NetBSD Foundation nor the names of its 24a7ee7a7dSMarius Strobl * contributors may be used to endorse or promote products derived 25a7ee7a7dSMarius Strobl * from this software without specific prior written permission. 26a7ee7a7dSMarius Strobl * 27a7ee7a7dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28a7ee7a7dSMarius Strobl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29a7ee7a7dSMarius Strobl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30a7ee7a7dSMarius Strobl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31a7ee7a7dSMarius Strobl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32a7ee7a7dSMarius Strobl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33a7ee7a7dSMarius Strobl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34a7ee7a7dSMarius Strobl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35a7ee7a7dSMarius Strobl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36a7ee7a7dSMarius Strobl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37a7ee7a7dSMarius Strobl * POSSIBILITY OF SUCH DAMAGE. 38a7ee7a7dSMarius Strobl */ 39a7ee7a7dSMarius Strobl 40a7ee7a7dSMarius Strobl /*- 41a7ee7a7dSMarius Strobl * Copyright (c) 1992, 1993 42a7ee7a7dSMarius Strobl * The Regents of the University of California. All rights reserved. 43a7ee7a7dSMarius Strobl * 44a7ee7a7dSMarius Strobl * This code is derived from software contributed to Berkeley by 45a7ee7a7dSMarius Strobl * Ralph Campbell and Rick Macklem. 46a7ee7a7dSMarius Strobl * 47a7ee7a7dSMarius Strobl * Redistribution and use in source and binary forms, with or without 48a7ee7a7dSMarius Strobl * modification, are permitted provided that the following conditions 49a7ee7a7dSMarius Strobl * are met: 50a7ee7a7dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 51a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer. 52a7ee7a7dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 53a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 54a7ee7a7dSMarius Strobl * documentation and/or other materials provided with the distribution. 55a7ee7a7dSMarius Strobl * 3. Neither the name of the University nor the names of its contributors 56a7ee7a7dSMarius Strobl * may be used to endorse or promote products derived from this software 57a7ee7a7dSMarius Strobl * without specific prior written permission. 58a7ee7a7dSMarius Strobl * 59a7ee7a7dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60a7ee7a7dSMarius Strobl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61a7ee7a7dSMarius Strobl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62a7ee7a7dSMarius Strobl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63a7ee7a7dSMarius Strobl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64a7ee7a7dSMarius Strobl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65a7ee7a7dSMarius Strobl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66a7ee7a7dSMarius Strobl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67a7ee7a7dSMarius Strobl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68a7ee7a7dSMarius Strobl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69a7ee7a7dSMarius Strobl * SUCH DAMAGE. 70a7ee7a7dSMarius Strobl * 71a7ee7a7dSMarius Strobl * @(#)if_le.c 8.2 (Berkeley) 11/16/93 72a7ee7a7dSMarius Strobl */ 73a7ee7a7dSMarius Strobl 74a7ee7a7dSMarius Strobl #include <sys/cdefs.h> 75a7ee7a7dSMarius Strobl __FBSDID("$FreeBSD$"); 76a7ee7a7dSMarius Strobl 77a7ee7a7dSMarius Strobl #include <sys/param.h> 78a7ee7a7dSMarius Strobl #include <sys/systm.h> 79a7ee7a7dSMarius Strobl #include <sys/bus.h> 80a7ee7a7dSMarius Strobl #include <sys/endian.h> 81a7ee7a7dSMarius Strobl #include <sys/kernel.h> 82a7ee7a7dSMarius Strobl #include <sys/lock.h> 83a7ee7a7dSMarius Strobl #include <sys/module.h> 84a7ee7a7dSMarius Strobl #include <sys/mutex.h> 85a7ee7a7dSMarius Strobl #include <sys/resource.h> 86a7ee7a7dSMarius Strobl #include <sys/rman.h> 87a7ee7a7dSMarius Strobl #include <sys/socket.h> 88a7ee7a7dSMarius Strobl 89a7ee7a7dSMarius Strobl #include <net/ethernet.h> 90a7ee7a7dSMarius Strobl #include <net/if.h> 91a7ee7a7dSMarius Strobl #include <net/if_media.h> 92a7ee7a7dSMarius Strobl 93a7ee7a7dSMarius Strobl #include <machine/bus.h> 94a7ee7a7dSMarius Strobl #include <machine/resource.h> 95a7ee7a7dSMarius Strobl 96a7ee7a7dSMarius Strobl #include <dev/pci/pcireg.h> 97a7ee7a7dSMarius Strobl #include <dev/pci/pcivar.h> 98a7ee7a7dSMarius Strobl 99a7ee7a7dSMarius Strobl #include <dev/le/lancereg.h> 100a7ee7a7dSMarius Strobl #include <dev/le/lancevar.h> 101a7ee7a7dSMarius Strobl #include <dev/le/am79900var.h> 102a7ee7a7dSMarius Strobl 103a7ee7a7dSMarius Strobl #define AMD_VENDOR 0x1022 104a7ee7a7dSMarius Strobl #define AMD_PCNET_PCI 0x2000 105a7ee7a7dSMarius Strobl #define AMD_PCNET_HOME 0x2001 106a7ee7a7dSMarius Strobl #define PCNET_MEMSIZE 16384 107a7ee7a7dSMarius Strobl #define PCNET_PCI_RDP 0x10 108a7ee7a7dSMarius Strobl #define PCNET_PCI_RAP 0x12 109a7ee7a7dSMarius Strobl #define PCNET_PCI_BDP 0x16 110a7ee7a7dSMarius Strobl 111a7ee7a7dSMarius Strobl struct le_pci_softc { 112a7ee7a7dSMarius Strobl struct am79900_softc sc_am79900; /* glue to MI code */ 113a7ee7a7dSMarius Strobl 114a7ee7a7dSMarius Strobl int sc_rrid; 115a7ee7a7dSMarius Strobl struct resource *sc_rres; 116a7ee7a7dSMarius Strobl bus_space_tag_t sc_regt; 117a7ee7a7dSMarius Strobl bus_space_handle_t sc_regh; 118a7ee7a7dSMarius Strobl 119a7ee7a7dSMarius Strobl int sc_irid; 120a7ee7a7dSMarius Strobl struct resource *sc_ires; 121a7ee7a7dSMarius Strobl void *sc_ih; 122a7ee7a7dSMarius Strobl 123a7ee7a7dSMarius Strobl bus_dma_tag_t sc_pdmat; 124a7ee7a7dSMarius Strobl bus_dma_tag_t sc_dmat; 125a7ee7a7dSMarius Strobl bus_dmamap_t sc_dmam; 126a7ee7a7dSMarius Strobl }; 127a7ee7a7dSMarius Strobl 128a7ee7a7dSMarius Strobl static device_probe_t le_pci_probe; 129a7ee7a7dSMarius Strobl static device_attach_t le_pci_attach; 130a7ee7a7dSMarius Strobl static device_detach_t le_pci_detach; 131a7ee7a7dSMarius Strobl static device_resume_t le_pci_resume; 132a7ee7a7dSMarius Strobl static device_suspend_t le_pci_suspend; 133a7ee7a7dSMarius Strobl 134a7ee7a7dSMarius Strobl static device_method_t le_pci_methods[] = { 135a7ee7a7dSMarius Strobl /* Device interface */ 136a7ee7a7dSMarius Strobl DEVMETHOD(device_probe, le_pci_probe), 137a7ee7a7dSMarius Strobl DEVMETHOD(device_attach, le_pci_attach), 138a7ee7a7dSMarius Strobl DEVMETHOD(device_detach, le_pci_detach), 139a7ee7a7dSMarius Strobl /* We can just use the suspend method here. */ 140a7ee7a7dSMarius Strobl DEVMETHOD(device_shutdown, le_pci_suspend), 141a7ee7a7dSMarius Strobl DEVMETHOD(device_suspend, le_pci_suspend), 142a7ee7a7dSMarius Strobl DEVMETHOD(device_resume, le_pci_resume), 143a7ee7a7dSMarius Strobl 144a7ee7a7dSMarius Strobl { 0, 0 } 145a7ee7a7dSMarius Strobl }; 146a7ee7a7dSMarius Strobl 147a7ee7a7dSMarius Strobl DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc)); 148a7ee7a7dSMarius Strobl DRIVER_MODULE(le, pci, le_pci_driver, le_devclass, 0, 0); 149a7ee7a7dSMarius Strobl MODULE_DEPEND(le_DRIVER_NAME, ether, 1, 1, 1); 150a7ee7a7dSMarius Strobl 151a7ee7a7dSMarius Strobl static const int le_home_supmedia[] = { 152a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0) 153a7ee7a7dSMarius Strobl }; 154a7ee7a7dSMarius Strobl 155a7ee7a7dSMarius Strobl static const int le_pci_supmedia[] = { 156a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 157a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FDX, 0), 158a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0), 159a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, 0), 160a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0), 161a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, IFM_FDX, 0) 162a7ee7a7dSMarius Strobl }; 163a7ee7a7dSMarius Strobl 164a7ee7a7dSMarius Strobl static void le_pci_wrbcr(struct lance_softc *, uint16_t, uint16_t); 165a7ee7a7dSMarius Strobl static uint16_t le_pci_rdbcr(struct lance_softc *, uint16_t); 166a7ee7a7dSMarius Strobl static void le_pci_wrcsr(struct lance_softc *, uint16_t, uint16_t); 167a7ee7a7dSMarius Strobl static uint16_t le_pci_rdcsr(struct lance_softc *, uint16_t); 168a7ee7a7dSMarius Strobl static int le_pci_mediachange(struct lance_softc *); 169a7ee7a7dSMarius Strobl static void le_pci_hwreset(struct lance_softc *); 170a7ee7a7dSMarius Strobl static bus_dmamap_callback_t le_pci_dma_callback; 171a7ee7a7dSMarius Strobl 172a7ee7a7dSMarius Strobl static void 173a7ee7a7dSMarius Strobl le_pci_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val) 174a7ee7a7dSMarius Strobl { 175a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 176a7ee7a7dSMarius Strobl 177a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); 178a7ee7a7dSMarius Strobl bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, 179a7ee7a7dSMarius Strobl BUS_SPACE_BARRIER_WRITE); 180a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_BDP, val); 181a7ee7a7dSMarius Strobl } 182a7ee7a7dSMarius Strobl 183a7ee7a7dSMarius Strobl static uint16_t 184a7ee7a7dSMarius Strobl le_pci_rdbcr(struct lance_softc *sc, uint16_t port) 185a7ee7a7dSMarius Strobl { 186a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 187a7ee7a7dSMarius Strobl 188a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); 189a7ee7a7dSMarius Strobl bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, 190a7ee7a7dSMarius Strobl BUS_SPACE_BARRIER_WRITE); 191a7ee7a7dSMarius Strobl return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_BDP)); 192a7ee7a7dSMarius Strobl } 193a7ee7a7dSMarius Strobl 194a7ee7a7dSMarius Strobl static void 195a7ee7a7dSMarius Strobl le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 196a7ee7a7dSMarius Strobl { 197a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 198a7ee7a7dSMarius Strobl 199a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); 200a7ee7a7dSMarius Strobl bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, 201a7ee7a7dSMarius Strobl BUS_SPACE_BARRIER_WRITE); 202a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP, val); 203a7ee7a7dSMarius Strobl } 204a7ee7a7dSMarius Strobl 205a7ee7a7dSMarius Strobl static uint16_t 206a7ee7a7dSMarius Strobl le_pci_rdcsr(struct lance_softc *sc, uint16_t port) 207a7ee7a7dSMarius Strobl { 208a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 209a7ee7a7dSMarius Strobl 210a7ee7a7dSMarius Strobl bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); 211a7ee7a7dSMarius Strobl bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, 212a7ee7a7dSMarius Strobl BUS_SPACE_BARRIER_WRITE); 213a7ee7a7dSMarius Strobl return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP)); 214a7ee7a7dSMarius Strobl } 215a7ee7a7dSMarius Strobl 216a7ee7a7dSMarius Strobl static int 217a7ee7a7dSMarius Strobl le_pci_mediachange(struct lance_softc *sc) 218a7ee7a7dSMarius Strobl { 219a7ee7a7dSMarius Strobl struct ifmedia *ifm = &sc->sc_media; 220a7ee7a7dSMarius Strobl uint16_t reg; 221a7ee7a7dSMarius Strobl 222a7ee7a7dSMarius Strobl if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 223a7ee7a7dSMarius Strobl return (EINVAL); 224a7ee7a7dSMarius Strobl 225a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) 226a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR49, 227a7ee7a7dSMarius Strobl (le_pci_rdbcr(sc, LE_BCR49) & ~LE_B49_PHYSEL) | 0x1); 228a7ee7a7dSMarius Strobl else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 229a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 230a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) | LE_B2_ASEL); 231a7ee7a7dSMarius Strobl else { 232a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 233a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) & ~LE_B2_ASEL); 234a7ee7a7dSMarius Strobl 235a7ee7a7dSMarius Strobl reg = le_pci_rdcsr(sc, LE_CSR15); 236a7ee7a7dSMarius Strobl reg &= ~LE_C15_PORTSEL(LE_PORTSEL_MASK); 237a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) 238a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_10T); 239a7ee7a7dSMarius Strobl else 240a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_AUI); 241a7ee7a7dSMarius Strobl le_pci_wrcsr(sc, LE_CSR15, reg); 242a7ee7a7dSMarius Strobl } 243a7ee7a7dSMarius Strobl 244a7ee7a7dSMarius Strobl reg = le_pci_rdbcr(sc, LE_BCR9); 245a7ee7a7dSMarius Strobl if (IFM_OPTIONS(ifm->ifm_media) & IFM_FDX) { 246a7ee7a7dSMarius Strobl reg |= LE_B9_FDEN; 247a7ee7a7dSMarius Strobl /* 248a7ee7a7dSMarius Strobl * Allow FDX on AUI only if explicitly chosen, 249a7ee7a7dSMarius Strobl * not in autoselect mode. 250a7ee7a7dSMarius Strobl */ 251a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_5) 252a7ee7a7dSMarius Strobl reg |= LE_B9_AUIFD; 253a7ee7a7dSMarius Strobl else 254a7ee7a7dSMarius Strobl reg &= ~LE_B9_AUIFD; 255a7ee7a7dSMarius Strobl } else 256a7ee7a7dSMarius Strobl reg &= ~LE_B9_FDEN; 257a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR9, reg); 258a7ee7a7dSMarius Strobl 259a7ee7a7dSMarius Strobl return (0); 260a7ee7a7dSMarius Strobl } 261a7ee7a7dSMarius Strobl 262a7ee7a7dSMarius Strobl static void 263a7ee7a7dSMarius Strobl le_pci_hwreset(struct lance_softc *sc) 264a7ee7a7dSMarius Strobl { 265a7ee7a7dSMarius Strobl 266a7ee7a7dSMarius Strobl /* Chip is stopped. Set "software style" to 32-bit. */ 267a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2); 268a7ee7a7dSMarius Strobl } 269a7ee7a7dSMarius Strobl 270a7ee7a7dSMarius Strobl static void 271a7ee7a7dSMarius Strobl le_pci_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 272a7ee7a7dSMarius Strobl { 273a7ee7a7dSMarius Strobl struct lance_softc *sc = (struct lance_softc *)xsc; 274a7ee7a7dSMarius Strobl 275a7ee7a7dSMarius Strobl if (error != 0) 276a7ee7a7dSMarius Strobl return; 277a7ee7a7dSMarius Strobl KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__)); 278a7ee7a7dSMarius Strobl sc->sc_addr = segs[0].ds_addr; 279a7ee7a7dSMarius Strobl } 280a7ee7a7dSMarius Strobl 281a7ee7a7dSMarius Strobl static int 282a7ee7a7dSMarius Strobl le_pci_probe(device_t dev) 283a7ee7a7dSMarius Strobl { 284a7ee7a7dSMarius Strobl 285a7ee7a7dSMarius Strobl if (pci_get_vendor(dev) != AMD_VENDOR) 286a7ee7a7dSMarius Strobl return (ENXIO); 287a7ee7a7dSMarius Strobl 288a7ee7a7dSMarius Strobl switch (pci_get_device(dev)) { 289a7ee7a7dSMarius Strobl case AMD_PCNET_PCI: 290a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 291a7ee7a7dSMarius Strobl device_set_desc(dev, "AMD PCnet Ethernet"); 292a7ee7a7dSMarius Strobl /* Let lnc(4) win for now. */ 293a7ee7a7dSMarius Strobl return (BUS_PROBE_LOW_PRIORITY); 294a7ee7a7dSMarius Strobl default: 295a7ee7a7dSMarius Strobl return (ENXIO); 296a7ee7a7dSMarius Strobl } 297a7ee7a7dSMarius Strobl } 298a7ee7a7dSMarius Strobl 299a7ee7a7dSMarius Strobl static int 300a7ee7a7dSMarius Strobl le_pci_attach(device_t dev) 301a7ee7a7dSMarius Strobl { 302a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 303a7ee7a7dSMarius Strobl struct lance_softc *sc; 304a7ee7a7dSMarius Strobl int error, i; 305a7ee7a7dSMarius Strobl 306a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 307a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 308a7ee7a7dSMarius Strobl 309a7ee7a7dSMarius Strobl LE_LOCK_INIT(sc, device_get_nameunit(dev)); 310a7ee7a7dSMarius Strobl 311a7ee7a7dSMarius Strobl pci_enable_busmaster(dev); 312a7ee7a7dSMarius Strobl pci_enable_io(dev, PCIM_CMD_PORTEN); 313a7ee7a7dSMarius Strobl 314a7ee7a7dSMarius Strobl lesc->sc_rrid = PCIR_BAR(0); 315a7ee7a7dSMarius Strobl lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 316a7ee7a7dSMarius Strobl &lesc->sc_rrid, RF_ACTIVE); 317a7ee7a7dSMarius Strobl if (lesc->sc_rres == NULL) { 318a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate registers\n"); 319a7ee7a7dSMarius Strobl error = ENXIO; 320a7ee7a7dSMarius Strobl goto fail_mtx; 321a7ee7a7dSMarius Strobl } 322a7ee7a7dSMarius Strobl lesc->sc_regt = rman_get_bustag(lesc->sc_rres); 323a7ee7a7dSMarius Strobl lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); 324a7ee7a7dSMarius Strobl 325a7ee7a7dSMarius Strobl lesc->sc_irid = 0; 326a7ee7a7dSMarius Strobl if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 327a7ee7a7dSMarius Strobl &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 328a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate interrupt\n"); 329a7ee7a7dSMarius Strobl error = ENXIO; 330a7ee7a7dSMarius Strobl goto fail_rres; 331a7ee7a7dSMarius Strobl } 332a7ee7a7dSMarius Strobl 333a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 334a7ee7a7dSMarius Strobl NULL, /* parent */ 335a7ee7a7dSMarius Strobl PAGE_SIZE, 0, /* alignment, boundary */ 336a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 337a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR, /* highaddr */ 338a7ee7a7dSMarius Strobl NULL, NULL, /* filter, filterarg */ 339a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 340a7ee7a7dSMarius Strobl 0, /* nsegments */ 341a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 342a7ee7a7dSMarius Strobl BUS_DMA_WAITOK, /* flags */ 343a7ee7a7dSMarius Strobl NULL, NULL, /* lockfunc, lockarg */ 344a7ee7a7dSMarius Strobl &lesc->sc_pdmat); 345a7ee7a7dSMarius Strobl if (error != 0) { 346a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate parent DMA tag\n"); 347a7ee7a7dSMarius Strobl goto fail_ires; 348a7ee7a7dSMarius Strobl } 349a7ee7a7dSMarius Strobl 350a7ee7a7dSMarius Strobl sc->sc_memsize = PCNET_MEMSIZE; 351a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 352a7ee7a7dSMarius Strobl lesc->sc_pdmat, /* parent */ 353a7ee7a7dSMarius Strobl 1, 0, /* alignment, boundary */ 354a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 355a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR, /* highaddr */ 356a7ee7a7dSMarius Strobl NULL, NULL, /* filter, filterarg */ 357a7ee7a7dSMarius Strobl sc->sc_memsize, /* maxsize */ 358a7ee7a7dSMarius Strobl 1, /* nsegments */ 359a7ee7a7dSMarius Strobl sc->sc_memsize, /* maxsegsize */ 360a7ee7a7dSMarius Strobl BUS_DMA_WAITOK, /* flags */ 361a7ee7a7dSMarius Strobl NULL, NULL, /* lockfunc, lockarg */ 362a7ee7a7dSMarius Strobl &lesc->sc_dmat); 363a7ee7a7dSMarius Strobl if (error != 0) { 364a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate buffer DMA tag\n"); 365a7ee7a7dSMarius Strobl goto fail_pdtag; 366a7ee7a7dSMarius Strobl } 367a7ee7a7dSMarius Strobl 368a7ee7a7dSMarius Strobl error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, 369a7ee7a7dSMarius Strobl BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); 370a7ee7a7dSMarius Strobl if (error != 0) { 371a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate DMA buffer memory\n"); 372a7ee7a7dSMarius Strobl goto fail_dtag; 373a7ee7a7dSMarius Strobl } 374a7ee7a7dSMarius Strobl 375a7ee7a7dSMarius Strobl sc->sc_addr = 0; 376a7ee7a7dSMarius Strobl error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, 377a7ee7a7dSMarius Strobl sc->sc_memsize, le_pci_dma_callback, sc, 0); 378a7ee7a7dSMarius Strobl if (error != 0 || sc->sc_addr == 0) { 379a7ee7a7dSMarius Strobl device_printf(dev, "cannot load DMA buffer map\n"); 380a7ee7a7dSMarius Strobl goto fail_dmem; 381a7ee7a7dSMarius Strobl } 382a7ee7a7dSMarius Strobl 383a7ee7a7dSMarius Strobl sc->sc_flags = LE_BSWAP; 384a7ee7a7dSMarius Strobl sc->sc_conf3 = 0; 385a7ee7a7dSMarius Strobl 386a7ee7a7dSMarius Strobl switch (pci_get_device(dev)) { 387a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 388a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 389a7ee7a7dSMarius Strobl sc->sc_supmedia = le_home_supmedia; 390a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_home_supmedia) / sizeof(int); 391a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_home_supmedia[0]; 392a7ee7a7dSMarius Strobl break; 393a7ee7a7dSMarius Strobl default: 394a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 395a7ee7a7dSMarius Strobl sc->sc_supmedia = le_pci_supmedia; 396a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int); 397a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_pci_supmedia[0]; 398a7ee7a7dSMarius Strobl } 399a7ee7a7dSMarius Strobl 400a7ee7a7dSMarius Strobl /* 401a7ee7a7dSMarius Strobl * Extract the physical MAC address from the ROM. 402a7ee7a7dSMarius Strobl */ 403a7ee7a7dSMarius Strobl for (i = 0; i < sizeof(sc->sc_enaddr); i++) 404a7ee7a7dSMarius Strobl sc->sc_enaddr[i] = 405a7ee7a7dSMarius Strobl bus_space_read_1(lesc->sc_regt, lesc->sc_regh, i); 406a7ee7a7dSMarius Strobl 407a7ee7a7dSMarius Strobl sc->sc_copytodesc = lance_copytobuf_contig; 408a7ee7a7dSMarius Strobl sc->sc_copyfromdesc = lance_copyfrombuf_contig; 409a7ee7a7dSMarius Strobl sc->sc_copytobuf = lance_copytobuf_contig; 410a7ee7a7dSMarius Strobl sc->sc_copyfrombuf = lance_copyfrombuf_contig; 411a7ee7a7dSMarius Strobl sc->sc_zerobuf = lance_zerobuf_contig; 412a7ee7a7dSMarius Strobl 413a7ee7a7dSMarius Strobl sc->sc_rdcsr = le_pci_rdcsr; 414a7ee7a7dSMarius Strobl sc->sc_wrcsr = le_pci_wrcsr; 415a7ee7a7dSMarius Strobl sc->sc_hwreset = le_pci_hwreset; 416a7ee7a7dSMarius Strobl 417a7ee7a7dSMarius Strobl error = am79900_config(&lesc->sc_am79900, device_get_name(dev), 418a7ee7a7dSMarius Strobl device_get_unit(dev)); 419a7ee7a7dSMarius Strobl if (error != 0) { 420a7ee7a7dSMarius Strobl device_printf(dev, "cannot attach AM79900\n"); 421a7ee7a7dSMarius Strobl goto fail_dmap; 422a7ee7a7dSMarius Strobl } 423a7ee7a7dSMarius Strobl 424a7ee7a7dSMarius Strobl error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 425a7ee7a7dSMarius Strobl am79900_intr, sc, &lesc->sc_ih); 426a7ee7a7dSMarius Strobl if (error != 0) { 427a7ee7a7dSMarius Strobl device_printf(dev, "cannot set up interrupt\n"); 428a7ee7a7dSMarius Strobl goto fail_am79900; 429a7ee7a7dSMarius Strobl } 430a7ee7a7dSMarius Strobl 431a7ee7a7dSMarius Strobl return (0); 432a7ee7a7dSMarius Strobl 433a7ee7a7dSMarius Strobl fail_am79900: 434a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 435a7ee7a7dSMarius Strobl fail_dmap: 436a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 437a7ee7a7dSMarius Strobl fail_dmem: 438a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 439a7ee7a7dSMarius Strobl fail_dtag: 440a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 441a7ee7a7dSMarius Strobl fail_pdtag: 442a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 443a7ee7a7dSMarius Strobl fail_ires: 444a7ee7a7dSMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 445a7ee7a7dSMarius Strobl fail_rres: 446a7ee7a7dSMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); 447a7ee7a7dSMarius Strobl fail_mtx: 448a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 449a7ee7a7dSMarius Strobl return (error); 450a7ee7a7dSMarius Strobl } 451a7ee7a7dSMarius Strobl 452a7ee7a7dSMarius Strobl static int 453a7ee7a7dSMarius Strobl le_pci_detach(device_t dev) 454a7ee7a7dSMarius Strobl { 455a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 456a7ee7a7dSMarius Strobl struct lance_softc *sc; 457a7ee7a7dSMarius Strobl 458a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 459a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 460a7ee7a7dSMarius Strobl 461a7ee7a7dSMarius Strobl bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 462a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 463a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 464a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 465a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 466a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 467a7ee7a7dSMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 468a7ee7a7dSMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres); 469a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 470a7ee7a7dSMarius Strobl 471a7ee7a7dSMarius Strobl return (0); 472a7ee7a7dSMarius Strobl } 473a7ee7a7dSMarius Strobl 474a7ee7a7dSMarius Strobl static int 475a7ee7a7dSMarius Strobl le_pci_suspend(device_t dev) 476a7ee7a7dSMarius Strobl { 477a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 478a7ee7a7dSMarius Strobl 479a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 480a7ee7a7dSMarius Strobl 481a7ee7a7dSMarius Strobl lance_suspend(&lesc->sc_am79900.lsc); 482a7ee7a7dSMarius Strobl 483a7ee7a7dSMarius Strobl return (0); 484a7ee7a7dSMarius Strobl } 485a7ee7a7dSMarius Strobl 486a7ee7a7dSMarius Strobl static int 487a7ee7a7dSMarius Strobl le_pci_resume(device_t dev) 488a7ee7a7dSMarius Strobl { 489a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 490a7ee7a7dSMarius Strobl 491a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 492a7ee7a7dSMarius Strobl 493a7ee7a7dSMarius Strobl lance_resume(&lesc->sc_am79900.lsc); 494a7ee7a7dSMarius Strobl 495a7ee7a7dSMarius Strobl return (0); 496a7ee7a7dSMarius Strobl } 497