1 /* $OpenBSD: if_atw_cardbus.c,v 1.23 2015/03/14 03:38:47 jsg Exp $ */ 2 /* $NetBSD: if_atw_cardbus.c,v 1.9 2004/07/23 07:07:55 dyoung Exp $ */ 3 4 /*- 5 * Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. This code was adapted for the ADMtek ADM8211 11 * by David Young. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * CardBus bus front-end for the ADMtek ADM8211 802.11 MAC/BBP driver. 37 */ 38 39 #include "bpfilter.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/mbuf.h> 44 #include <sys/malloc.h> 45 #include <sys/kernel.h> 46 #include <sys/socket.h> 47 #include <sys/ioctl.h> 48 #include <sys/errno.h> 49 #include <sys/device.h> 50 #include <sys/endian.h> 51 52 #include <net/if.h> 53 #include <net/if_dl.h> 54 #include <net/if_media.h> 55 56 #include <netinet/in.h> 57 #include <netinet/if_ether.h> 58 59 #include <net80211/ieee80211_radiotap.h> 60 #include <net80211/ieee80211_var.h> 61 62 #if NBPFILTER > 0 63 #include <net/bpf.h> 64 #endif 65 66 #include <machine/bus.h> 67 #include <machine/intr.h> 68 69 #include <dev/ic/atwreg.h> 70 #include <dev/ic/si4136reg.h> 71 #include <dev/ic/atwvar.h> 72 73 #include <dev/pci/pcivar.h> 74 #include <dev/pci/pcireg.h> 75 #include <dev/pci/pcidevs.h> 76 77 #include <dev/cardbus/cardbusvar.h> 78 79 /* 80 * PCI configuration space registers used by the ADM8211. 81 */ 82 #define ATW_PCI_IOBA 0x10 /* i/o mapped base */ 83 #define ATW_PCI_MMBA 0x14 /* memory mapped base */ 84 85 struct atw_cardbus_softc { 86 struct atw_softc sc_atw; /* real ADM8211 softc */ 87 88 /* CardBus-specific goo. */ 89 void *sc_ih; /* interrupt handle */ 90 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */ 91 pcitag_t sc_tag; /* our CardBus tag */ 92 int sc_csr; /* CSR bits */ 93 bus_size_t sc_mapsize; /* the size of mapped bus space 94 region */ 95 96 int sc_cben; /* CardBus enables */ 97 int sc_bar_reg; /* which BAR to use */ 98 pcireg_t sc_bar_val; /* value of the BAR */ 99 100 int sc_intrline; /* interrupt line */ 101 pci_chipset_tag_t sc_pc; 102 }; 103 104 int atw_cardbus_match(struct device *, void *, void *); 105 void atw_cardbus_attach(struct device *, struct device *, void *); 106 int atw_cardbus_detach(struct device *, int); 107 108 struct cfattach atw_cardbus_ca = { 109 sizeof(struct atw_cardbus_softc), atw_cardbus_match, atw_cardbus_attach, 110 atw_cardbus_detach 111 }; 112 113 void atw_cardbus_setup(struct atw_cardbus_softc *); 114 115 int atw_cardbus_enable(struct atw_softc *); 116 void atw_cardbus_disable(struct atw_softc *); 117 void atw_cardbus_power(struct atw_softc *, int); 118 119 const struct pci_matchid atw_cardbus_devices[] = { 120 { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211 }, 121 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRSHPW796 }, 122 }; 123 124 int 125 atw_cardbus_match(struct device *parent, void *match, void *aux) 126 { 127 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 128 atw_cardbus_devices, nitems(atw_cardbus_devices))); 129 } 130 131 void 132 atw_cardbus_attach(struct device *parent, struct device *self, void *aux) 133 { 134 struct atw_cardbus_softc *csc = (void *)self; 135 struct atw_softc *sc = &csc->sc_atw; 136 struct cardbus_attach_args *ca = aux; 137 cardbus_devfunc_t ct = ca->ca_ct; 138 bus_addr_t adr; 139 140 sc->sc_dmat = ca->ca_dmat; 141 csc->sc_ct = ct; 142 csc->sc_tag = ca->ca_tag; 143 csc->sc_pc = ca->ca_pc; 144 145 /* 146 * Power management hooks. 147 */ 148 sc->sc_enable = atw_cardbus_enable; 149 sc->sc_disable = atw_cardbus_disable; 150 sc->sc_power = atw_cardbus_power; 151 152 /* Get revision info. */ 153 sc->sc_rev = PCI_REVISION(ca->ca_class); 154 155 #if 0 156 printf(": signature %08x\n%s", 157 pci_conf_read(ca->ca_pc, csc->sc_tag, 0x80), 158 sc->sc_dev.dv_xname); 159 #endif 160 161 /* 162 * Map the device. 163 */ 164 csc->sc_csr = PCI_COMMAND_MASTER_ENABLE; 165 if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA, 166 PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr, 167 &csc->sc_mapsize) == 0) { 168 #if 0 169 printf(": atw_cardbus_attach mapped %d bytes mem space\n%s", 170 csc->sc_mapsize, sc->sc_dev.dv_xname); 171 #endif 172 csc->sc_cben = CARDBUS_MEM_ENABLE; 173 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; 174 csc->sc_bar_reg = ATW_PCI_MMBA; 175 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; 176 } else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA, 177 PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr, 178 &csc->sc_mapsize) == 0) { 179 #if 0 180 printf(": atw_cardbus_attach mapped %d bytes I/O space\n%s", 181 csc->sc_mapsize, sc->sc_dev.dv_xname); 182 #endif 183 csc->sc_cben = CARDBUS_IO_ENABLE; 184 csc->sc_csr |= PCI_COMMAND_IO_ENABLE; 185 csc->sc_bar_reg = ATW_PCI_IOBA; 186 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO; 187 } else { 188 printf(": unable to map device registers\n"); 189 return; 190 } 191 192 /* 193 * Bring the chip out of powersave mode and initialize the 194 * configuration registers. 195 */ 196 atw_cardbus_setup(csc); 197 198 /* Remember which interrupt line. */ 199 csc->sc_intrline = ca->ca_intrline; 200 201 printf(": revision %d.%d: irq %d\n", 202 (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf, csc->sc_intrline); 203 #if 0 204 /* 205 * The CardBus cards will make it to store-and-forward mode as 206 * soon as you put them under any kind of load, so just start 207 * out there. 208 */ 209 sc->sc_txthresh = 3; /* TBD name constant */ 210 #endif 211 212 /* 213 * Finish off the attach. 214 */ 215 atw_attach(sc); 216 217 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR); 218 219 /* 220 * Power down the socket. 221 */ 222 Cardbus_function_disable(csc->sc_ct); 223 } 224 225 int 226 atw_cardbus_detach(struct device *self, int flags) 227 { 228 struct atw_cardbus_softc *csc = (void *)self; 229 struct atw_softc *sc = &csc->sc_atw; 230 struct cardbus_devfunc *ct = csc->sc_ct; 231 int rv; 232 233 #if defined(DIAGNOSTIC) 234 if (ct == NULL) 235 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 236 #endif 237 238 rv = atw_detach(sc); 239 if (rv) 240 return (rv); 241 242 /* 243 * Unhook the interrupt handler. 244 */ 245 if (csc->sc_ih != NULL) 246 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 247 248 /* 249 * Release bus space and close window. 250 */ 251 if (csc->sc_bar_reg != 0) 252 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, 253 sc->sc_st, sc->sc_sh, csc->sc_mapsize); 254 255 return (0); 256 } 257 258 int 259 atw_cardbus_enable(struct atw_softc *sc) 260 { 261 struct atw_cardbus_softc *csc = (void *) sc; 262 cardbus_devfunc_t ct = csc->sc_ct; 263 cardbus_chipset_tag_t cc = ct->ct_cc; 264 cardbus_function_tag_t cf = ct->ct_cf; 265 266 /* 267 * Power on the socket. 268 */ 269 Cardbus_function_enable(ct); 270 271 /* 272 * Set up the PCI configuration registers. 273 */ 274 atw_cardbus_setup(csc); 275 276 /* 277 * Map and establish the interrupt. 278 */ 279 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 280 atw_intr, sc, sc->sc_dev.dv_xname); 281 if (csc->sc_ih == NULL) { 282 printf("%s: unable to establish interrupt at %d\n", 283 sc->sc_dev.dv_xname, csc->sc_intrline); 284 Cardbus_function_disable(csc->sc_ct); 285 return (1); 286 } 287 288 return (0); 289 } 290 291 void 292 atw_cardbus_disable(struct atw_softc *sc) 293 { 294 struct atw_cardbus_softc *csc = (void *) sc; 295 cardbus_devfunc_t ct = csc->sc_ct; 296 cardbus_chipset_tag_t cc = ct->ct_cc; 297 cardbus_function_tag_t cf = ct->ct_cf; 298 299 /* Unhook the interrupt handler. */ 300 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 301 csc->sc_ih = NULL; 302 303 /* Power down the socket. */ 304 Cardbus_function_disable(ct); 305 } 306 307 void 308 atw_cardbus_power(struct atw_softc *sc, int why) 309 { 310 if (why == DVACT_RESUME) 311 atw_enable(sc); 312 } 313 314 void 315 atw_cardbus_setup(struct atw_cardbus_softc *csc) 316 { 317 #ifdef notyet 318 struct atw_softc *sc = &csc->sc_atw; 319 #endif 320 cardbus_devfunc_t ct = csc->sc_ct; 321 cardbus_chipset_tag_t cc = ct->ct_cc; 322 pci_chipset_tag_t pc = csc->sc_pc; 323 pcireg_t reg; 324 325 #ifdef notyet 326 (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, 327 PCI_PWR_D0); 328 #endif 329 330 /* Program the BAR. */ 331 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg, 332 csc->sc_bar_val); 333 334 /* Make sure the right access type is on the CardBus bridge. */ 335 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); 336 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 337 338 /* Enable the appropriate bits in the PCI CSR. */ 339 reg = pci_conf_read(pc, csc->sc_tag, 340 PCI_COMMAND_STATUS_REG); 341 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); 342 reg |= csc->sc_csr; 343 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, 344 reg); 345 346 /* 347 * Make sure the latency timer is set to some reasonable 348 * value. 349 */ 350 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 351 if (PCI_LATTIMER(reg) < 0x20) { 352 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 353 reg |= (0x20 << PCI_LATTIMER_SHIFT); 354 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 355 } 356 } 357