1a7ee7a7dSMarius Strobl /* $NetBSD: if_le_pci.c,v 1.43 2005/12/11 12:22:49 christos Exp $ */ 2a7ee7a7dSMarius Strobl 3a7ee7a7dSMarius Strobl /*- 4*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause 5718cf2ccSPedro F. Giffuni * 6a7ee7a7dSMarius Strobl * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 7a7ee7a7dSMarius Strobl * All rights reserved. 8a7ee7a7dSMarius Strobl * 9a7ee7a7dSMarius Strobl * This code is derived from software contributed to The NetBSD Foundation 10a7ee7a7dSMarius Strobl * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 11a7ee7a7dSMarius Strobl * Simulation Facility, NASA Ames Research Center. 12a7ee7a7dSMarius Strobl * 13a7ee7a7dSMarius Strobl * Redistribution and use in source and binary forms, with or without 14a7ee7a7dSMarius Strobl * modification, are permitted provided that the following conditions 15a7ee7a7dSMarius Strobl * are met: 16a7ee7a7dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 17a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer. 18a7ee7a7dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 19a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 20a7ee7a7dSMarius Strobl * documentation and/or other materials provided with the distribution. 21a7ee7a7dSMarius Strobl * 22a7ee7a7dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23a7ee7a7dSMarius Strobl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24a7ee7a7dSMarius Strobl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25a7ee7a7dSMarius Strobl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26a7ee7a7dSMarius Strobl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27a7ee7a7dSMarius Strobl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28a7ee7a7dSMarius Strobl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29a7ee7a7dSMarius Strobl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30a7ee7a7dSMarius Strobl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31a7ee7a7dSMarius Strobl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32a7ee7a7dSMarius Strobl * POSSIBILITY OF SUCH DAMAGE. 33a7ee7a7dSMarius Strobl */ 34a7ee7a7dSMarius Strobl 35a7ee7a7dSMarius Strobl /*- 36a7ee7a7dSMarius Strobl * Copyright (c) 1992, 1993 37a7ee7a7dSMarius Strobl * The Regents of the University of California. All rights reserved. 38a7ee7a7dSMarius Strobl * 39a7ee7a7dSMarius Strobl * This code is derived from software contributed to Berkeley by 40a7ee7a7dSMarius Strobl * Ralph Campbell and Rick Macklem. 41a7ee7a7dSMarius Strobl * 42a7ee7a7dSMarius Strobl * Redistribution and use in source and binary forms, with or without 43a7ee7a7dSMarius Strobl * modification, are permitted provided that the following conditions 44a7ee7a7dSMarius Strobl * are met: 45a7ee7a7dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 46a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer. 47a7ee7a7dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 48a7ee7a7dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 49a7ee7a7dSMarius Strobl * documentation and/or other materials provided with the distribution. 50a7ee7a7dSMarius Strobl * 3. Neither the name of the University nor the names of its contributors 51a7ee7a7dSMarius Strobl * may be used to endorse or promote products derived from this software 52a7ee7a7dSMarius Strobl * without specific prior written permission. 53a7ee7a7dSMarius Strobl * 54a7ee7a7dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55a7ee7a7dSMarius Strobl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56a7ee7a7dSMarius Strobl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57a7ee7a7dSMarius Strobl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58a7ee7a7dSMarius Strobl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59a7ee7a7dSMarius Strobl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60a7ee7a7dSMarius Strobl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61a7ee7a7dSMarius Strobl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62a7ee7a7dSMarius Strobl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63a7ee7a7dSMarius Strobl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64a7ee7a7dSMarius Strobl * SUCH DAMAGE. 65a7ee7a7dSMarius Strobl * 66a7ee7a7dSMarius Strobl * @(#)if_le.c 8.2 (Berkeley) 11/16/93 67a7ee7a7dSMarius Strobl */ 68a7ee7a7dSMarius Strobl 69a7ee7a7dSMarius Strobl #include <sys/cdefs.h> 70a7ee7a7dSMarius Strobl __FBSDID("$FreeBSD$"); 71a7ee7a7dSMarius Strobl 72a7ee7a7dSMarius Strobl #include <sys/param.h> 73a7ee7a7dSMarius Strobl #include <sys/systm.h> 74a7ee7a7dSMarius Strobl #include <sys/bus.h> 75a7ee7a7dSMarius Strobl #include <sys/endian.h> 76a7ee7a7dSMarius Strobl #include <sys/kernel.h> 77a7ee7a7dSMarius Strobl #include <sys/lock.h> 78a7ee7a7dSMarius Strobl #include <sys/module.h> 79a7ee7a7dSMarius Strobl #include <sys/mutex.h> 80a7ee7a7dSMarius Strobl #include <sys/resource.h> 81a7ee7a7dSMarius Strobl #include <sys/rman.h> 82a7ee7a7dSMarius Strobl #include <sys/socket.h> 83a7ee7a7dSMarius Strobl 84a7ee7a7dSMarius Strobl #include <net/ethernet.h> 85a7ee7a7dSMarius Strobl #include <net/if.h> 86a7ee7a7dSMarius Strobl #include <net/if_media.h> 87a7ee7a7dSMarius Strobl 88a7ee7a7dSMarius Strobl #include <machine/bus.h> 89a7ee7a7dSMarius Strobl #include <machine/resource.h> 90a7ee7a7dSMarius Strobl 91a7ee7a7dSMarius Strobl #include <dev/pci/pcireg.h> 92a7ee7a7dSMarius Strobl #include <dev/pci/pcivar.h> 93a7ee7a7dSMarius Strobl 94a7ee7a7dSMarius Strobl #include <dev/le/lancereg.h> 95a7ee7a7dSMarius Strobl #include <dev/le/lancevar.h> 96a7ee7a7dSMarius Strobl #include <dev/le/am79900var.h> 97a7ee7a7dSMarius Strobl 98a7ee7a7dSMarius Strobl #define AMD_VENDOR 0x1022 99a7ee7a7dSMarius Strobl #define AMD_PCNET_PCI 0x2000 100a7ee7a7dSMarius Strobl #define AMD_PCNET_HOME 0x2001 10160c430f5SMarius Strobl #define PCNET_MEMSIZE (32*1024) 102a7ee7a7dSMarius Strobl #define PCNET_PCI_RDP 0x10 103a7ee7a7dSMarius Strobl #define PCNET_PCI_RAP 0x12 104a7ee7a7dSMarius Strobl #define PCNET_PCI_BDP 0x16 105a7ee7a7dSMarius Strobl 106a7ee7a7dSMarius Strobl struct le_pci_softc { 107a7ee7a7dSMarius Strobl struct am79900_softc sc_am79900; /* glue to MI code */ 108a7ee7a7dSMarius Strobl 109a7ee7a7dSMarius Strobl struct resource *sc_rres; 110a7ee7a7dSMarius Strobl 111a7ee7a7dSMarius Strobl struct resource *sc_ires; 112a7ee7a7dSMarius Strobl void *sc_ih; 113a7ee7a7dSMarius Strobl 114a7ee7a7dSMarius Strobl bus_dma_tag_t sc_pdmat; 115a7ee7a7dSMarius Strobl bus_dma_tag_t sc_dmat; 116a7ee7a7dSMarius Strobl bus_dmamap_t sc_dmam; 117a7ee7a7dSMarius Strobl }; 118a7ee7a7dSMarius Strobl 119a7ee7a7dSMarius Strobl static device_probe_t le_pci_probe; 120a7ee7a7dSMarius Strobl static device_attach_t le_pci_attach; 121a7ee7a7dSMarius Strobl static device_detach_t le_pci_detach; 122a7ee7a7dSMarius Strobl static device_resume_t le_pci_resume; 123a7ee7a7dSMarius Strobl static device_suspend_t le_pci_suspend; 124a7ee7a7dSMarius Strobl 125a7ee7a7dSMarius Strobl static device_method_t le_pci_methods[] = { 126a7ee7a7dSMarius Strobl /* Device interface */ 127a7ee7a7dSMarius Strobl DEVMETHOD(device_probe, le_pci_probe), 128a7ee7a7dSMarius Strobl DEVMETHOD(device_attach, le_pci_attach), 129a7ee7a7dSMarius Strobl DEVMETHOD(device_detach, le_pci_detach), 130a7ee7a7dSMarius Strobl /* We can just use the suspend method here. */ 131a7ee7a7dSMarius Strobl DEVMETHOD(device_shutdown, le_pci_suspend), 132a7ee7a7dSMarius Strobl DEVMETHOD(device_suspend, le_pci_suspend), 133a7ee7a7dSMarius Strobl DEVMETHOD(device_resume, le_pci_resume), 134a7ee7a7dSMarius Strobl 135a7ee7a7dSMarius Strobl { 0, 0 } 136a7ee7a7dSMarius Strobl }; 137a7ee7a7dSMarius Strobl 138a7ee7a7dSMarius Strobl DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc)); 1398e995b46SJohn Baldwin DRIVER_MODULE(le, pci, le_pci_driver, 0, 0); 14060c430f5SMarius Strobl MODULE_DEPEND(le, ether, 1, 1, 1); 141a7ee7a7dSMarius Strobl 142a7ee7a7dSMarius Strobl static const int le_home_supmedia[] = { 143a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0) 144a7ee7a7dSMarius Strobl }; 145a7ee7a7dSMarius Strobl 146a7ee7a7dSMarius Strobl static const int le_pci_supmedia[] = { 147a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 148a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FDX, 0), 149a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0), 150a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, 0), 151a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0), 152a7ee7a7dSMarius Strobl IFM_MAKEWORD(IFM_ETHER, IFM_10_5, IFM_FDX, 0) 153a7ee7a7dSMarius Strobl }; 154a7ee7a7dSMarius Strobl 155a7ee7a7dSMarius Strobl static void le_pci_wrbcr(struct lance_softc *, uint16_t, uint16_t); 156a7ee7a7dSMarius Strobl static uint16_t le_pci_rdbcr(struct lance_softc *, uint16_t); 157a7ee7a7dSMarius Strobl static void le_pci_wrcsr(struct lance_softc *, uint16_t, uint16_t); 158a7ee7a7dSMarius Strobl static uint16_t le_pci_rdcsr(struct lance_softc *, uint16_t); 159a7ee7a7dSMarius Strobl static int le_pci_mediachange(struct lance_softc *); 160a7ee7a7dSMarius Strobl static void le_pci_hwreset(struct lance_softc *); 161a7ee7a7dSMarius Strobl static bus_dmamap_callback_t le_pci_dma_callback; 162a7ee7a7dSMarius Strobl 163a7ee7a7dSMarius Strobl static void 164a7ee7a7dSMarius Strobl le_pci_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val) 165a7ee7a7dSMarius Strobl { 166a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 167a7ee7a7dSMarius Strobl 168c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 169c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 170c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_BDP, val); 171a7ee7a7dSMarius Strobl } 172a7ee7a7dSMarius Strobl 173a7ee7a7dSMarius Strobl static uint16_t 174a7ee7a7dSMarius Strobl le_pci_rdbcr(struct lance_softc *sc, uint16_t port) 175a7ee7a7dSMarius Strobl { 176a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 177a7ee7a7dSMarius Strobl 178c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 179c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 180c75c2a68SMarius Strobl return (bus_read_2(lesc->sc_rres, PCNET_PCI_BDP)); 181a7ee7a7dSMarius Strobl } 182a7ee7a7dSMarius Strobl 183a7ee7a7dSMarius Strobl static void 184a7ee7a7dSMarius Strobl le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 185a7ee7a7dSMarius Strobl { 186a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 187a7ee7a7dSMarius Strobl 188c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 189c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 190c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RDP, val); 191a7ee7a7dSMarius Strobl } 192a7ee7a7dSMarius Strobl 193a7ee7a7dSMarius Strobl static uint16_t 194a7ee7a7dSMarius Strobl le_pci_rdcsr(struct lance_softc *sc, uint16_t port) 195a7ee7a7dSMarius Strobl { 196a7ee7a7dSMarius Strobl struct le_pci_softc *lesc = (struct le_pci_softc *)sc; 197a7ee7a7dSMarius Strobl 198c75c2a68SMarius Strobl bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, port); 199c75c2a68SMarius Strobl bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); 200c75c2a68SMarius Strobl return (bus_read_2(lesc->sc_rres, PCNET_PCI_RDP)); 201a7ee7a7dSMarius Strobl } 202a7ee7a7dSMarius Strobl 203a7ee7a7dSMarius Strobl static int 204a7ee7a7dSMarius Strobl le_pci_mediachange(struct lance_softc *sc) 205a7ee7a7dSMarius Strobl { 206a7ee7a7dSMarius Strobl struct ifmedia *ifm = &sc->sc_media; 207a7ee7a7dSMarius Strobl uint16_t reg; 208a7ee7a7dSMarius Strobl 209a7ee7a7dSMarius Strobl if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 210a7ee7a7dSMarius Strobl return (EINVAL); 211a7ee7a7dSMarius Strobl 212a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) 213a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR49, 214a7ee7a7dSMarius Strobl (le_pci_rdbcr(sc, LE_BCR49) & ~LE_B49_PHYSEL) | 0x1); 215a7ee7a7dSMarius Strobl else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 216a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 217a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) | LE_B2_ASEL); 218a7ee7a7dSMarius Strobl else { 219a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR2, 220a7ee7a7dSMarius Strobl le_pci_rdbcr(sc, LE_BCR2) & ~LE_B2_ASEL); 221a7ee7a7dSMarius Strobl 222a7ee7a7dSMarius Strobl reg = le_pci_rdcsr(sc, LE_CSR15); 223a7ee7a7dSMarius Strobl reg &= ~LE_C15_PORTSEL(LE_PORTSEL_MASK); 224a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) 225a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_10T); 226a7ee7a7dSMarius Strobl else 227a7ee7a7dSMarius Strobl reg |= LE_C15_PORTSEL(LE_PORTSEL_AUI); 228a7ee7a7dSMarius Strobl le_pci_wrcsr(sc, LE_CSR15, reg); 229a7ee7a7dSMarius Strobl } 230a7ee7a7dSMarius Strobl 231a7ee7a7dSMarius Strobl reg = le_pci_rdbcr(sc, LE_BCR9); 232a7ee7a7dSMarius Strobl if (IFM_OPTIONS(ifm->ifm_media) & IFM_FDX) { 233a7ee7a7dSMarius Strobl reg |= LE_B9_FDEN; 234a7ee7a7dSMarius Strobl /* 235a7ee7a7dSMarius Strobl * Allow FDX on AUI only if explicitly chosen, 236a7ee7a7dSMarius Strobl * not in autoselect mode. 237a7ee7a7dSMarius Strobl */ 238a7ee7a7dSMarius Strobl if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_5) 239a7ee7a7dSMarius Strobl reg |= LE_B9_AUIFD; 240a7ee7a7dSMarius Strobl else 241a7ee7a7dSMarius Strobl reg &= ~LE_B9_AUIFD; 242a7ee7a7dSMarius Strobl } else 243a7ee7a7dSMarius Strobl reg &= ~LE_B9_FDEN; 244a7ee7a7dSMarius Strobl le_pci_wrbcr(sc, LE_BCR9, reg); 245a7ee7a7dSMarius Strobl 246a7ee7a7dSMarius Strobl return (0); 247a7ee7a7dSMarius Strobl } 248a7ee7a7dSMarius Strobl 249a7ee7a7dSMarius Strobl static void 250a7ee7a7dSMarius Strobl le_pci_hwreset(struct lance_softc *sc) 251a7ee7a7dSMarius Strobl { 252a7ee7a7dSMarius Strobl 2533a225e0bSMarius Strobl /* 2543a225e0bSMarius Strobl * Chip is stopped. Set software style to PCnet-PCI (32-bit). 2553a225e0bSMarius Strobl * Actually, am79900.c implements ILACC support (hence its 2563a225e0bSMarius Strobl * name) but unfortunately VMware does not. As far as this 2573a225e0bSMarius Strobl * driver is concerned that should not make a difference 2583a225e0bSMarius Strobl * though, as the settings used have the same meaning for 2593a225e0bSMarius Strobl * both, ILACC and PCnet-PCI (note that there would be a 2603a225e0bSMarius Strobl * difference for the ADD_FCS/NO_FCS bit if used). 2613a225e0bSMarius Strobl */ 2623a225e0bSMarius Strobl le_pci_wrbcr(sc, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2); 263a7ee7a7dSMarius Strobl } 264a7ee7a7dSMarius Strobl 265a7ee7a7dSMarius Strobl static void 266a7ee7a7dSMarius Strobl le_pci_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 267a7ee7a7dSMarius Strobl { 268a7ee7a7dSMarius Strobl struct lance_softc *sc = (struct lance_softc *)xsc; 269a7ee7a7dSMarius Strobl 270a7ee7a7dSMarius Strobl if (error != 0) 271a7ee7a7dSMarius Strobl return; 272a7ee7a7dSMarius Strobl KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__)); 273a7ee7a7dSMarius Strobl sc->sc_addr = segs[0].ds_addr; 274a7ee7a7dSMarius Strobl } 275a7ee7a7dSMarius Strobl 276a7ee7a7dSMarius Strobl static int 277a7ee7a7dSMarius Strobl le_pci_probe(device_t dev) 278a7ee7a7dSMarius Strobl { 279a7ee7a7dSMarius Strobl 280a7ee7a7dSMarius Strobl if (pci_get_vendor(dev) != AMD_VENDOR) 281a7ee7a7dSMarius Strobl return (ENXIO); 282a7ee7a7dSMarius Strobl 283a7ee7a7dSMarius Strobl switch (pci_get_device(dev)) { 284a7ee7a7dSMarius Strobl case AMD_PCNET_PCI: 28560c430f5SMarius Strobl device_set_desc(dev, "AMD PCnet-PCI"); 28660c430f5SMarius Strobl /* Let pcn(4) win. */ 28760c430f5SMarius Strobl return (BUS_PROBE_LOW_PRIORITY); 288a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 28960c430f5SMarius Strobl device_set_desc(dev, "AMD PCnet-Home"); 29060c430f5SMarius Strobl /* Let pcn(4) win. */ 29160c430f5SMarius Strobl return (BUS_PROBE_LOW_PRIORITY); 292a7ee7a7dSMarius Strobl default: 293a7ee7a7dSMarius Strobl return (ENXIO); 294a7ee7a7dSMarius Strobl } 295a7ee7a7dSMarius Strobl } 296a7ee7a7dSMarius Strobl 297a7ee7a7dSMarius Strobl static int 298a7ee7a7dSMarius Strobl le_pci_attach(device_t dev) 299a7ee7a7dSMarius Strobl { 300a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 301a7ee7a7dSMarius Strobl struct lance_softc *sc; 302a7ee7a7dSMarius Strobl int error, i; 303a7ee7a7dSMarius Strobl 304a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 305a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 306a7ee7a7dSMarius Strobl 307a7ee7a7dSMarius Strobl LE_LOCK_INIT(sc, device_get_nameunit(dev)); 308a7ee7a7dSMarius Strobl 309a7ee7a7dSMarius Strobl pci_enable_busmaster(dev); 310a7ee7a7dSMarius Strobl 311c75c2a68SMarius Strobl i = PCIR_BAR(0); 312a7ee7a7dSMarius Strobl lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 313c75c2a68SMarius Strobl &i, RF_ACTIVE); 314a7ee7a7dSMarius Strobl if (lesc->sc_rres == NULL) { 315a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate registers\n"); 316a7ee7a7dSMarius Strobl error = ENXIO; 317a7ee7a7dSMarius Strobl goto fail_mtx; 318a7ee7a7dSMarius Strobl } 319a7ee7a7dSMarius Strobl 320c75c2a68SMarius Strobl i = 0; 321a7ee7a7dSMarius Strobl if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 322c75c2a68SMarius Strobl &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 323a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate interrupt\n"); 324a7ee7a7dSMarius Strobl error = ENXIO; 325a7ee7a7dSMarius Strobl goto fail_rres; 326a7ee7a7dSMarius Strobl } 327a7ee7a7dSMarius Strobl 328a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 329d2255d02SMarius Strobl bus_get_dma_tag(dev), /* parent */ 33060c430f5SMarius Strobl 1, 0, /* alignment, boundary */ 331a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 332a7ee7a7dSMarius Strobl BUS_SPACE_MAXADDR, /* highaddr */ 333a7ee7a7dSMarius Strobl NULL, NULL, /* filter, filterarg */ 334a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 335a7ee7a7dSMarius Strobl 0, /* nsegments */ 336a7ee7a7dSMarius Strobl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 3370c7d35d0SMarius Strobl 0, /* flags */ 338a7ee7a7dSMarius Strobl NULL, NULL, /* lockfunc, lockarg */ 339a7ee7a7dSMarius Strobl &lesc->sc_pdmat); 340a7ee7a7dSMarius Strobl if (error != 0) { 341a7ee7a7dSMarius Strobl device_printf(dev, "cannot allocate parent DMA tag\n"); 342a7ee7a7dSMarius Strobl goto fail_ires; 343a7ee7a7dSMarius Strobl } 344a7ee7a7dSMarius Strobl 345a7ee7a7dSMarius Strobl sc->sc_memsize = PCNET_MEMSIZE; 34660c430f5SMarius Strobl /* 34760c430f5SMarius Strobl * For Am79C970A, Am79C971 and Am79C978 the init block must be 2-byte 34860c430f5SMarius Strobl * aligned and the ring descriptors must be 16-byte aligned when using 34960c430f5SMarius Strobl * a 32-bit software style. 35060c430f5SMarius Strobl */ 351a7ee7a7dSMarius Strobl error = bus_dma_tag_create( 352a7ee7a7dSMarius Strobl lesc->sc_pdmat, /* parent */ 35360c430f5SMarius Strobl 16, 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 */ 3600c7d35d0SMarius Strobl 0, /* 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 38660c430f5SMarius Strobl sc->sc_mediastatus = NULL; 387a7ee7a7dSMarius Strobl switch (pci_get_device(dev)) { 388a7ee7a7dSMarius Strobl case AMD_PCNET_HOME: 389a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 390a7ee7a7dSMarius Strobl sc->sc_supmedia = le_home_supmedia; 391a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_home_supmedia) / sizeof(int); 392a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_home_supmedia[0]; 393a7ee7a7dSMarius Strobl break; 394a7ee7a7dSMarius Strobl default: 395a7ee7a7dSMarius Strobl sc->sc_mediachange = le_pci_mediachange; 396a7ee7a7dSMarius Strobl sc->sc_supmedia = le_pci_supmedia; 397a7ee7a7dSMarius Strobl sc->sc_nsupmedia = sizeof(le_pci_supmedia) / sizeof(int); 398a7ee7a7dSMarius Strobl sc->sc_defaultmedia = le_pci_supmedia[0]; 399a7ee7a7dSMarius Strobl } 400a7ee7a7dSMarius Strobl 401a7ee7a7dSMarius Strobl /* 402a7ee7a7dSMarius Strobl * Extract the physical MAC address from the ROM. 403a7ee7a7dSMarius Strobl */ 404c75c2a68SMarius Strobl bus_read_region_1(lesc->sc_rres, 0, sc->sc_enaddr, 405c75c2a68SMarius Strobl sizeof(sc->sc_enaddr)); 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; 41660c430f5SMarius Strobl sc->sc_hwinit = NULL; 41760c430f5SMarius Strobl sc->sc_hwintr = NULL; 41860c430f5SMarius Strobl sc->sc_nocarrier = NULL; 419a7ee7a7dSMarius Strobl 420a7ee7a7dSMarius Strobl error = am79900_config(&lesc->sc_am79900, device_get_name(dev), 421a7ee7a7dSMarius Strobl device_get_unit(dev)); 422a7ee7a7dSMarius Strobl if (error != 0) { 42360c430f5SMarius Strobl device_printf(dev, "cannot attach Am79900\n"); 424a7ee7a7dSMarius Strobl goto fail_dmap; 425a7ee7a7dSMarius Strobl } 426a7ee7a7dSMarius Strobl 427a7ee7a7dSMarius Strobl error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 428ef544f63SPaolo Pisati NULL, am79900_intr, sc, &lesc->sc_ih); 429a7ee7a7dSMarius Strobl if (error != 0) { 430a7ee7a7dSMarius Strobl device_printf(dev, "cannot set up interrupt\n"); 431a7ee7a7dSMarius Strobl goto fail_am79900; 432a7ee7a7dSMarius Strobl } 433a7ee7a7dSMarius Strobl 434a7ee7a7dSMarius Strobl return (0); 435a7ee7a7dSMarius Strobl 436a7ee7a7dSMarius Strobl fail_am79900: 437a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 438a7ee7a7dSMarius Strobl fail_dmap: 439a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 440a7ee7a7dSMarius Strobl fail_dmem: 441a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 442a7ee7a7dSMarius Strobl fail_dtag: 443a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 444a7ee7a7dSMarius Strobl fail_pdtag: 445a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 446a7ee7a7dSMarius Strobl fail_ires: 447c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, 448c75c2a68SMarius Strobl rman_get_rid(lesc->sc_ires), lesc->sc_ires); 449a7ee7a7dSMarius Strobl fail_rres: 450c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, 451c75c2a68SMarius Strobl rman_get_rid(lesc->sc_rres), lesc->sc_rres); 452a7ee7a7dSMarius Strobl fail_mtx: 453a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 454a7ee7a7dSMarius Strobl return (error); 455a7ee7a7dSMarius Strobl } 456a7ee7a7dSMarius Strobl 457a7ee7a7dSMarius Strobl static int 458a7ee7a7dSMarius Strobl le_pci_detach(device_t dev) 459a7ee7a7dSMarius Strobl { 460a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 461a7ee7a7dSMarius Strobl struct lance_softc *sc; 462a7ee7a7dSMarius Strobl 463a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 464a7ee7a7dSMarius Strobl sc = &lesc->sc_am79900.lsc; 465a7ee7a7dSMarius Strobl 466a7ee7a7dSMarius Strobl bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 467a7ee7a7dSMarius Strobl am79900_detach(&lesc->sc_am79900); 468a7ee7a7dSMarius Strobl bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); 469a7ee7a7dSMarius Strobl bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); 470a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_dmat); 471a7ee7a7dSMarius Strobl bus_dma_tag_destroy(lesc->sc_pdmat); 472c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IRQ, 473c75c2a68SMarius Strobl rman_get_rid(lesc->sc_ires), lesc->sc_ires); 474c75c2a68SMarius Strobl bus_release_resource(dev, SYS_RES_IOPORT, 475c75c2a68SMarius Strobl rman_get_rid(lesc->sc_rres), lesc->sc_rres); 476a7ee7a7dSMarius Strobl LE_LOCK_DESTROY(sc); 477a7ee7a7dSMarius Strobl 478a7ee7a7dSMarius Strobl return (0); 479a7ee7a7dSMarius Strobl } 480a7ee7a7dSMarius Strobl 481a7ee7a7dSMarius Strobl static int 482a7ee7a7dSMarius Strobl le_pci_suspend(device_t dev) 483a7ee7a7dSMarius Strobl { 484a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 485a7ee7a7dSMarius Strobl 486a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 487a7ee7a7dSMarius Strobl 488a7ee7a7dSMarius Strobl lance_suspend(&lesc->sc_am79900.lsc); 489a7ee7a7dSMarius Strobl 490a7ee7a7dSMarius Strobl return (0); 491a7ee7a7dSMarius Strobl } 492a7ee7a7dSMarius Strobl 493a7ee7a7dSMarius Strobl static int 494a7ee7a7dSMarius Strobl le_pci_resume(device_t dev) 495a7ee7a7dSMarius Strobl { 496a7ee7a7dSMarius Strobl struct le_pci_softc *lesc; 497a7ee7a7dSMarius Strobl 498a7ee7a7dSMarius Strobl lesc = device_get_softc(dev); 499a7ee7a7dSMarius Strobl 500a7ee7a7dSMarius Strobl lance_resume(&lesc->sc_am79900.lsc); 501a7ee7a7dSMarius Strobl 502a7ee7a7dSMarius Strobl return (0); 503a7ee7a7dSMarius Strobl } 504