1 /* $OpenBSD: if_bwi_cardbus.c,v 1.15 2013/12/06 21:03:02 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> 5 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Cardbus front-end for the Broadcom AirForce 22 */ 23 24 #include "bpfilter.h" 25 26 #include <sys/param.h> 27 #include <sys/mbuf.h> 28 #include <sys/socket.h> 29 #include <sys/systm.h> 30 #include <sys/timeout.h> 31 32 #include <net/if.h> 33 #include <net/if_media.h> 34 35 #include <netinet/in.h> 36 #include <netinet/if_ether.h> 37 38 #include <net80211/ieee80211_var.h> 39 #include <net80211/ieee80211_amrr.h> 40 #include <net80211/ieee80211_radiotap.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcidevs.h> 45 46 #include <dev/cardbus/cardbusvar.h> 47 48 #include <dev/ic/bwivar.h> 49 50 struct bwi_cardbus_softc { 51 struct bwi_softc csc_bwi; 52 53 /* cardbus specific goo */ 54 cardbus_devfunc_t csc_ct; 55 pcitag_t csc_tag; 56 void *csc_ih; 57 58 bus_size_t csc_mapsize; 59 pcireg_t csc_bar_val; 60 int csc_intrline; 61 pci_chipset_tag_t csc_pc; 62 }; 63 64 int bwi_cardbus_match(struct device *, void *, void*); 65 void bwi_cardbus_attach(struct device *, struct device *, void *); 66 int bwi_cardbus_detach(struct device *, int); 67 void bwi_cardbus_setup(struct bwi_cardbus_softc *); 68 int bwi_cardbus_enable(struct bwi_softc *); 69 void bwi_cardbus_disable(struct bwi_softc *); 70 void bwi_cardbus_conf_write(void *, uint32_t, uint32_t); 71 uint32_t bwi_cardbus_conf_read(void *, uint32_t); 72 73 struct cfattach bwi_cardbus_ca = { 74 sizeof (struct bwi_cardbus_softc), bwi_cardbus_match, 75 bwi_cardbus_attach, bwi_cardbus_detach 76 }; 77 78 static const struct pci_matchid bwi_cardbus_devices[] = { 79 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 }, 80 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 }, 81 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 }, 82 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 }, 83 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 }, 84 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 }, 85 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 }, 86 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG } 87 }; 88 89 int 90 bwi_cardbus_match(struct device *parent, void *match, void *aux) 91 { 92 return (cardbus_matchbyid(aux, bwi_cardbus_devices, 93 sizeof (bwi_cardbus_devices) / sizeof (bwi_cardbus_devices[0]))); 94 } 95 96 void 97 bwi_cardbus_attach(struct device *parent, struct device *self, void *aux) 98 { 99 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 100 struct cardbus_attach_args *ca = aux; 101 struct bwi_softc *sc = &csc->csc_bwi; 102 cardbus_devfunc_t ct = ca->ca_ct; 103 pcireg_t reg; 104 bus_addr_t base; 105 int error; 106 107 sc->sc_dmat = ca->ca_dmat; 108 csc->csc_ct = ct; 109 csc->csc_tag = ca->ca_tag; 110 csc->csc_intrline = ca->ca_intrline; 111 csc->csc_pc = ca->ca_pc; 112 113 /* power management hooks */ 114 sc->sc_enable = bwi_cardbus_enable; 115 sc->sc_disable = bwi_cardbus_disable; 116 //sc->sc_power = bwi_cardbus_power; 117 118 /* map control/status registers */ 119 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 120 PCI_MAPREG_TYPE_MEM, 0, &sc->sc_mem_bt, 121 &sc->sc_mem_bh, &base, &csc->csc_mapsize); 122 if (error != 0) { 123 printf(": can't map mem space\n"); 124 return; 125 } 126 csc->csc_bar_val = base | PCI_MAPREG_TYPE_MEM; 127 128 /* set up the PCI configuration registers */ 129 bwi_cardbus_setup(csc); 130 131 printf(": irq %d", csc->csc_intrline); 132 133 /* we need to access Cardbus config space from the driver */ 134 sc->sc_conf_read = bwi_cardbus_conf_read; 135 sc->sc_conf_write = bwi_cardbus_conf_write; 136 137 reg = (sc->sc_conf_read)(sc, PCI_SUBSYS_ID_REG); 138 139 sc->sc_pci_revid = PCI_REVISION(ca->ca_class); 140 sc->sc_pci_did = PCI_PRODUCT(ca->ca_id); 141 sc->sc_pci_subvid = PCI_VENDOR(reg); 142 sc->sc_pci_subdid = PCI_PRODUCT(reg); 143 144 error = bwi_attach(sc); 145 if (error != 0) 146 bwi_cardbus_detach(&sc->sc_dev, 0); 147 148 Cardbus_function_disable(ct); 149 } 150 151 int 152 bwi_cardbus_detach(struct device *self, int flags) 153 { 154 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 155 struct bwi_softc *sc = &csc->csc_bwi; 156 cardbus_devfunc_t ct = csc->csc_ct; 157 cardbus_chipset_tag_t cc = ct->ct_cc; 158 cardbus_function_tag_t cf = ct->ct_cf; 159 int error; 160 161 error = bwi_detach(sc); 162 if (error != 0) 163 return (error); 164 165 /* unhook the interrupt handler */ 166 if (csc->csc_ih != NULL) { 167 cardbus_intr_disestablish(cc, cf, csc->csc_ih); 168 csc->csc_ih = NULL; 169 } 170 171 /* release bus space and close window */ 172 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem_bt, 173 sc->sc_mem_bh, csc->csc_mapsize); 174 175 return (0); 176 } 177 178 void 179 bwi_cardbus_setup(struct bwi_cardbus_softc *csc) 180 { 181 cardbus_devfunc_t ct = csc->csc_ct; 182 cardbus_chipset_tag_t cc = ct->ct_cc; 183 pci_chipset_tag_t pc = csc->csc_pc; 184 cardbus_function_tag_t cf = ct->ct_cf; 185 pcireg_t reg; 186 187 /* program the BAR */ 188 pci_conf_write(pc, csc->csc_tag, CARDBUS_BASE0_REG, 189 csc->csc_bar_val); 190 191 /* make sure the right access type is on the cardbus bridge */ 192 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 193 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 194 195 /* enable the appropriate bits in the PCI CSR */ 196 reg = pci_conf_read(pc, csc->csc_tag, 197 PCI_COMMAND_STATUS_REG); 198 reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 199 pci_conf_write(pc, csc->csc_tag, PCI_COMMAND_STATUS_REG, 200 reg); 201 } 202 203 int 204 bwi_cardbus_enable(struct bwi_softc *sc) 205 { 206 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc; 207 cardbus_devfunc_t ct = csc->csc_ct; 208 cardbus_chipset_tag_t cc = ct->ct_cc; 209 cardbus_function_tag_t cf = ct->ct_cf; 210 211 /* power on the socket */ 212 Cardbus_function_enable(ct); 213 214 /* setup the PCI configuration registers */ 215 bwi_cardbus_setup(csc); 216 217 /* map and establish the interrupt handler */ 218 csc->csc_ih = cardbus_intr_establish(cc, cf, csc->csc_intrline, IPL_NET, 219 bwi_intr, sc, sc->sc_dev.dv_xname); 220 if (csc->csc_ih == NULL) { 221 printf("%s: could not establish interrupt at %d\n", 222 sc->sc_dev.dv_xname, csc->csc_intrline); 223 Cardbus_function_disable(ct); 224 return (1); 225 } 226 227 return (0); 228 } 229 230 void 231 bwi_cardbus_disable(struct bwi_softc *sc) 232 { 233 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc; 234 cardbus_devfunc_t ct = csc->csc_ct; 235 cardbus_chipset_tag_t cc = ct->ct_cc; 236 cardbus_function_tag_t cf = ct->ct_cf; 237 238 /* unhook the interrupt handler */ 239 cardbus_intr_disestablish(cc, cf, csc->csc_ih); 240 csc->csc_ih = NULL; 241 242 /* power down the socket */ 243 Cardbus_function_disable(ct); 244 } 245 246 void 247 bwi_cardbus_conf_write(void *self, uint32_t reg, uint32_t val) 248 { 249 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 250 pci_chipset_tag_t pc = csc->csc_pc; 251 252 pci_conf_write(pc, csc->csc_tag, reg, val); 253 } 254 255 uint32_t 256 bwi_cardbus_conf_read(void *self, uint32_t reg) 257 { 258 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 259 pci_chipset_tag_t pc = csc->csc_pc; 260 261 return (pci_conf_read(pc, csc->csc_tag, reg)); 262 } 263