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 10660c430f5SMarius Strobl #define PCNET_MEMSIZE (32*1024) 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 struct resource *sc_rres; 115a7ee7a7dSMarius Strobl 116a7ee7a7dSMarius Strobl struct resource *sc_ires; 117a7ee7a7dSMarius Strobl void *sc_ih; 118a7ee7a7dSMarius Strobl 119a7ee7a7dSMarius Strobl bus_dma_tag_t sc_pdmat; 120a7ee7a7dSMarius Strobl bus_dma_tag_t sc_dmat; 121a7ee7a7dSMarius Strobl bus_dmamap_t sc_dmam; 122a7ee7a7dSMarius Strobl }; 123a7ee7a7dSMarius Strobl 124a7ee7a7dSMarius Strobl static device_probe_t le_pci_probe; 125a7ee7a7dSMarius Strobl static device_attach_t le_pci_attach; 126a7ee7a7dSMarius Strobl static device_detach_t le_pci_detach; 127a7ee7a7dSMarius Strobl static device_resume_t le_pci_resume; 128a7ee7a7dSMarius Strobl static device_suspend_t le_pci_suspend; 129a7ee7a7dSMarius Strobl 130a7ee7a7dSMarius Strobl static device_method_t le_pci_methods[] = { 131a7ee7a7dSMarius Strobl /* Device interface */ 132a7ee7a7dSMarius Strobl DEVMETHOD(device_probe, le_pci_probe), 133a7ee7a7dSMarius Strobl DEVMETHOD(device_attach, le_pci_attach), 134a7ee7a7dSMarius Strobl DEVMETHOD(device_detach, le_pci_detach), 135a7ee7a7dSMarius Strobl /* We can just use the suspend method here. */ 136a7ee7a7dSMarius Strobl DEVMETHOD(device_shutdown, le_pci_suspend), 137a7ee7a7dSMarius Strobl DEVMETHOD(device_suspend, le_pci_suspend), 138a7ee7a7dSMarius Strobl DEVMETHOD(device_resume, le_pci_resume), 139a7ee7a7dSMarius Strobl 140a7ee7a7dSMarius Strobl { 0, 0 } 141a7ee7a7dSMarius Strobl }; 142a7ee7a7dSMarius Strobl 143a7ee7a7dSMarius Strobl DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc)); 144a7ee7a7dSMarius Strobl DRIVER_MODULE(le, pci, le_pci_driver, le_devclass, 0, 0); 14560c430f5SMarius Strobl MODULE_DEPEND(le, ether, 1, 1, 1); 146a7ee7a7dSMarius Strobl 147a7ee7a7dSMarius Strobl static const int le_home_supmedia[] = { 148a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0) 149a7ee7a7dSMarius Strobl }; 150a7ee7a7dSMarius Strobl 151a7ee7a7dSMarius Strobl static const int le_pci_supmedia[] = { 152a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 153a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FDX, 0), 154a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0), 155a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, 0), 156a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0), 157a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, IFM_FDX, 0) 158a7ee7a7dSMarius Strobl }; 159a7ee7a7dSMarius Strobl 160a7ee7a7dSMarius Strobl static void le_pci_wrbcr(struct lance_softc *, uint16_t, uint16_t); 161a7ee7a7dSMarius Strobl static uint16_t le_pci_rdbcr(struct lance_softc *, uint16_t); 162a7ee7a7dSMarius Strobl static void le_pci_wrcsr(struct lance_softc *, uint16_t, uint16_t); 163a7ee7a7dSMarius Strobl static uint16_t le_pci_rdcsr(struct lance_softc *, uint16_t); 164a7ee7a7dSMarius Strobl static int le_pci_mediachange(struct lance_softc *); 165a7ee7a7dSMarius Strobl static void le_pci_hwreset(struct lance_softc *); 166a7ee7a7dSMarius Strobl static bus_dmamap_callback_t le_pci_dma_callback; 167a7ee7a7dSMarius Strobl 168a7ee7a7dSMarius Strobl static void 169a7ee7a7dSMarius Strobl le_pci_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val) 170a7ee7a7dSMarius Strobl { 171a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 172a7ee7a7dSMarius Strobl 173c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 174c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 175c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_BDP, val); 176a7ee7a7dSMarius Strobl } 177a7ee7a7dSMarius Strobl 178a7ee7a7dSMarius Strobl static uint16_t 179a7ee7a7dSMarius Strobl le_pci_rdbcr(struct lance_softc *sc, uint16_t port) 180a7ee7a7dSMarius Strobl { 181a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 182a7ee7a7dSMarius Strobl 183c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 184c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 185c75c2a68SMarius Strobl return (bus_read_2(lesc->sc_rres, PCNET_PCI_BDP)); 186a7ee7a7dSMarius Strobl } 187a7ee7a7dSMarius Strobl 188a7ee7a7dSMarius Strobl static void 189a7ee7a7dSMarius Strobl le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 190a7ee7a7dSMarius Strobl { 191a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 192a7ee7a7dSMarius Strobl 193c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 194c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 195c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RDP, val); 196a7ee7a7dSMarius Strobl } 197a7ee7a7dSMarius Strobl 198a7ee7a7dSMarius Strobl static uint16_t 199a7ee7a7dSMarius Strobl le_pci_rdcsr(struct lance_softc *sc, uint16_t port) 200a7ee7a7dSMarius Strobl { 201a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 202a7ee7a7dSMarius Strobl 203c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 204c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 205c75c2a68SMarius Strobl return (bus_read_2(lesc->sc_rres, PCNET_PCI_RDP)); 206a7ee7a7dSMarius Strobl } 207a7ee7a7dSMarius Strobl 208a7ee7a7dSMarius Strobl static int 209a7ee7a7dSMarius Strobl le_pci_mediachange(struct lance_softc *sc) 210a7ee7a7dSMarius Strobl { 211a7ee7a7dSMarius Strobl struct ifmedia *ifm = &sc->sc_media; 212a7ee7a7dSMarius Strobl uint16_t reg; 213a7ee7a7dSMarius Strobl 214a7ee7a7dSMarius Strobl if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 215a7ee7a7dSMarius Strobl return (EINVAL); 216a7ee7a7dSMarius Strobl 217a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) 218a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR49, 219a7ee7a7dSMarius Strobl (le_pci_rdbcr(sc, LE_BCR49) & ~LE_B49_PHYSEL) | 0x1); 220a7ee7a7dSMarius Strobl else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 221a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 222a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) | LE_B2_ASEL); 223a7ee7a7dSMarius Strobl else { 224a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 225a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) & ~LE_B2_ASEL); 226a7ee7a7dSMarius Strobl 227a7ee7a7dSMarius Strobl reg = le_pci_rdcsr(sc, LE_CSR15); 228a7ee7a7dSMarius Strobl reg &= ~LE_C15_PORTSEL(LE_PORTSEL_MASK); 229a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) 230a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_10T); 231a7ee7a7dSMarius Strobl else 232a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_AUI); 233a7ee7a7dSMarius Strobl le_pci_wrcsr(sc, LE_CSR15, reg); 234a7ee7a7dSMarius Strobl } 235a7ee7a7dSMarius Strobl 236a7ee7a7dSMarius Strobl reg = le_pci_rdbcr(sc, LE_BCR9); 237a7ee7a7dSMarius Strobl if (IFM_OPTIONS(ifm->ifm_media) & IFM_FDX) { 238a7ee7a7dSMarius Strobl reg |= LE_B9_FDEN; 239a7ee7a7dSMarius Strobl /* 240a7ee7a7dSMarius Strobl * Allow FDX on AUI only if explicitly chosen, 241a7ee7a7dSMarius Strobl * not in autoselect mode. 242a7ee7a7dSMarius Strobl */ 243a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_5) 244a7ee7a7dSMarius Strobl reg |= LE_B9_AUIFD; 245a7ee7a7dSMarius Strobl else 246a7ee7a7dSMarius Strobl reg &= ~LE_B9_AUIFD; 247a7ee7a7dSMarius Strobl } else 248a7ee7a7dSMarius Strobl reg &= ~LE_B9_FDEN; 249a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR9, reg); 250a7ee7a7dSMarius Strobl 251a7ee7a7dSMarius Strobl return (0); 252a7ee7a7dSMarius Strobl } 253a7ee7a7dSMarius Strobl 254a7ee7a7dSMarius Strobl static void 255a7ee7a7dSMarius Strobl le_pci_hwreset(struct lance_softc *sc) 256a7ee7a7dSMarius Strobl { 257a7ee7a7dSMarius Strobl 2583a225e0bSMarius Strobl /* 2593a225e0bSMarius Strobl * Chip is stopped. Set software style to PCnet-PCI (32-bit). 2603a225e0bSMarius Strobl * Actually, am79900.c implements ILACC support (hence its 2613a225e0bSMarius Strobl * name) but unfortunately VMware does not. As far as this 2623a225e0bSMarius Strobl * driver is concerned that should not make a difference 2633a225e0bSMarius Strobl * though, as the settings used have the same meaning for 2643a225e0bSMarius Strobl * both, ILACC and PCnet-PCI (note that there would be a 2653a225e0bSMarius Strobl * difference for the ADD_FCS/NO_FCS bit if used). 2663a225e0bSMarius Strobl */ 2673a225e0bSMarius 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: 29060c430f5SMarius Strobl device_set_desc(dev, "AMD PCnet-PCI"); 29160c430f5SMarius Strobl /* Let pcn(4) win. */ 29260c430f5SMarius Strobl return (BUS_PROBE_LOW_PRIORITY); 293a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 29460c430f5SMarius Strobl device_set_desc(dev, "AMD PCnet-Home"); 29560c430f5SMarius Strobl /* Let pcn(4) win. */ 29660c430f5SMarius Strobl return (BUS_PROBE_LOW_PRIORITY); 297a7ee7a7dSMarius Strobl default: 298a7ee7a7dSMarius Strobl return (ENXIO); 299a7ee7a7dSMarius Strobl } 300a7ee7a7dSMarius Strobl } 301a7ee7a7dSMarius Strobl 302a7ee7a7dSMarius Strobl static int 303a7ee7a7dSMarius Strobl le_pci_attach(device_t dev) 304a7ee7a7dSMarius Strobl { 305a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 306a7ee7a7dSMarius Strobl struct lance_softc *sc; 307a7ee7a7dSMarius Strobl int error, i; 308a7ee7a7dSMarius Strobl 309a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 310a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 311a7ee7a7dSMarius Strobl 312a7ee7a7dSMarius Strobl LE_LOCK_INIT(sc, device_get_nameunit(dev)); 313a7ee7a7dSMarius Strobl 314a7ee7a7dSMarius Strobl pci_enable_busmaster(dev); 315a7ee7a7dSMarius Strobl pci_enable_io(dev, PCIM_CMD_PORTEN); 316a7ee7a7dSMarius Strobl 317c75c2a68SMarius Strobl i = PCIR_BAR(0); 318a7ee7a7dSMarius Strobl lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 319c75c2a68SMarius Strobl &i, RF_ACTIVE); 320a7ee7a7dSMarius Strobl if (lesc->sc_rres == NULL) { 321a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate registers\n"); 322a7ee7a7dSMarius Strobl error = ENXIO; 323a7ee7a7dSMarius Strobl goto fail_mtx; 324a7ee7a7dSMarius Strobl } 325a7ee7a7dSMarius Strobl 326c75c2a68SMarius Strobl i = 0; 327a7ee7a7dSMarius Strobl if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 328c75c2a68SMarius Strobl &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 329a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate interrupt\n"); 330a7ee7a7dSMarius Strobl error = ENXIO; 331a7ee7a7dSMarius Strobl goto fail_rres; 332a7ee7a7dSMarius Strobl } 333a7ee7a7dSMarius Strobl 334a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 335d2255d02SMarius Strobl bus_get_dma_tag(dev), /* parent */ 33660c430f5SMarius Strobl 1, 0, /* alignment, boundary */ 337a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 338a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR, /* highaddr */ 339a7ee7a7dSMarius Strobl NULL, NULL, /* filter, filterarg */ 340a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 341a7ee7a7dSMarius Strobl 0, /* nsegments */ 342a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 3430c7d35d0SMarius Strobl 0, /* flags */ 344a7ee7a7dSMarius Strobl NULL, NULL, /* lockfunc, lockarg */ 345a7ee7a7dSMarius Strobl &lesc->sc_pdmat); 346a7ee7a7dSMarius Strobl if (error != 0) { 347a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate parent DMA tag\n"); 348a7ee7a7dSMarius Strobl goto fail_ires; 349a7ee7a7dSMarius Strobl } 350a7ee7a7dSMarius Strobl 351a7ee7a7dSMarius Strobl sc->sc_memsize = PCNET_MEMSIZE; 35260c430f5SMarius Strobl /* 35360c430f5SMarius Strobl * For Am79C970A, Am79C971 and Am79C978 the init block must be 2-byte 35460c430f5SMarius Strobl * aligned and the ring descriptors must be 16-byte aligned when using 35560c430f5SMarius Strobl * a 32-bit software style. 35660c430f5SMarius Strobl */ 357a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 358a7ee7a7dSMarius Strobl lesc->sc_pdmat, /* parent */ 35960c430f5SMarius Strobl 16, 0, /* alignment, boundary */ 360a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 361a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR, /* highaddr */ 362a7ee7a7dSMarius Strobl NULL, NULL, /* filter, filterarg */ 363a7ee7a7dSMarius Strobl sc->sc_memsize, /* maxsize */ 364a7ee7a7dSMarius Strobl 1, /* nsegments */ 365a7ee7a7dSMarius Strobl sc->sc_memsize, /* maxsegsize */ 3660c7d35d0SMarius Strobl 0, /* flags */ 367a7ee7a7dSMarius Strobl NULL, NULL, /* lockfunc, lockarg */ 368a7ee7a7dSMarius Strobl &lesc->sc_dmat); 369a7ee7a7dSMarius Strobl if (error != 0) { 370a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate buffer DMA tag\n"); 371a7ee7a7dSMarius Strobl goto fail_pdtag; 372a7ee7a7dSMarius Strobl } 373a7ee7a7dSMarius Strobl 374a7ee7a7dSMarius Strobl error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, 375a7ee7a7dSMarius Strobl BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); 376a7ee7a7dSMarius Strobl if (error != 0) { 377a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate DMA buffer memory\n"); 378a7ee7a7dSMarius Strobl goto fail_dtag; 379a7ee7a7dSMarius Strobl } 380a7ee7a7dSMarius Strobl 381a7ee7a7dSMarius Strobl sc->sc_addr = 0; 382a7ee7a7dSMarius Strobl error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, 383a7ee7a7dSMarius Strobl sc->sc_memsize, le_pci_dma_callback, sc, 0); 384a7ee7a7dSMarius Strobl if (error != 0 || sc->sc_addr == 0) { 385a7ee7a7dSMarius Strobl device_printf(dev, "cannot load DMA buffer map\n"); 386a7ee7a7dSMarius Strobl goto fail_dmem; 387a7ee7a7dSMarius Strobl } 388a7ee7a7dSMarius Strobl 389a7ee7a7dSMarius Strobl sc->sc_flags = LE_BSWAP; 390a7ee7a7dSMarius Strobl sc->sc_conf3 = 0; 391a7ee7a7dSMarius Strobl 39260c430f5SMarius Strobl sc->sc_mediastatus = NULL; 393a7ee7a7dSMarius Strobl switch (pci_get_device(dev)) { 394a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 395a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 396a7ee7a7dSMarius Strobl sc->sc_supmedia = le_home_supmedia; 397a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_home_supmedia) / sizeof(int); 398a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_home_supmedia[0]; 399a7ee7a7dSMarius Strobl break; 400a7ee7a7dSMarius Strobl default: 401a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 402a7ee7a7dSMarius Strobl sc->sc_supmedia = le_pci_supmedia; 403a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int); 404a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_pci_supmedia[0]; 405a7ee7a7dSMarius Strobl } 406a7ee7a7dSMarius Strobl 407a7ee7a7dSMarius Strobl /* 408a7ee7a7dSMarius Strobl * Extract the physical MAC address from the ROM. 409a7ee7a7dSMarius Strobl */ 410c75c2a68SMarius Strobl bus_read_region_1(lesc->sc_rres, 0, sc->sc_enaddr, 411c75c2a68SMarius Strobl sizeof(sc->sc_enaddr)); 412a7ee7a7dSMarius Strobl 413a7ee7a7dSMarius Strobl sc->sc_copytodesc = lance_copytobuf_contig; 414a7ee7a7dSMarius Strobl sc->sc_copyfromdesc = lance_copyfrombuf_contig; 415a7ee7a7dSMarius Strobl sc->sc_copytobuf = lance_copytobuf_contig; 416a7ee7a7dSMarius Strobl sc->sc_copyfrombuf = lance_copyfrombuf_contig; 417a7ee7a7dSMarius Strobl sc->sc_zerobuf = lance_zerobuf_contig; 418a7ee7a7dSMarius Strobl 419a7ee7a7dSMarius Strobl sc->sc_rdcsr = le_pci_rdcsr; 420a7ee7a7dSMarius Strobl sc->sc_wrcsr = le_pci_wrcsr; 421a7ee7a7dSMarius Strobl sc->sc_hwreset = le_pci_hwreset; 42260c430f5SMarius Strobl sc->sc_hwinit = NULL; 42360c430f5SMarius Strobl sc->sc_hwintr = NULL; 42460c430f5SMarius Strobl sc->sc_nocarrier = NULL; 425a7ee7a7dSMarius Strobl 426a7ee7a7dSMarius Strobl error = am79900_config(&lesc->sc_am79900, device_get_name(dev), 427a7ee7a7dSMarius Strobl device_get_unit(dev)); 428a7ee7a7dSMarius Strobl if (error != 0) { 42960c430f5SMarius Strobl device_printf(dev, "cannot attach Am79900\n"); 430a7ee7a7dSMarius Strobl goto fail_dmap; 431a7ee7a7dSMarius Strobl } 432a7ee7a7dSMarius Strobl 433a7ee7a7dSMarius Strobl error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 434ef544f63SPaolo Pisati NULL, am79900_intr, sc, &lesc->sc_ih); 435a7ee7a7dSMarius Strobl if (error != 0) { 436a7ee7a7dSMarius Strobl device_printf(dev, "cannot set up interrupt\n"); 437a7ee7a7dSMarius Strobl goto fail_am79900; 438a7ee7a7dSMarius Strobl } 439a7ee7a7dSMarius Strobl 440a7ee7a7dSMarius Strobl return (0); 441a7ee7a7dSMarius Strobl 442a7ee7a7dSMarius Strobl fail_am79900: 443a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 444a7ee7a7dSMarius Strobl fail_dmap: 445a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 446a7ee7a7dSMarius Strobl fail_dmem: 447a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 448a7ee7a7dSMarius Strobl fail_dtag: 449a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 450a7ee7a7dSMarius Strobl fail_pdtag: 451a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 452a7ee7a7dSMarius Strobl fail_ires: 453c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, 454c75c2a68SMarius Strobl rman_get_rid(lesc->sc_ires), lesc->sc_ires); 455a7ee7a7dSMarius Strobl fail_rres: 456c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, 457c75c2a68SMarius Strobl rman_get_rid(lesc->sc_rres), lesc->sc_rres); 458a7ee7a7dSMarius Strobl fail_mtx: 459a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 460a7ee7a7dSMarius Strobl return (error); 461a7ee7a7dSMarius Strobl } 462a7ee7a7dSMarius Strobl 463a7ee7a7dSMarius Strobl static int 464a7ee7a7dSMarius Strobl le_pci_detach(device_t dev) 465a7ee7a7dSMarius Strobl { 466a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 467a7ee7a7dSMarius Strobl struct lance_softc *sc; 468a7ee7a7dSMarius Strobl 469a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 470a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 471a7ee7a7dSMarius Strobl 472a7ee7a7dSMarius Strobl bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 473a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 474a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 475a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 476a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 477a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 478c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, 479c75c2a68SMarius Strobl rman_get_rid(lesc->sc_ires), lesc->sc_ires); 480c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, 481c75c2a68SMarius Strobl rman_get_rid(lesc->sc_rres), lesc->sc_rres); 482a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 483a7ee7a7dSMarius Strobl 484a7ee7a7dSMarius Strobl return (0); 485a7ee7a7dSMarius Strobl } 486a7ee7a7dSMarius Strobl 487a7ee7a7dSMarius Strobl static int 488a7ee7a7dSMarius Strobl le_pci_suspend(device_t dev) 489a7ee7a7dSMarius Strobl { 490a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 491a7ee7a7dSMarius Strobl 492a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 493a7ee7a7dSMarius Strobl 494a7ee7a7dSMarius Strobl lance_suspend(&lesc->sc_am79900.lsc); 495a7ee7a7dSMarius Strobl 496a7ee7a7dSMarius Strobl return (0); 497a7ee7a7dSMarius Strobl } 498a7ee7a7dSMarius Strobl 499a7ee7a7dSMarius Strobl static int 500a7ee7a7dSMarius Strobl le_pci_resume(device_t dev) 501a7ee7a7dSMarius Strobl { 502a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 503a7ee7a7dSMarius Strobl 504a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 505a7ee7a7dSMarius Strobl 506a7ee7a7dSMarius Strobl lance_resume(&lesc->sc_am79900.lsc); 507a7ee7a7dSMarius Strobl 508a7ee7a7dSMarius Strobl return (0); 509a7ee7a7dSMarius Strobl } 510