1 /* $NetBSD: if_ath_cardbus.c,v 1.1 2003/10/14 17:47:03 ichiro Exp $ */ 2 /* 3 * Copyright (c) 2003 4 * Ichiro FUKUHARA <ichiro@ichiro.org>. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Ichiro FUKUHARA. 18 * 4. The name of the company nor the name of the author may be used to 19 * endorse or promote products derived from this software without specific 20 * prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR 26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * CardBus bus front-end for the AR5001 Wireless LAN 802.11a/b/g CardBus. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.1 2003/10/14 17:47:03 ichiro Exp $"); 40 41 #include "opt_inet.h" 42 #include "opt_ns.h" 43 #include "bpfilter.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/mbuf.h> 48 #include <sys/malloc.h> 49 #include <sys/kernel.h> 50 #include <sys/socket.h> 51 #include <sys/ioctl.h> 52 #include <sys/errno.h> 53 #include <sys/device.h> 54 55 #include <machine/endian.h> 56 57 #include <net/if.h> 58 #include <net/if_dl.h> 59 #include <net/if_media.h> 60 #include <net/if_ether.h> 61 62 #include <net80211/ieee80211_compat.h> 63 #include <net80211/ieee80211_var.h> 64 65 #if NBPFILTER > 0 66 #include <net/bpf.h> 67 #endif 68 69 #ifdef INET 70 #include <netinet/in.h> 71 #include <netinet/if_inarp.h> 72 #endif 73 74 #ifdef NS 75 #include <netns/ns.h> 76 #include <netns/ns_if.h> 77 #endif 78 79 #include <machine/bus.h> 80 #include <machine/intr.h> 81 82 #include <dev/mii/miivar.h> 83 #include <dev/mii/mii_bitbang.h> 84 85 #include <dev/ic/athcompat.h> 86 #include <dev/ic/athvar.h> 87 #include <../contrib/sys/dev/ic/athhal.h> 88 89 #include <dev/pci/pcivar.h> 90 #include <dev/pci/pcireg.h> 91 #include <dev/pci/pcidevs.h> 92 93 #include <dev/cardbus/cardbusvar.h> 94 #include <dev/cardbus/cardbusdevs.h> 95 96 /* 97 * PCI configuration space registers 98 */ 99 #define ATH_PCI_MMBA 0x10 /* memory mapped base */ 100 101 struct ath_cardbus_softc { 102 struct ath_softc sc_ath; 103 104 /* CardBus-specific goo. */ 105 void *sc_ih; /* interrupt handle */ 106 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */ 107 cardbustag_t sc_tag; /* our CardBus tag */ 108 bus_size_t sc_mapsize; /* the size of mapped bus space region */ 109 110 pcireg_t sc_bar_val; /* value of the BAR */ 111 112 int sc_intrline; /* interrupt line */ 113 }; 114 115 int ath_cardbus_match(struct device *, struct cfdata *, void *); 116 void ath_cardbus_attach(struct device *, struct device *, void *); 117 int ath_cardbus_detach(struct device *, int); 118 119 CFATTACH_DECL(ath_cardbus, sizeof(struct ath_cardbus_softc), 120 ath_cardbus_match, ath_cardbus_attach, ath_cardbus_detach, ath_activate); 121 122 void ath_cardbus_setup(struct ath_cardbus_softc *); 123 124 int ath_cardbus_enable(struct ath_softc *); 125 void ath_cardbus_disable(struct ath_softc *); 126 void ath_cardbus_power(struct ath_softc *, int); 127 128 int 129 ath_cardbus_match(struct device *parent, struct cfdata *match, 130 void *aux) 131 { 132 struct cardbus_attach_args *ca = aux; 133 const char* devname; 134 135 devname = ath_hal_probe(PCI_VENDOR(ca->ca_id), 136 PCI_PRODUCT(ca->ca_id)); 137 138 if (devname) 139 return (1); 140 141 return (0); 142 } 143 144 void 145 ath_cardbus_attach(struct device *parent, struct device *self, 146 void *aux) 147 { 148 struct ath_cardbus_softc *csc = (void *)self; 149 struct ath_softc *sc = &csc->sc_ath; 150 struct cardbus_attach_args *ca = aux; 151 cardbus_devfunc_t ct = ca->ca_ct; 152 bus_addr_t adr; 153 154 sc->sc_dmat = ca->ca_dmat; 155 csc->sc_ct = ct; 156 csc->sc_tag = ca->ca_tag; 157 158 /* 159 * Power management hooks. 160 */ 161 sc->sc_enable = ath_cardbus_enable; 162 sc->sc_disable = ath_cardbus_disable; 163 sc->sc_power = ath_cardbus_power; 164 165 /* 166 * Map the device. 167 */ 168 if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, CARDBUS_MAPREG_TYPE_MEM, 0, 169 &sc->sc_st, &sc->sc_sh, &adr, &csc->sc_mapsize) == 0) { 170 #if rbus 171 #else 172 (*ct->ct_cf->cardbus_mem_open)(cc, 0, adr, adr+csc->sc_mapsize); 173 #endif 174 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM; 175 } 176 177 else { 178 printf("%s: unable to map device registers\n", 179 sc->sc_dev.dv_xname); 180 return; 181 } 182 183 /* 184 * Set up the PCI configuration registers. 185 */ 186 ath_cardbus_setup(csc); 187 188 /* Remember which interrupt line. */ 189 csc->sc_intrline = ca->ca_intrline; 190 191 /* 192 * Finish off the attach. 193 */ 194 ath_attach(PCI_PRODUCT(ca->ca_id), sc); 195 196 /* 197 * Power down the socket. 198 */ 199 Cardbus_function_disable(csc->sc_ct); 200 } 201 202 int 203 ath_cardbus_detach(struct device *self, int flags) 204 { 205 struct ath_cardbus_softc *csc = (void *)self; 206 struct ath_softc *sc = &csc->sc_ath; 207 struct cardbus_devfunc *ct = csc->sc_ct; 208 int rv; 209 210 #if defined(DIAGNOSTIC) 211 if (ct == NULL) 212 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 213 #endif 214 215 rv = ath_detach(sc); 216 if (rv) 217 return (rv); 218 219 /* 220 * Unhook the interrupt handler. 221 */ 222 if (csc->sc_ih != NULL) 223 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 224 csc->sc_ih = NULL; 225 226 /* 227 * Release bus space and close window. 228 */ 229 Cardbus_mapreg_unmap(ct, ATH_PCI_MMBA, 230 sc->sc_st, sc->sc_sh, csc->sc_mapsize); 231 232 return (0); 233 } 234 235 int 236 ath_cardbus_enable(struct ath_softc *sc) 237 { 238 struct ath_cardbus_softc *csc = (void *) sc; 239 cardbus_devfunc_t ct = csc->sc_ct; 240 cardbus_chipset_tag_t cc = ct->ct_cc; 241 cardbus_function_tag_t cf = ct->ct_cf; 242 243 /* 244 * Power on the socket. 245 */ 246 Cardbus_function_enable(ct); 247 248 /* 249 * Set up the PCI configuration registers. 250 */ 251 ath_cardbus_setup(csc); 252 253 /* 254 * Map and establish the interrupt. 255 */ 256 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 257 ath_intr, sc); 258 if (csc->sc_ih == NULL) { 259 printf("%s: unable to establish interrupt at %d\n", 260 sc->sc_dev.dv_xname, csc->sc_intrline); 261 Cardbus_function_disable(csc->sc_ct); 262 return (1); 263 } 264 printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, 265 csc->sc_intrline); 266 267 return (0); 268 } 269 270 void 271 ath_cardbus_disable(struct ath_softc *sc) 272 { 273 struct ath_cardbus_softc *csc = (void *) sc; 274 cardbus_devfunc_t ct = csc->sc_ct; 275 cardbus_chipset_tag_t cc = ct->ct_cc; 276 cardbus_function_tag_t cf = ct->ct_cf; 277 278 /* Unhook the interrupt handler. */ 279 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 280 csc->sc_ih = NULL; 281 282 /* Power down the socket. */ 283 Cardbus_function_disable(ct); 284 } 285 286 void 287 ath_cardbus_power(struct ath_softc *sc, int why) 288 { 289 struct ath_cardbus_softc *csc = (void *) sc; 290 291 printf("%s: ath_cardbus_power\n", sc->sc_dev.dv_xname); 292 293 if (why == PWR_RESUME) { 294 /* 295 * Give the PCI configuration registers a kick 296 * in the head. 297 */ 298 #ifdef DIAGNOSTIC 299 if (ATH_IS_ENABLED(sc) == 0) 300 panic("ath_cardbus_power"); 301 #endif 302 ath_cardbus_setup(csc); 303 } 304 } 305 306 void 307 ath_cardbus_setup(struct ath_cardbus_softc *csc) 308 { 309 struct ath_softc *sc = &csc->sc_ath; 310 cardbus_devfunc_t ct = csc->sc_ct; 311 cardbus_chipset_tag_t cc = ct->ct_cc; 312 cardbus_function_tag_t cf = ct->ct_cf; 313 pcireg_t reg; 314 int pmreg; 315 316 if (cardbus_get_capability(cc, cf, csc->sc_tag, 317 PCI_CAP_PWRMGMT, &pmreg, 0)) { 318 reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4); 319 #if 1 /* XXX Probably not right for CardBus. */ 320 if (reg & 0x03) { 321 /* 322 * The card has lost all configuration data in 323 * this state, so punt. 324 */ 325 printf("%s: unable to wake up from power state D3\n", 326 sc->sc_dev.dv_xname); 327 return; 328 } 329 #endif 330 if (reg != 0) { 331 printf("%s: waking up from power state D%d\n", 332 sc->sc_dev.dv_xname, reg); 333 cardbus_conf_write(cc, cf, csc->sc_tag, 334 pmreg + 4, 0); 335 } 336 } 337 338 /* Make sure the right access type is on the CardBus bridge. */ 339 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 340 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 341 342 /* Program the BAR. */ 343 cardbus_conf_write(cc, cf, csc->sc_tag, ATH_PCI_MMBA, 344 csc->sc_bar_val); 345 346 /* Enable the appropriate bits in the PCI CSR. */ 347 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 348 CARDBUS_COMMAND_STATUS_REG); 349 reg |= CARDBUS_COMMAND_MASTER_ENABLE | CARDBUS_COMMAND_MEM_ENABLE; 350 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 351 reg); 352 353 /* 354 * Make sure the latency timer is set to some reasonable 355 * value. 356 */ 357 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG); 358 if (CARDBUS_LATTIMER(reg) < 0x20) { 359 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 360 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 361 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg); 362 } 363 } 364