1*0ff4d878Sbrad /* $OpenBSD: if_epic_pci.c,v 1.2 2005/05/10 02:37:46 brad Exp $ */ 2059342fcSbrad /* $NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $ */ 3059342fcSbrad 4059342fcSbrad /*- 5059342fcSbrad * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 6059342fcSbrad * All rights reserved. 7059342fcSbrad * 8059342fcSbrad * This code is derived from software contributed to The NetBSD Foundation 9059342fcSbrad * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10059342fcSbrad * NASA Ames Research Center. 11059342fcSbrad * 12059342fcSbrad * Redistribution and use in source and binary forms, with or without 13059342fcSbrad * modification, are permitted provided that the following conditions 14059342fcSbrad * are met: 15059342fcSbrad * 1. Redistributions of source code must retain the above copyright 16059342fcSbrad * notice, this list of conditions and the following disclaimer. 17059342fcSbrad * 2. Redistributions in binary form must reproduce the above copyright 18059342fcSbrad * notice, this list of conditions and the following disclaimer in the 19059342fcSbrad * documentation and/or other materials provided with the distribution. 20059342fcSbrad * 3. All advertising materials mentioning features or use of this software 21059342fcSbrad * must display the following acknowledgement: 22059342fcSbrad * This product includes software developed by the NetBSD 23059342fcSbrad * Foundation, Inc. and its contributors. 24059342fcSbrad * 4. Neither the name of The NetBSD Foundation nor the names of its 25059342fcSbrad * contributors may be used to endorse or promote products derived 26059342fcSbrad * from this software without specific prior written permission. 27059342fcSbrad * 28059342fcSbrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29059342fcSbrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30059342fcSbrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31059342fcSbrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32059342fcSbrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33059342fcSbrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34059342fcSbrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35059342fcSbrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36059342fcSbrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37059342fcSbrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38059342fcSbrad * POSSIBILITY OF SUCH DAMAGE. 39059342fcSbrad */ 40059342fcSbrad 41059342fcSbrad /* 42059342fcSbrad * PCI bus front-end for the Standard Microsystems Corp. 83C170 43059342fcSbrad * Ethernet PCI Integrated Controller (EPIC/100) driver. 44059342fcSbrad */ 45059342fcSbrad 46059342fcSbrad #if 0 47059342fcSbrad #include <sys/cdefs.h> 48059342fcSbrad __KERNEL_RCSID(0, "$NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $"); 49059342fcSbrad #endif 50059342fcSbrad 51059342fcSbrad #include <sys/param.h> 52059342fcSbrad #include <sys/systm.h> 53059342fcSbrad #include <sys/mbuf.h> 54059342fcSbrad #include <sys/malloc.h> 55059342fcSbrad #include <sys/kernel.h> 56059342fcSbrad #include <sys/socket.h> 57059342fcSbrad #include <sys/ioctl.h> 58059342fcSbrad #include <sys/errno.h> 59059342fcSbrad #include <sys/device.h> 60059342fcSbrad 61059342fcSbrad #include <net/if.h> 62059342fcSbrad #include <net/if_dl.h> 63059342fcSbrad #include <net/if_types.h> 64059342fcSbrad 65059342fcSbrad #ifdef INET 66059342fcSbrad #include <netinet/in.h> 67059342fcSbrad #include <netinet/in_systm.h> 68059342fcSbrad #include <netinet/in_var.h> 69059342fcSbrad #include <netinet/ip.h> 70059342fcSbrad #include <netinet/if_ether.h> 71059342fcSbrad #endif 72059342fcSbrad 73059342fcSbrad #include <net/if_media.h> 74059342fcSbrad 75059342fcSbrad #include <machine/bus.h> 76059342fcSbrad #include <machine/intr.h> 77059342fcSbrad 78059342fcSbrad #include <dev/mii/miivar.h> 79059342fcSbrad 80059342fcSbrad #include <dev/ic/smc83c170reg.h> 81059342fcSbrad #include <dev/ic/smc83c170var.h> 82059342fcSbrad 83059342fcSbrad #include <dev/pci/pcivar.h> 84059342fcSbrad #include <dev/pci/pcireg.h> 85059342fcSbrad #include <dev/pci/pcidevs.h> 86059342fcSbrad 87059342fcSbrad /* 88059342fcSbrad * PCI configuration space registers used by the EPIC. 89059342fcSbrad */ 90059342fcSbrad #define EPIC_PCI_IOBA 0x10 /* i/o mapped base */ 91059342fcSbrad #define EPIC_PCI_MMBA 0x14 /* memory mapped base */ 92059342fcSbrad 93059342fcSbrad struct epic_pci_softc { 94059342fcSbrad struct epic_softc sc_epic; /* real EPIC softc */ 95059342fcSbrad 96059342fcSbrad /* PCI-specific goo. */ 97059342fcSbrad void *sc_ih; /* interrupt handle */ 98059342fcSbrad }; 99059342fcSbrad 100059342fcSbrad static int epic_pci_match(struct device *, void *, void *); 101059342fcSbrad static void epic_pci_attach(struct device *, struct device *, void *); 102059342fcSbrad 103059342fcSbrad struct cfattach epic_pci_ca = { 104059342fcSbrad sizeof(struct epic_pci_softc), epic_pci_match, epic_pci_attach 105059342fcSbrad }; 106059342fcSbrad 107*0ff4d878Sbrad const struct pci_matchid epic_pci_devices[] = { 108*0ff4d878Sbrad { PCI_VENDOR_SMC, PCI_PRODUCT_SMC_83C170 }, 109*0ff4d878Sbrad { PCI_VENDOR_SMC, PCI_PRODUCT_SMC_83C175 }, 110059342fcSbrad }; 111059342fcSbrad 112059342fcSbrad static const struct epic_pci_subsys_info { 113059342fcSbrad pcireg_t subsysid; 114059342fcSbrad int flags; 115059342fcSbrad } epic_pci_subsys_info[] = { 116059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa015), /* SMC9432BTX */ 117059342fcSbrad EPIC_HAS_BNC }, 118059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa024), /* SMC9432BTX1 */ 119059342fcSbrad EPIC_HAS_BNC }, 120059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa016), /* SMC9432FTX */ 121059342fcSbrad EPIC_HAS_MII_FIBER | EPIC_DUPLEXLED_ON_694 }, 122059342fcSbrad { 0xffffffff, 123059342fcSbrad 0 } 124059342fcSbrad }; 125059342fcSbrad 126059342fcSbrad static const struct epic_pci_subsys_info * 127059342fcSbrad epic_pci_subsys_lookup(const struct pci_attach_args *pa) 128059342fcSbrad { 129059342fcSbrad pci_chipset_tag_t pc = pa->pa_pc; 130059342fcSbrad pcireg_t reg; 131059342fcSbrad const struct epic_pci_subsys_info *esp; 132059342fcSbrad 133059342fcSbrad reg = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 134059342fcSbrad 135059342fcSbrad for (esp = epic_pci_subsys_info; esp->subsysid != 0xffffffff; esp++) 136059342fcSbrad if (esp->subsysid == reg) 137059342fcSbrad return (esp); 138059342fcSbrad 139059342fcSbrad return (NULL); 140059342fcSbrad } 141059342fcSbrad 142059342fcSbrad static int 143059342fcSbrad epic_pci_match(struct device *parent, void *match, void *aux) 144059342fcSbrad { 145*0ff4d878Sbrad return (pci_matchbyid((struct pci_attach_args *)aux, epic_pci_devices, 146*0ff4d878Sbrad sizeof(epic_pci_devices)/sizeof(epic_pci_devices[0]))); 147059342fcSbrad } 148059342fcSbrad 149059342fcSbrad static void 150059342fcSbrad epic_pci_attach(struct device *parent, struct device *self, void *aux) 151059342fcSbrad { 152059342fcSbrad struct epic_pci_softc *psc = (struct epic_pci_softc *)self; 153059342fcSbrad struct epic_softc *sc = &psc->sc_epic; 154059342fcSbrad struct pci_attach_args *pa = aux; 155059342fcSbrad pci_chipset_tag_t pc = pa->pa_pc; 156059342fcSbrad pci_intr_handle_t ih; 157059342fcSbrad const char *intrstr = NULL; 158059342fcSbrad const struct epic_pci_subsys_info *esp; 159059342fcSbrad bus_space_tag_t iot, memt; 160059342fcSbrad bus_space_handle_t ioh, memh; 161059342fcSbrad pcireg_t reg; 162059342fcSbrad int pmreg, ioh_valid, memh_valid; 163059342fcSbrad 164059342fcSbrad if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) { 165059342fcSbrad reg = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR); 166059342fcSbrad switch (reg & PCI_PMCSR_STATE_MASK) { 167059342fcSbrad case PCI_PMCSR_STATE_D1: 168059342fcSbrad case PCI_PMCSR_STATE_D2: 169059342fcSbrad printf(": waking up from power state D%d\n", 170059342fcSbrad sc->sc_dev.dv_xname, reg & PCI_PMCSR_STATE_MASK); 171059342fcSbrad pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR, 172059342fcSbrad (reg & ~PCI_PMCSR_STATE_MASK) | 173059342fcSbrad PCI_PMCSR_STATE_D0); 174059342fcSbrad break; 175059342fcSbrad case PCI_PMCSR_STATE_D3: 176059342fcSbrad /* 177059342fcSbrad * IO and MEM are disabled. We can't enable 178059342fcSbrad * the card because the BARs might be invalid. 179059342fcSbrad */ 180059342fcSbrad printf( 181059342fcSbrad ": unable to wake up from power state D3, " 182059342fcSbrad "reboot required.\n", sc->sc_dev.dv_xname); 183059342fcSbrad pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR, 184059342fcSbrad (reg & ~PCI_PMCSR_STATE_MASK) | 185059342fcSbrad PCI_PMCSR_STATE_D0); 186059342fcSbrad return; 187059342fcSbrad } 188059342fcSbrad } 189059342fcSbrad 190059342fcSbrad /* 191059342fcSbrad * Map the device. 192059342fcSbrad */ 193059342fcSbrad ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA, 194059342fcSbrad PCI_MAPREG_TYPE_IO, 0, 195059342fcSbrad &iot, &ioh, NULL, NULL, 0) == 0); 196059342fcSbrad memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA, 197059342fcSbrad PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, 198059342fcSbrad &memt, &memh, NULL, NULL, 0) == 0); 199059342fcSbrad 200059342fcSbrad if (memh_valid) { 201059342fcSbrad sc->sc_st = memt; 202059342fcSbrad sc->sc_sh = memh; 203059342fcSbrad } else if (ioh_valid) { 204059342fcSbrad sc->sc_st = iot; 205059342fcSbrad sc->sc_sh = ioh; 206059342fcSbrad } else { 207059342fcSbrad printf(": unable to map device registers\n", 208059342fcSbrad sc->sc_dev.dv_xname); 209059342fcSbrad return; 210059342fcSbrad } 211059342fcSbrad 212059342fcSbrad sc->sc_dmat = pa->pa_dmat; 213059342fcSbrad 214059342fcSbrad /* Make sure bus mastering is enabled. */ 215059342fcSbrad pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 216059342fcSbrad pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | 217059342fcSbrad PCI_COMMAND_MASTER_ENABLE); 218059342fcSbrad 219059342fcSbrad /* 220059342fcSbrad * Map and establish our interrupt. 221059342fcSbrad */ 222059342fcSbrad if (pci_intr_map(pa, &ih)) { 223059342fcSbrad printf(": unable to map interrupt\n", 224059342fcSbrad sc->sc_dev.dv_xname); 225059342fcSbrad return; 226059342fcSbrad } 227059342fcSbrad intrstr = pci_intr_string(pc, ih); 228059342fcSbrad psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc, 229059342fcSbrad self->dv_xname); 230059342fcSbrad if (psc->sc_ih == NULL) { 231059342fcSbrad printf("%s: unable to establish interrupt", 232059342fcSbrad sc->sc_dev.dv_xname); 233059342fcSbrad if (intrstr != NULL) 234059342fcSbrad printf(" at %s", intrstr); 235059342fcSbrad printf("\n"); 236059342fcSbrad return; 237059342fcSbrad } 238059342fcSbrad 239059342fcSbrad esp = epic_pci_subsys_lookup(pa); 240059342fcSbrad if (esp) 241059342fcSbrad sc->sc_hwflags = esp->flags; 242059342fcSbrad 243059342fcSbrad /* 244059342fcSbrad * Finish off the attach. 245059342fcSbrad */ 246059342fcSbrad epic_attach(sc, intrstr); 247059342fcSbrad } 248