1 /* $OpenBSD: if_re_cardbus.c,v 1.28 2015/11/24 17:11:39 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Peter Valchev <pvalchev@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Cardbus front-end for the Realtek 8169 21 */ 22 23 #include <sys/param.h> 24 #include <sys/endian.h> 25 #include <sys/systm.h> 26 #include <sys/sockio.h> 27 #include <sys/mbuf.h> 28 #include <sys/malloc.h> 29 #include <sys/kernel.h> 30 #include <sys/device.h> 31 #include <sys/timeout.h> 32 #include <sys/socket.h> 33 34 #include <net/if.h> 35 #include <net/if_media.h> 36 37 #include <netinet/in.h> 38 #include <netinet/if_ether.h> 39 40 #include <dev/mii/miivar.h> 41 42 #include <dev/pci/pcidevs.h> 43 44 #include <dev/cardbus/cardbusvar.h> 45 46 #include <dev/ic/rtl81x9reg.h> 47 #include <dev/ic/revar.h> 48 49 struct re_cardbus_softc { 50 /* General */ 51 struct rl_softc sc_rl; 52 53 /* Cardbus-specific data */ 54 void *sc_ih; 55 cardbus_devfunc_t ct; 56 pcitag_t sc_tag; 57 pci_chipset_tag_t sc_pc; 58 int sc_csr; 59 int sc_cben; 60 int sc_bar_reg; 61 pcireg_t sc_bar_val; 62 int sc_intrline; 63 64 bus_size_t sc_mapsize; 65 }; 66 67 int re_cardbus_probe(struct device *, void *, void *); 68 void re_cardbus_attach(struct device *, struct device *, void *); 69 int re_cardbus_detach(struct device *, int); 70 void re_cardbus_setup(struct rl_softc *); 71 72 /* 73 * Cardbus autoconfig definitions 74 */ 75 struct cfattach re_cardbus_ca = { 76 sizeof(struct re_cardbus_softc), 77 re_cardbus_probe, 78 re_cardbus_attach, 79 re_cardbus_detach 80 }; 81 82 const struct pci_matchid re_cardbus_devices[] = { 83 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 }, 84 }; 85 86 /* 87 * Probe for a Realtek 8169/8110 chip. Check the PCI vendor and device 88 * IDs against our list and return a device name if we find a match. 89 */ 90 int 91 re_cardbus_probe(struct device *parent, void *match, void *aux) 92 { 93 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 94 re_cardbus_devices, nitems(re_cardbus_devices))); 95 } 96 97 /* 98 * Attach the interface. Allocate softc structures, do ifmedia 99 * setup and ethernet/BPF attach. 100 */ 101 void 102 re_cardbus_attach(struct device *parent, struct device *self, void *aux) 103 { 104 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self; 105 struct rl_softc *sc = &csc->sc_rl; 106 struct cardbus_attach_args *ca = aux; 107 struct cardbus_softc *psc = 108 (struct cardbus_softc *)sc->sc_dev.dv_parent; 109 cardbus_chipset_tag_t cc = psc->sc_cc; 110 cardbus_function_tag_t cf = psc->sc_cf; 111 cardbus_devfunc_t ct = ca->ca_ct; 112 bus_addr_t adr; 113 char intrstr[16]; 114 115 sc->sc_dmat = ca->ca_dmat; 116 csc->ct = ct; 117 csc->sc_tag = ca->ca_tag; 118 csc->sc_pc = ca->ca_pc; 119 csc->sc_intrline = ca->ca_intrline; 120 121 /* 122 * Map control/status registers. 123 */ 124 if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0, 125 &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) { 126 csc->sc_cben = CARDBUS_MEM_ENABLE; 127 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; 128 csc->sc_bar_reg = RL_PCI_LOMEM; 129 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; 130 } else { 131 printf(": can't map mem space\n"); 132 return; 133 } 134 135 /* Enable power */ 136 Cardbus_function_enable(ct); 137 138 /* Get chip out of powersave mode (if applicable), initialize 139 * config registers */ 140 re_cardbus_setup(sc); 141 142 /* Allocate interrupt */ 143 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 144 IPL_NET, re_intr, sc, sc->sc_dev.dv_xname); 145 if (csc->sc_ih == NULL) { 146 printf(": couldn't establish interrupt at %d", 147 ca->ca_intrline); 148 Cardbus_function_disable(csc->ct); 149 return; 150 } 151 snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline); 152 153 sc->sc_product = PCI_PRODUCT(ca->ca_id); 154 155 /* Call bus-independent (common) attach routine */ 156 if (re_attach(sc, intrstr)) { 157 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 158 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, 159 sc->rl_bhandle, csc->sc_mapsize); 160 } 161 } 162 163 /* 164 * Get chip out of power-saving mode, init registers 165 */ 166 void 167 re_cardbus_setup(struct rl_softc *sc) 168 { 169 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc; 170 cardbus_devfunc_t ct = csc->ct; 171 cardbus_chipset_tag_t cc = ct->ct_cc; 172 pci_chipset_tag_t pc = csc->sc_pc; 173 pcireg_t reg, command; 174 int pmreg; 175 176 /* Handle power management nonsense */ 177 if (pci_get_capability(pc, csc->sc_tag, 178 PCI_CAP_PWRMGMT, &pmreg, 0)) { 179 command = pci_conf_read(pc, csc->sc_tag, 180 pmreg + PCI_PMCSR); 181 182 if (command & RL_PSTATE_MASK) { 183 pcireg_t iobase, membase, irq; 184 185 /* Save important PCI config data */ 186 iobase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOIO); 187 membase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOMEM); 188 irq = pci_conf_read(pc, csc->sc_tag, RL_PCI_INTLINE); 189 190 /* Reset the power state */ 191 printf("%s: chip is in D%d power mode " 192 "-- setting to D0\n", sc->sc_dev.dv_xname, 193 command & RL_PSTATE_MASK); 194 command &= RL_PSTATE_MASK; 195 pci_conf_write(pc, csc->sc_tag, pmreg + PCI_PMCSR, 196 command); 197 198 /* Restore PCI config data */ 199 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOIO, iobase); 200 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOMEM, membase); 201 pci_conf_write(pc, csc->sc_tag, RL_PCI_INTLINE, irq); 202 } 203 } 204 205 /* Make sure the right access type is on the Cardbus bridge */ 206 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); 207 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 208 209 /* Program the BAR */ 210 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); 211 212 /* Enable proper bits in CARDBUS CSR */ 213 reg = pci_conf_read(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG); 214 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); 215 reg |= csc->sc_csr; 216 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 217 218 /* Make sure the latency timer is set to some reasonable value */ 219 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 220 if (PCI_LATTIMER(reg) < 0x20) { 221 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 222 reg |= (0x20 << PCI_LATTIMER_SHIFT); 223 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 224 } 225 } 226 227 /* 228 * Cardbus detach function: deallocate all resources 229 */ 230 int 231 re_cardbus_detach(struct device *self, int flags) 232 { 233 struct re_cardbus_softc *csc = (void *)self; 234 struct rl_softc *sc = &csc->sc_rl; 235 struct cardbus_devfunc *ct = csc->ct; 236 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 237 238 /* Remove timeout handler */ 239 timeout_del(&sc->timer_handle); 240 241 /* Detach PHY */ 242 if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL) 243 mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY); 244 245 /* Delete media stuff */ 246 ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY); 247 ether_ifdetach(ifp); 248 if_detach(ifp); 249 250 /* Disable interrupts */ 251 if (csc->sc_ih != NULL) 252 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 253 254 /* Free cardbus resources */ 255 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle, 256 csc->sc_mapsize); 257 258 return (0); 259 } 260