1*059342fcSbrad /* $OpenBSD: if_epic_pci.c,v 1.1 2005/05/10 01:16:32 brad Exp $ */ 2*059342fcSbrad /* $NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $ */ 3*059342fcSbrad 4*059342fcSbrad /*- 5*059342fcSbrad * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 6*059342fcSbrad * All rights reserved. 7*059342fcSbrad * 8*059342fcSbrad * This code is derived from software contributed to The NetBSD Foundation 9*059342fcSbrad * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10*059342fcSbrad * NASA Ames Research Center. 11*059342fcSbrad * 12*059342fcSbrad * Redistribution and use in source and binary forms, with or without 13*059342fcSbrad * modification, are permitted provided that the following conditions 14*059342fcSbrad * are met: 15*059342fcSbrad * 1. Redistributions of source code must retain the above copyright 16*059342fcSbrad * notice, this list of conditions and the following disclaimer. 17*059342fcSbrad * 2. Redistributions in binary form must reproduce the above copyright 18*059342fcSbrad * notice, this list of conditions and the following disclaimer in the 19*059342fcSbrad * documentation and/or other materials provided with the distribution. 20*059342fcSbrad * 3. All advertising materials mentioning features or use of this software 21*059342fcSbrad * must display the following acknowledgement: 22*059342fcSbrad * This product includes software developed by the NetBSD 23*059342fcSbrad * Foundation, Inc. and its contributors. 24*059342fcSbrad * 4. Neither the name of The NetBSD Foundation nor the names of its 25*059342fcSbrad * contributors may be used to endorse or promote products derived 26*059342fcSbrad * from this software without specific prior written permission. 27*059342fcSbrad * 28*059342fcSbrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29*059342fcSbrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30*059342fcSbrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31*059342fcSbrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32*059342fcSbrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33*059342fcSbrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34*059342fcSbrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35*059342fcSbrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36*059342fcSbrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37*059342fcSbrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38*059342fcSbrad * POSSIBILITY OF SUCH DAMAGE. 39*059342fcSbrad */ 40*059342fcSbrad 41*059342fcSbrad /* 42*059342fcSbrad * PCI bus front-end for the Standard Microsystems Corp. 83C170 43*059342fcSbrad * Ethernet PCI Integrated Controller (EPIC/100) driver. 44*059342fcSbrad */ 45*059342fcSbrad 46*059342fcSbrad #if 0 47*059342fcSbrad #include <sys/cdefs.h> 48*059342fcSbrad __KERNEL_RCSID(0, "$NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $"); 49*059342fcSbrad #endif 50*059342fcSbrad 51*059342fcSbrad #include <sys/param.h> 52*059342fcSbrad #include <sys/systm.h> 53*059342fcSbrad #include <sys/mbuf.h> 54*059342fcSbrad #include <sys/malloc.h> 55*059342fcSbrad #include <sys/kernel.h> 56*059342fcSbrad #include <sys/socket.h> 57*059342fcSbrad #include <sys/ioctl.h> 58*059342fcSbrad #include <sys/errno.h> 59*059342fcSbrad #include <sys/device.h> 60*059342fcSbrad 61*059342fcSbrad #include <net/if.h> 62*059342fcSbrad #include <net/if_dl.h> 63*059342fcSbrad #include <net/if_types.h> 64*059342fcSbrad 65*059342fcSbrad #ifdef INET 66*059342fcSbrad #include <netinet/in.h> 67*059342fcSbrad #include <netinet/in_systm.h> 68*059342fcSbrad #include <netinet/in_var.h> 69*059342fcSbrad #include <netinet/ip.h> 70*059342fcSbrad #include <netinet/if_ether.h> 71*059342fcSbrad #endif 72*059342fcSbrad 73*059342fcSbrad #include <net/if_media.h> 74*059342fcSbrad 75*059342fcSbrad #include <machine/bus.h> 76*059342fcSbrad #include <machine/intr.h> 77*059342fcSbrad 78*059342fcSbrad #include <dev/mii/miivar.h> 79*059342fcSbrad 80*059342fcSbrad #include <dev/ic/smc83c170reg.h> 81*059342fcSbrad #include <dev/ic/smc83c170var.h> 82*059342fcSbrad 83*059342fcSbrad #include <dev/pci/pcivar.h> 84*059342fcSbrad #include <dev/pci/pcireg.h> 85*059342fcSbrad #include <dev/pci/pcidevs.h> 86*059342fcSbrad 87*059342fcSbrad /* 88*059342fcSbrad * PCI configuration space registers used by the EPIC. 89*059342fcSbrad */ 90*059342fcSbrad #define EPIC_PCI_IOBA 0x10 /* i/o mapped base */ 91*059342fcSbrad #define EPIC_PCI_MMBA 0x14 /* memory mapped base */ 92*059342fcSbrad 93*059342fcSbrad struct epic_pci_softc { 94*059342fcSbrad struct epic_softc sc_epic; /* real EPIC softc */ 95*059342fcSbrad 96*059342fcSbrad /* PCI-specific goo. */ 97*059342fcSbrad void *sc_ih; /* interrupt handle */ 98*059342fcSbrad }; 99*059342fcSbrad 100*059342fcSbrad static int epic_pci_match(struct device *, void *, void *); 101*059342fcSbrad static void epic_pci_attach(struct device *, struct device *, void *); 102*059342fcSbrad 103*059342fcSbrad struct cfattach epic_pci_ca = { 104*059342fcSbrad sizeof(struct epic_pci_softc), epic_pci_match, epic_pci_attach 105*059342fcSbrad }; 106*059342fcSbrad 107*059342fcSbrad static const struct epic_pci_product { 108*059342fcSbrad u_int32_t epp_prodid; /* PCI product ID */ 109*059342fcSbrad const char *epp_name; /* device name */ 110*059342fcSbrad } epic_pci_products[] = { 111*059342fcSbrad { PCI_PRODUCT_SMC_83C170, "SMC 83c170 Fast Ethernet" }, 112*059342fcSbrad { PCI_PRODUCT_SMC_83C175, "SMC 83c175 Fast Ethernet" }, 113*059342fcSbrad { 0, NULL }, 114*059342fcSbrad }; 115*059342fcSbrad 116*059342fcSbrad static const struct epic_pci_product * 117*059342fcSbrad epic_pci_lookup(const struct pci_attach_args *pa) 118*059342fcSbrad { 119*059342fcSbrad const struct epic_pci_product *epp; 120*059342fcSbrad 121*059342fcSbrad if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SMC) 122*059342fcSbrad return (NULL); 123*059342fcSbrad 124*059342fcSbrad for (epp = epic_pci_products; epp->epp_name != NULL; epp++) 125*059342fcSbrad if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid) 126*059342fcSbrad return (epp); 127*059342fcSbrad 128*059342fcSbrad return (NULL); 129*059342fcSbrad } 130*059342fcSbrad 131*059342fcSbrad static const struct epic_pci_subsys_info { 132*059342fcSbrad pcireg_t subsysid; 133*059342fcSbrad int flags; 134*059342fcSbrad } epic_pci_subsys_info[] = { 135*059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa015), /* SMC9432BTX */ 136*059342fcSbrad EPIC_HAS_BNC }, 137*059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa024), /* SMC9432BTX1 */ 138*059342fcSbrad EPIC_HAS_BNC }, 139*059342fcSbrad { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa016), /* SMC9432FTX */ 140*059342fcSbrad EPIC_HAS_MII_FIBER | EPIC_DUPLEXLED_ON_694 }, 141*059342fcSbrad { 0xffffffff, 142*059342fcSbrad 0 } 143*059342fcSbrad }; 144*059342fcSbrad 145*059342fcSbrad static const struct epic_pci_subsys_info * 146*059342fcSbrad epic_pci_subsys_lookup(const struct pci_attach_args *pa) 147*059342fcSbrad { 148*059342fcSbrad pci_chipset_tag_t pc = pa->pa_pc; 149*059342fcSbrad pcireg_t reg; 150*059342fcSbrad const struct epic_pci_subsys_info *esp; 151*059342fcSbrad 152*059342fcSbrad reg = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 153*059342fcSbrad 154*059342fcSbrad for (esp = epic_pci_subsys_info; esp->subsysid != 0xffffffff; esp++) 155*059342fcSbrad if (esp->subsysid == reg) 156*059342fcSbrad return (esp); 157*059342fcSbrad 158*059342fcSbrad return (NULL); 159*059342fcSbrad } 160*059342fcSbrad 161*059342fcSbrad static int 162*059342fcSbrad epic_pci_match(struct device *parent, void *match, void *aux) 163*059342fcSbrad { 164*059342fcSbrad struct pci_attach_args *pa = aux; 165*059342fcSbrad 166*059342fcSbrad if (epic_pci_lookup(pa) != NULL) 167*059342fcSbrad return (1); 168*059342fcSbrad 169*059342fcSbrad return (0); 170*059342fcSbrad } 171*059342fcSbrad 172*059342fcSbrad static void 173*059342fcSbrad epic_pci_attach(struct device *parent, struct device *self, void *aux) 174*059342fcSbrad { 175*059342fcSbrad struct epic_pci_softc *psc = (struct epic_pci_softc *)self; 176*059342fcSbrad struct epic_softc *sc = &psc->sc_epic; 177*059342fcSbrad struct pci_attach_args *pa = aux; 178*059342fcSbrad pci_chipset_tag_t pc = pa->pa_pc; 179*059342fcSbrad pci_intr_handle_t ih; 180*059342fcSbrad const char *intrstr = NULL; 181*059342fcSbrad const struct epic_pci_product *epp; 182*059342fcSbrad const struct epic_pci_subsys_info *esp; 183*059342fcSbrad bus_space_tag_t iot, memt; 184*059342fcSbrad bus_space_handle_t ioh, memh; 185*059342fcSbrad pcireg_t reg; 186*059342fcSbrad int pmreg, ioh_valid, memh_valid; 187*059342fcSbrad 188*059342fcSbrad epp = epic_pci_lookup(pa); 189*059342fcSbrad if (epp == NULL) { 190*059342fcSbrad printf("\n"); 191*059342fcSbrad panic(": epic_pci_attach: impossible"); 192*059342fcSbrad } 193*059342fcSbrad 194*059342fcSbrad if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) { 195*059342fcSbrad reg = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR); 196*059342fcSbrad switch (reg & PCI_PMCSR_STATE_MASK) { 197*059342fcSbrad case PCI_PMCSR_STATE_D1: 198*059342fcSbrad case PCI_PMCSR_STATE_D2: 199*059342fcSbrad printf(": waking up from power state D%d\n", 200*059342fcSbrad sc->sc_dev.dv_xname, reg & PCI_PMCSR_STATE_MASK); 201*059342fcSbrad pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR, 202*059342fcSbrad (reg & ~PCI_PMCSR_STATE_MASK) | 203*059342fcSbrad PCI_PMCSR_STATE_D0); 204*059342fcSbrad break; 205*059342fcSbrad case PCI_PMCSR_STATE_D3: 206*059342fcSbrad /* 207*059342fcSbrad * IO and MEM are disabled. We can't enable 208*059342fcSbrad * the card because the BARs might be invalid. 209*059342fcSbrad */ 210*059342fcSbrad printf( 211*059342fcSbrad ": unable to wake up from power state D3, " 212*059342fcSbrad "reboot required.\n", sc->sc_dev.dv_xname); 213*059342fcSbrad pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR, 214*059342fcSbrad (reg & ~PCI_PMCSR_STATE_MASK) | 215*059342fcSbrad PCI_PMCSR_STATE_D0); 216*059342fcSbrad return; 217*059342fcSbrad } 218*059342fcSbrad } 219*059342fcSbrad 220*059342fcSbrad /* 221*059342fcSbrad * Map the device. 222*059342fcSbrad */ 223*059342fcSbrad ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA, 224*059342fcSbrad PCI_MAPREG_TYPE_IO, 0, 225*059342fcSbrad &iot, &ioh, NULL, NULL, 0) == 0); 226*059342fcSbrad memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA, 227*059342fcSbrad PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, 228*059342fcSbrad &memt, &memh, NULL, NULL, 0) == 0); 229*059342fcSbrad 230*059342fcSbrad if (memh_valid) { 231*059342fcSbrad sc->sc_st = memt; 232*059342fcSbrad sc->sc_sh = memh; 233*059342fcSbrad } else if (ioh_valid) { 234*059342fcSbrad sc->sc_st = iot; 235*059342fcSbrad sc->sc_sh = ioh; 236*059342fcSbrad } else { 237*059342fcSbrad printf(": unable to map device registers\n", 238*059342fcSbrad sc->sc_dev.dv_xname); 239*059342fcSbrad return; 240*059342fcSbrad } 241*059342fcSbrad 242*059342fcSbrad sc->sc_dmat = pa->pa_dmat; 243*059342fcSbrad 244*059342fcSbrad /* Make sure bus mastering is enabled. */ 245*059342fcSbrad pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 246*059342fcSbrad pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | 247*059342fcSbrad PCI_COMMAND_MASTER_ENABLE); 248*059342fcSbrad 249*059342fcSbrad /* 250*059342fcSbrad * Map and establish our interrupt. 251*059342fcSbrad */ 252*059342fcSbrad if (pci_intr_map(pa, &ih)) { 253*059342fcSbrad printf(": unable to map interrupt\n", 254*059342fcSbrad sc->sc_dev.dv_xname); 255*059342fcSbrad return; 256*059342fcSbrad } 257*059342fcSbrad intrstr = pci_intr_string(pc, ih); 258*059342fcSbrad psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc, 259*059342fcSbrad self->dv_xname); 260*059342fcSbrad if (psc->sc_ih == NULL) { 261*059342fcSbrad printf("%s: unable to establish interrupt", 262*059342fcSbrad sc->sc_dev.dv_xname); 263*059342fcSbrad if (intrstr != NULL) 264*059342fcSbrad printf(" at %s", intrstr); 265*059342fcSbrad printf("\n"); 266*059342fcSbrad return; 267*059342fcSbrad } 268*059342fcSbrad 269*059342fcSbrad esp = epic_pci_subsys_lookup(pa); 270*059342fcSbrad if (esp) 271*059342fcSbrad sc->sc_hwflags = esp->flags; 272*059342fcSbrad 273*059342fcSbrad /* 274*059342fcSbrad * Finish off the attach. 275*059342fcSbrad */ 276*059342fcSbrad epic_attach(sc, intrstr); 277*059342fcSbrad } 278