1 /* $OpenBSD: if_atw_cardbus.c,v 1.24 2015/11/24 17:11:39 mpi 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_media.h> 54 55 #include <netinet/in.h> 56 #include <netinet/if_ether.h> 57 58 #include <net80211/ieee80211_radiotap.h> 59 #include <net80211/ieee80211_var.h> 60 61 #if NBPFILTER > 0 62 #include <net/bpf.h> 63 #endif 64 65 #include <machine/bus.h> 66 #include <machine/intr.h> 67 68 #include <dev/ic/atwreg.h> 69 #include <dev/ic/si4136reg.h> 70 #include <dev/ic/atwvar.h> 71 72 #include <dev/pci/pcivar.h> 73 #include <dev/pci/pcireg.h> 74 #include <dev/pci/pcidevs.h> 75 76 #include <dev/cardbus/cardbusvar.h> 77 78 /* 79 * PCI configuration space registers used by the ADM8211. 80 */ 81 #define ATW_PCI_IOBA 0x10 /* i/o mapped base */ 82 #define ATW_PCI_MMBA 0x14 /* memory mapped base */ 83 84 struct atw_cardbus_softc { 85 struct atw_softc sc_atw; /* real ADM8211 softc */ 86 87 /* CardBus-specific goo. */ 88 void *sc_ih; /* interrupt handle */ 89 cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */ 90 pcitag_t sc_tag; /* our CardBus tag */ 91 int sc_csr; /* CSR bits */ 92 bus_size_t sc_mapsize; /* the size of mapped bus space 93 region */ 94 95 int sc_cben; /* CardBus enables */ 96 int sc_bar_reg; /* which BAR to use */ 97 pcireg_t sc_bar_val; /* value of the BAR */ 98 99 int sc_intrline; /* interrupt line */ 100 pci_chipset_tag_t sc_pc; 101 }; 102 103 int atw_cardbus_match(struct device *, void *, void *); 104 void atw_cardbus_attach(struct device *, struct device *, void *); 105 int atw_cardbus_detach(struct device *, int); 106 107 struct cfattach atw_cardbus_ca = { 108 sizeof(struct atw_cardbus_softc), atw_cardbus_match, atw_cardbus_attach, 109 atw_cardbus_detach 110 }; 111 112 void atw_cardbus_setup(struct atw_cardbus_softc *); 113 114 int atw_cardbus_enable(struct atw_softc *); 115 void atw_cardbus_disable(struct atw_softc *); 116 void atw_cardbus_power(struct atw_softc *, int); 117 118 const struct pci_matchid atw_cardbus_devices[] = { 119 { PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_ADM8211 }, 120 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRSHPW796 }, 121 }; 122 123 int 124 atw_cardbus_match(struct device *parent, void *match, void *aux) 125 { 126 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 127 atw_cardbus_devices, nitems(atw_cardbus_devices))); 128 } 129 130 void 131 atw_cardbus_attach(struct device *parent, struct device *self, void *aux) 132 { 133 struct atw_cardbus_softc *csc = (void *)self; 134 struct atw_softc *sc = &csc->sc_atw; 135 struct cardbus_attach_args *ca = aux; 136 cardbus_devfunc_t ct = ca->ca_ct; 137 bus_addr_t adr; 138 139 sc->sc_dmat = ca->ca_dmat; 140 csc->sc_ct = ct; 141 csc->sc_tag = ca->ca_tag; 142 csc->sc_pc = ca->ca_pc; 143 144 /* 145 * Power management hooks. 146 */ 147 sc->sc_enable = atw_cardbus_enable; 148 sc->sc_disable = atw_cardbus_disable; 149 sc->sc_power = atw_cardbus_power; 150 151 /* Get revision info. */ 152 sc->sc_rev = PCI_REVISION(ca->ca_class); 153 154 #if 0 155 printf(": signature %08x\n%s", 156 pci_conf_read(ca->ca_pc, csc->sc_tag, 0x80), 157 sc->sc_dev.dv_xname); 158 #endif 159 160 /* 161 * Map the device. 162 */ 163 csc->sc_csr = PCI_COMMAND_MASTER_ENABLE; 164 if (Cardbus_mapreg_map(ct, ATW_PCI_MMBA, 165 PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &adr, 166 &csc->sc_mapsize) == 0) { 167 #if 0 168 printf(": atw_cardbus_attach mapped %d bytes mem space\n%s", 169 csc->sc_mapsize, sc->sc_dev.dv_xname); 170 #endif 171 csc->sc_cben = CARDBUS_MEM_ENABLE; 172 csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; 173 csc->sc_bar_reg = ATW_PCI_MMBA; 174 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; 175 } else if (Cardbus_mapreg_map(ct, ATW_PCI_IOBA, 176 PCI_MAPREG_TYPE_IO, 0, &sc->sc_st, &sc->sc_sh, &adr, 177 &csc->sc_mapsize) == 0) { 178 #if 0 179 printf(": atw_cardbus_attach mapped %d bytes I/O space\n%s", 180 csc->sc_mapsize, sc->sc_dev.dv_xname); 181 #endif 182 csc->sc_cben = CARDBUS_IO_ENABLE; 183 csc->sc_csr |= PCI_COMMAND_IO_ENABLE; 184 csc->sc_bar_reg = ATW_PCI_IOBA; 185 csc->sc_bar_val = adr | PCI_MAPREG_TYPE_IO; 186 } else { 187 printf(": unable to map device registers\n"); 188 return; 189 } 190 191 /* 192 * Bring the chip out of powersave mode and initialize the 193 * configuration registers. 194 */ 195 atw_cardbus_setup(csc); 196 197 /* Remember which interrupt line. */ 198 csc->sc_intrline = ca->ca_intrline; 199 200 printf(": revision %d.%d: irq %d\n", 201 (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf, csc->sc_intrline); 202 #if 0 203 /* 204 * The CardBus cards will make it to store-and-forward mode as 205 * soon as you put them under any kind of load, so just start 206 * out there. 207 */ 208 sc->sc_txthresh = 3; /* TBD name constant */ 209 #endif 210 211 /* 212 * Finish off the attach. 213 */ 214 atw_attach(sc); 215 216 ATW_WRITE(sc, ATW_FER, ATW_FER_INTR); 217 218 /* 219 * Power down the socket. 220 */ 221 Cardbus_function_disable(csc->sc_ct); 222 } 223 224 int 225 atw_cardbus_detach(struct device *self, int flags) 226 { 227 struct atw_cardbus_softc *csc = (void *)self; 228 struct atw_softc *sc = &csc->sc_atw; 229 struct cardbus_devfunc *ct = csc->sc_ct; 230 int rv; 231 232 #if defined(DIAGNOSTIC) 233 if (ct == NULL) 234 panic("%s: data structure lacks", sc->sc_dev.dv_xname); 235 #endif 236 237 rv = atw_detach(sc); 238 if (rv) 239 return (rv); 240 241 /* 242 * Unhook the interrupt handler. 243 */ 244 if (csc->sc_ih != NULL) 245 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih); 246 247 /* 248 * Release bus space and close window. 249 */ 250 if (csc->sc_bar_reg != 0) 251 Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, 252 sc->sc_st, sc->sc_sh, csc->sc_mapsize); 253 254 return (0); 255 } 256 257 int 258 atw_cardbus_enable(struct atw_softc *sc) 259 { 260 struct atw_cardbus_softc *csc = (void *) sc; 261 cardbus_devfunc_t ct = csc->sc_ct; 262 cardbus_chipset_tag_t cc = ct->ct_cc; 263 cardbus_function_tag_t cf = ct->ct_cf; 264 265 /* 266 * Power on the socket. 267 */ 268 Cardbus_function_enable(ct); 269 270 /* 271 * Set up the PCI configuration registers. 272 */ 273 atw_cardbus_setup(csc); 274 275 /* 276 * Map and establish the interrupt. 277 */ 278 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 279 atw_intr, sc, sc->sc_dev.dv_xname); 280 if (csc->sc_ih == NULL) { 281 printf("%s: unable to establish interrupt at %d\n", 282 sc->sc_dev.dv_xname, csc->sc_intrline); 283 Cardbus_function_disable(csc->sc_ct); 284 return (1); 285 } 286 287 return (0); 288 } 289 290 void 291 atw_cardbus_disable(struct atw_softc *sc) 292 { 293 struct atw_cardbus_softc *csc = (void *) sc; 294 cardbus_devfunc_t ct = csc->sc_ct; 295 cardbus_chipset_tag_t cc = ct->ct_cc; 296 cardbus_function_tag_t cf = ct->ct_cf; 297 298 /* Unhook the interrupt handler. */ 299 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 300 csc->sc_ih = NULL; 301 302 /* Power down the socket. */ 303 Cardbus_function_disable(ct); 304 } 305 306 void 307 atw_cardbus_power(struct atw_softc *sc, int why) 308 { 309 if (why == DVACT_RESUME) 310 atw_enable(sc); 311 } 312 313 void 314 atw_cardbus_setup(struct atw_cardbus_softc *csc) 315 { 316 #ifdef notyet 317 struct atw_softc *sc = &csc->sc_atw; 318 #endif 319 cardbus_devfunc_t ct = csc->sc_ct; 320 cardbus_chipset_tag_t cc = ct->ct_cc; 321 pci_chipset_tag_t pc = csc->sc_pc; 322 pcireg_t reg; 323 324 #ifdef notyet 325 (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, 326 PCI_PWR_D0); 327 #endif 328 329 /* Program the BAR. */ 330 pci_conf_write(pc, csc->sc_tag, csc->sc_bar_reg, 331 csc->sc_bar_val); 332 333 /* Make sure the right access type is on the CardBus bridge. */ 334 (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); 335 (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 336 337 /* Enable the appropriate bits in the PCI CSR. */ 338 reg = pci_conf_read(pc, csc->sc_tag, 339 PCI_COMMAND_STATUS_REG); 340 reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); 341 reg |= csc->sc_csr; 342 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, 343 reg); 344 345 /* 346 * Make sure the latency timer is set to some reasonable 347 * value. 348 */ 349 reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG); 350 if (PCI_LATTIMER(reg) < 0x20) { 351 reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 352 reg |= (0x20 << PCI_LATTIMER_SHIFT); 353 pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg); 354 } 355 } 356