1 /* $NetBSD: if_ath_cardbus.c,v 1.7 2005/06/22 06:15:37 dyoung 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.7 2005/06/22 06:15:37 dyoung 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_netbsd.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/ath_netbsd.h> 86 #include <dev/ic/athvar.h> 87 #include <contrib/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/pci/pcidevs.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 printf("\n"); 159 160 /* 161 * Power management hooks. 162 */ 163 sc->sc_enable = ath_cardbus_enable; 164 sc->sc_disable = ath_cardbus_disable; 165 sc->sc_power = ath_cardbus_power; 166 167 /* 168 * Map the device. 169 */ 170 if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, CARDBUS_MAPREG_TYPE_MEM, 0, 171 &sc->sc_st, &sc->sc_sh, &adr, &csc->sc_mapsize) == 0) { 172 #if rbus 173 #else 174 (*ct->ct_cf->cardbus_mem_open)(cc, 0, adr, adr+csc->sc_mapsize); 175 #endif 176 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM; 177 } 178 179 else { 180 printf("%s: unable to map device registers\n", 181 sc->sc_dev.dv_xname); 182 return; 183 } 184 185 /* 186 * Set up the PCI configuration registers. 187 */ 188 ath_cardbus_setup(csc); 189 190 /* Remember which interrupt line. */ 191 csc->sc_intrline = ca->ca_intrline; 192 193 /* 194 * Finish off the attach. 195 */ 196 ath_attach(PCI_PRODUCT(ca->ca_id), sc); 197 198 /* 199 * Power down the socket. 200 */ 201 Cardbus_function_disable(csc->sc_ct); 202 } 203 204 int 205 ath_cardbus_detach(struct device *self, int flags) 206 { 207 struct ath_cardbus_softc *csc = (void *)self; 208 struct ath_softc *sc = &csc->sc_ath; 209 struct cardbus_devfunc *ct = csc->sc_ct; 210 int rv; 211 212 #if defined(DIAGNOSTIC) 213 if (ct == NULL) 214 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 215 #endif 216 217 rv = ath_detach(sc); 218 if (rv) 219 return (rv); 220 221 /* 222 * Unhook the interrupt handler. 223 */ 224 if (csc->sc_ih != NULL) 225 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 226 csc->sc_ih = NULL; 227 228 /* 229 * Release bus space and close window. 230 */ 231 Cardbus_mapreg_unmap(ct, ATH_PCI_MMBA, 232 sc->sc_st, sc->sc_sh, csc->sc_mapsize); 233 234 return (0); 235 } 236 237 int 238 ath_cardbus_enable(struct ath_softc *sc) 239 { 240 struct ath_cardbus_softc *csc = (void *) sc; 241 cardbus_devfunc_t ct = csc->sc_ct; 242 cardbus_chipset_tag_t cc = ct->ct_cc; 243 cardbus_function_tag_t cf = ct->ct_cf; 244 245 /* 246 * Power on the socket. 247 */ 248 Cardbus_function_enable(ct); 249 250 /* 251 * Set up the PCI configuration registers. 252 */ 253 ath_cardbus_setup(csc); 254 255 /* 256 * Map and establish the interrupt. 257 */ 258 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 259 ath_intr, sc); 260 if (csc->sc_ih == NULL) { 261 printf("%s: unable to establish interrupt at %d\n", 262 sc->sc_dev.dv_xname, csc->sc_intrline); 263 Cardbus_function_disable(csc->sc_ct); 264 return (1); 265 } 266 printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, 267 csc->sc_intrline); 268 269 return (0); 270 } 271 272 void 273 ath_cardbus_disable(struct ath_softc *sc) 274 { 275 struct ath_cardbus_softc *csc = (void *) sc; 276 cardbus_devfunc_t ct = csc->sc_ct; 277 cardbus_chipset_tag_t cc = ct->ct_cc; 278 cardbus_function_tag_t cf = ct->ct_cf; 279 280 /* Unhook the interrupt handler. */ 281 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 282 csc->sc_ih = NULL; 283 284 /* Power down the socket. */ 285 Cardbus_function_disable(ct); 286 } 287 288 void 289 ath_cardbus_power(struct ath_softc *sc, int why) 290 { 291 struct ath_cardbus_softc *csc = (void *) sc; 292 293 printf("%s: ath_cardbus_power\n", sc->sc_dev.dv_xname); 294 295 if (why == PWR_RESUME) { 296 /* 297 * Give the PCI configuration registers a kick 298 * in the head. 299 */ 300 #ifdef DIAGNOSTIC 301 if (ATH_IS_ENABLED(sc) == 0) 302 panic("ath_cardbus_power"); 303 #endif 304 ath_cardbus_setup(csc); 305 } 306 } 307 308 void 309 ath_cardbus_setup(struct ath_cardbus_softc *csc) 310 { 311 struct ath_softc *sc = &csc->sc_ath; 312 cardbus_devfunc_t ct = csc->sc_ct; 313 cardbus_chipset_tag_t cc = ct->ct_cc; 314 cardbus_function_tag_t cf = ct->ct_cf; 315 pcireg_t reg; 316 317 (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, 318 PCI_PWR_D0); 319 320 /* Program the BAR. */ 321 cardbus_conf_write(cc, cf, csc->sc_tag, ATH_PCI_MMBA, 322 csc->sc_bar_val); 323 324 /* Make sure the right access type is on the CardBus bridge. */ 325 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 326 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 327 328 /* Enable the appropriate bits in the PCI CSR. */ 329 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 330 CARDBUS_COMMAND_STATUS_REG); 331 reg |= CARDBUS_COMMAND_MASTER_ENABLE | CARDBUS_COMMAND_MEM_ENABLE; 332 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 333 reg); 334 335 /* 336 * Make sure the latency timer is set to some reasonable 337 * value. 338 */ 339 reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG); 340 if (CARDBUS_LATTIMER(reg) < 0x20) { 341 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 342 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 343 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg); 344 } 345 } 346