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