1 /* $OpenBSD: if_athn_cardbus.c,v 1.15 2017/01/12 16:32:28 stsp Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> 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 Atheros 802.11a/g/n chipsets. 21 */ 22 23 #include "bpfilter.h" 24 25 #include <sys/param.h> 26 #include <sys/sockio.h> 27 #include <sys/mbuf.h> 28 #include <sys/kernel.h> 29 #include <sys/socket.h> 30 #include <sys/systm.h> 31 #include <sys/malloc.h> 32 #include <sys/timeout.h> 33 #include <sys/device.h> 34 35 #include <machine/bus.h> 36 #include <machine/intr.h> 37 38 #include <net/if.h> 39 #include <net/if_media.h> 40 41 #include <netinet/in.h> 42 #include <netinet/if_ether.h> 43 44 #include <net80211/ieee80211_var.h> 45 #include <net80211/ieee80211_amrr.h> 46 #include <net80211/ieee80211_mira.h> 47 #include <net80211/ieee80211_radiotap.h> 48 49 #include <dev/ic/athnreg.h> 50 #include <dev/ic/athnvar.h> 51 52 #include <dev/pci/pcireg.h> 53 #include <dev/pci/pcivar.h> 54 #include <dev/pci/pcidevs.h> 55 56 #include <dev/cardbus/cardbusvar.h> 57 58 struct athn_cardbus_softc { 59 struct athn_softc sc_sc; 60 61 /* CardBus specific goo. */ 62 cardbus_devfunc_t sc_ct; 63 pcitag_t sc_tag; 64 void *sc_ih; 65 bus_space_tag_t sc_st; 66 bus_space_handle_t sc_sh; 67 bus_size_t sc_mapsize; 68 pcireg_t sc_bar_val; 69 int sc_intrline; 70 pci_chipset_tag_t sc_pc; 71 }; 72 73 int athn_cardbus_match(struct device *, void *, void *); 74 void athn_cardbus_attach(struct device *, struct device *, void *); 75 int athn_cardbus_detach(struct device *, int); 76 int athn_cardbus_enable(struct athn_softc *); 77 void athn_cardbus_disable(struct athn_softc *); 78 void athn_cardbus_power(struct athn_softc *, int); 79 void athn_cardbus_setup(struct athn_cardbus_softc *); 80 uint32_t athn_cardbus_read(struct athn_softc *, uint32_t); 81 void athn_cardbus_write(struct athn_softc *, uint32_t, uint32_t); 82 void athn_cardbus_write_barrier(struct athn_softc *); 83 84 struct cfattach athn_cardbus_ca = { 85 sizeof (struct athn_cardbus_softc), 86 athn_cardbus_match, 87 athn_cardbus_attach, 88 athn_cardbus_detach 89 }; 90 91 static const struct pci_matchid athn_cardbus_devices[] = { 92 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 }, 93 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 }, 94 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 }, 95 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 }, 96 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 }, 97 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 }, 98 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 }, 99 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 }, 100 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 }, 101 { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9300 } 102 }; 103 104 int 105 athn_cardbus_match(struct device *parent, void *match, void *aux) 106 { 107 return (cardbus_matchbyid(aux, athn_cardbus_devices, 108 nitems(athn_cardbus_devices))); 109 } 110 111 void 112 athn_cardbus_attach(struct device *parent, struct device *self, void *aux) 113 { 114 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self; 115 struct athn_softc *sc = &csc->sc_sc; 116 struct cardbus_attach_args *ca = aux; 117 cardbus_devfunc_t ct = ca->ca_ct; 118 bus_addr_t base; 119 int error; 120 121 sc->sc_dmat = ca->ca_dmat; 122 csc->sc_ct = ct; 123 csc->sc_tag = ca->ca_tag; 124 csc->sc_intrline = ca->ca_intrline; 125 csc->sc_pc = ca->ca_pc; 126 127 /* Power management hooks. */ 128 sc->sc_enable = athn_cardbus_enable; 129 sc->sc_disable = athn_cardbus_disable; 130 sc->sc_power = athn_cardbus_power; 131 132 sc->ops.read = athn_cardbus_read; 133 sc->ops.write = athn_cardbus_write; 134 sc->ops.write_barrier = athn_cardbus_write_barrier; 135 136 /* Map control/status registers. */ 137 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 138 PCI_MAPREG_TYPE_MEM, 0, &csc->sc_st, &csc->sc_sh, &base, 139 &csc->sc_mapsize); 140 if (error != 0) { 141 printf(": can't map mem space\n"); 142 return; 143 } 144 csc->sc_bar_val = base | PCI_MAPREG_TYPE_MEM; 145 146 /* Set up the PCI configuration registers. */ 147 athn_cardbus_setup(csc); 148 149 printf(": irq %d\n", csc->sc_intrline); 150 151 athn_attach(sc); 152 Cardbus_function_disable(ct); 153 } 154 155 int 156 athn_cardbus_detach(struct device *self, int flags) 157 { 158 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self; 159 struct athn_softc *sc = &csc->sc_sc; 160 cardbus_devfunc_t ct = csc->sc_ct; 161 cardbus_chipset_tag_t cc = ct->ct_cc; 162 cardbus_function_tag_t cf = ct->ct_cf; 163 164 athn_detach(sc); 165 166 /* Unhook the interrupt handler. */ 167 if (csc->sc_ih != NULL) 168 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 169 170 /* Release bus space and close window. */ 171 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_st, csc->sc_sh, 172 csc->sc_mapsize); 173 174 return (0); 175 } 176 177 int 178 athn_cardbus_enable(struct athn_softc *sc) 179 { 180 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 181 cardbus_devfunc_t ct = csc->sc_ct; 182 cardbus_chipset_tag_t cc = ct->ct_cc; 183 cardbus_function_tag_t cf = ct->ct_cf; 184 185 /* Power on the socket. */ 186 Cardbus_function_enable(ct); 187 188 /* Setup the PCI configuration registers. */ 189 athn_cardbus_setup(csc); 190 191 /* Map and establish the interrupt handler. */ 192 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 193 athn_intr, sc, sc->sc_dev.dv_xname); 194 if (csc->sc_ih == NULL) { 195 printf("%s: could not establish interrupt at %d\n", 196 sc->sc_dev.dv_xname, csc->sc_intrline); 197 Cardbus_function_disable(ct); 198 return (1); 199 } 200 return (0); 201 } 202 203 void 204 athn_cardbus_disable(struct athn_softc *sc) 205 { 206 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 207 cardbus_devfunc_t ct = csc->sc_ct; 208 cardbus_chipset_tag_t cc = ct->ct_cc; 209 cardbus_function_tag_t cf = ct->ct_cf; 210 211 /* Unhook the interrupt handler. */ 212 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 213 csc->sc_ih = NULL; 214 215 /* Power down the socket. */ 216 Cardbus_function_disable(ct); 217 } 218 219 void 220 athn_cardbus_power(struct athn_softc *sc, int why) 221 { 222 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 223 224 if (why == DVACT_RESUME) { 225 /* Restore the PCI configuration registers. */ 226 athn_cardbus_setup(csc); 227 } 228 } 229 230 void 231 athn_cardbus_setup(struct athn_cardbus_softc *csc) 232 { 233 cardbus_devfunc_t ct = csc->sc_ct; 234 cardbus_chipset_tag_t cc = ct->ct_cc; 235 pci_chipset_tag_t pc = csc->sc_pc; 236 cardbus_function_tag_t cf = ct->ct_cf; 237 pcireg_t reg; 238 239 /* Program the BAR. */ 240 pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG, 241 csc->sc_bar_val); 242 243 /* Make sure the right access type is on the cardbus bridge. */ 244 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 245 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 246 247 /* Enable the appropriate bits in the PCI CSR. */ 248 reg = pci_conf_read(pc, csc->sc_tag, 249 PCI_COMMAND_STATUS_REG); 250 reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 251 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, 252 reg); 253 254 /* 255 * Noone knows why this shit is necessary but there are claims that 256 * not doing this may cause very frequent PCI FATAL interrupts from 257 * the card: http://bugzilla.kernel.org/show_bug.cgi?id=13483 258 */ 259 reg = pci_conf_read(pc, csc->sc_tag, 0x40); 260 if (reg & 0xff00) 261 pci_conf_write(pc, csc->sc_tag, 0x40, reg & ~0xff00); 262 263 /* Change latency timer; default value yields poor results. */ 264 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 265 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 266 reg |= 168 << PCI_LATTIMER_SHIFT; 267 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 268 } 269 270 uint32_t 271 athn_cardbus_read(struct athn_softc *sc, uint32_t addr) 272 { 273 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 274 275 return (bus_space_read_4(csc->sc_st, csc->sc_sh, addr)); 276 } 277 278 void 279 athn_cardbus_write(struct athn_softc *sc, uint32_t addr, uint32_t val) 280 { 281 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 282 283 bus_space_write_4(csc->sc_st, csc->sc_sh, addr, val); 284 } 285 286 void 287 athn_cardbus_write_barrier(struct athn_softc *sc) 288 { 289 struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc; 290 291 bus_space_barrier(csc->sc_st, csc->sc_sh, 0, csc->sc_mapsize, 292 BUS_SPACE_BARRIER_WRITE); 293 } 294