1 /* $OpenBSD: if_re_cardbus.c,v 1.22 2011/04/02 17:47:04 jasper 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_dl.h> 36 #include <net/if_media.h> 37 38 #ifdef INET 39 #include <netinet/in.h> 40 #include <netinet/in_systm.h> 41 #include <netinet/in_var.h> 42 #include <netinet/ip.h> 43 #include <netinet/if_ether.h> 44 #endif 45 46 #include <dev/mii/mii.h> 47 #include <dev/mii/miivar.h> 48 49 #include <dev/pci/pcidevs.h> 50 51 #include <dev/cardbus/cardbusvar.h> 52 53 #include <dev/ic/rtl81x9reg.h> 54 #include <dev/ic/revar.h> 55 56 struct re_cardbus_softc { 57 /* General */ 58 struct rl_softc sc_rl; 59 60 /* Cardbus-specific data */ 61 void *sc_ih; 62 cardbus_devfunc_t ct; 63 pcitag_t sc_tag; 64 pci_chipset_tag_t sc_pc; 65 int sc_csr; 66 int sc_cben; 67 int sc_bar_reg; 68 pcireg_t sc_bar_val; 69 int sc_intrline; 70 71 bus_size_t sc_mapsize; 72 }; 73 74 int re_cardbus_probe(struct device *, void *, void *); 75 void re_cardbus_attach(struct device *, struct device *, void *); 76 int re_cardbus_detach(struct device *, int); 77 void re_cardbus_setup(struct rl_softc *); 78 79 /* 80 * Cardbus autoconfig definitions 81 */ 82 struct cfattach re_cardbus_ca = { 83 sizeof(struct re_cardbus_softc), 84 re_cardbus_probe, 85 re_cardbus_attach, 86 re_cardbus_detach 87 }; 88 89 const struct pci_matchid re_cardbus_devices[] = { 90 { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 }, 91 }; 92 93 /* 94 * Probe for a RealTek 8169/8110 chip. Check the PCI vendor and device 95 * IDs against our list and return a device name if we find a match. 96 */ 97 int 98 re_cardbus_probe(struct device *parent, void *match, void *aux) 99 { 100 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 101 re_cardbus_devices, nitems(re_cardbus_devices))); 102 } 103 104 /* 105 * Attach the interface. Allocate softc structures, do ifmedia 106 * setup and ethernet/BPF attach. 107 */ 108 void 109 re_cardbus_attach(struct device *parent, struct device *self, void *aux) 110 { 111 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self; 112 struct rl_softc *sc = &csc->sc_rl; 113 struct cardbus_attach_args *ca = aux; 114 struct cardbus_softc *psc = 115 (struct cardbus_softc *)sc->sc_dev.dv_parent; 116 cardbus_chipset_tag_t cc = psc->sc_cc; 117 cardbus_function_tag_t cf = psc->sc_cf; 118 cardbus_devfunc_t ct = ca->ca_ct; 119 bus_addr_t adr; 120 char intrstr[16]; 121 122 sc->sc_dmat = ca->ca_dmat; 123 csc->ct = ct; 124 csc->sc_tag = ca->ca_tag; 125 csc->sc_pc = ca->ca_pc; 126 csc->sc_intrline = ca->ca_intrline; 127 128 /* 129 * Map control/status registers. 130 */ 131 if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0, 132 &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) { 133 csc->sc_cben = CARDBUS_MEM_ENABLE; 134 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; 135 csc->sc_bar_reg = RL_PCI_LOMEM; 136 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; 137 } else { 138 printf(": can't map mem space\n"); 139 return; 140 } 141 142 /* Enable power */ 143 Cardbus_function_enable(ct); 144 145 /* Get chip out of powersave mode (if applicable), initialize 146 * config registers */ 147 re_cardbus_setup(sc); 148 149 /* Allocate interrupt */ 150 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, 151 IPL_NET, re_intr, sc, sc->sc_dev.dv_xname); 152 if (csc->sc_ih == NULL) { 153 printf(": couldn't establish interrupt at %d", 154 ca->ca_intrline); 155 Cardbus_function_disable(csc->ct); 156 return; 157 } 158 snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline); 159 160 /* Call bus-independent (common) attach routine */ 161 if (re_attach(sc, intrstr)) { 162 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 163 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, 164 sc->rl_bhandle, csc->sc_mapsize); 165 } 166 } 167 168 /* 169 * Get chip out of power-saving mode, init registers 170 */ 171 void 172 re_cardbus_setup(struct rl_softc *sc) 173 { 174 struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc; 175 cardbus_devfunc_t ct = csc->ct; 176 cardbus_chipset_tag_t cc = ct->ct_cc; 177 pci_chipset_tag_t pc = csc->sc_pc; 178 pcireg_t reg, command; 179 int pmreg; 180 181 /* Handle power management nonsense */ 182 if (pci_get_capability(pc, csc->sc_tag, 183 PCI_CAP_PWRMGMT, &pmreg, 0)) { 184 command = pci_conf_read(pc, csc->sc_tag, 185 pmreg + PCI_PMCSR); 186 187 if (command & RL_PSTATE_MASK) { 188 pcireg_t iobase, membase, irq; 189 190 /* Save important PCI config data */ 191 iobase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOIO); 192 membase = pci_conf_read(pc, csc->sc_tag, RL_PCI_LOMEM); 193 irq = pci_conf_read(pc, csc->sc_tag, RL_PCI_INTLINE); 194 195 /* Reset the power state */ 196 printf("%s: chip is in D%d power mode " 197 "-- setting to D0\n", sc->sc_dev.dv_xname, 198 command & RL_PSTATE_MASK); 199 command &= RL_PSTATE_MASK; 200 pci_conf_write(pc, csc->sc_tag, pmreg + PCI_PMCSR, 201 command); 202 203 /* Restore PCI config data */ 204 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOIO, iobase); 205 pci_conf_write(pc, csc->sc_tag, RL_PCI_LOMEM, membase); 206 pci_conf_write(pc, csc->sc_tag, RL_PCI_INTLINE, irq); 207 } 208 } 209 210 /* Make sure the right access type is on the Cardbus bridge */ 211 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); 212 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 213 214 /* Program the BAR */ 215 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val); 216 217 /* Enable proper bits in CARDBUS CSR */ 218 reg = pci_conf_read(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG); 219 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); 220 reg |= csc->sc_csr; 221 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 222 223 /* Make sure the latency timer is set to some reasonable value */ 224 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 225 if (PCI_LATTIMER(reg) < 0x20) { 226 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 227 reg |= (0x20 << PCI_LATTIMER_SHIFT); 228 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 229 } 230 } 231 232 /* 233 * Cardbus detach function: deallocate all resources 234 */ 235 int 236 re_cardbus_detach(struct device *self, int flags) 237 { 238 struct re_cardbus_softc *csc = (void *)self; 239 struct rl_softc *sc = &csc->sc_rl; 240 struct cardbus_devfunc *ct = csc->ct; 241 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 242 243 /* Remove timeout handler */ 244 timeout_del(&sc->timer_handle); 245 246 /* Detach PHY */ 247 if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL) 248 mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY); 249 250 /* Delete media stuff */ 251 ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY); 252 ether_ifdetach(ifp); 253 if_detach(ifp); 254 255 /* Disable interrupts */ 256 if (csc->sc_ih != NULL) 257 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 258 259 /* Free cardbus resources */ 260 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle, 261 csc->sc_mapsize); 262 263 return (0); 264 } 265