1 /* $OpenBSD: if_bwi_pci.c,v 1.14 2013/12/06 21:03:04 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * PCI front-end for the Broadcom AirForce 21 */ 22 23 #include "bpfilter.h" 24 25 #include <sys/param.h> 26 #include <sys/sockio.h> 27 #include <sys/mbuf.h> 28 #include <sys/kernel.h> 29 #include <sys/socket.h> 30 #include <sys/systm.h> 31 #include <sys/malloc.h> 32 #include <sys/timeout.h> 33 #include <sys/device.h> 34 35 #include <machine/bus.h> 36 #include <machine/intr.h> 37 38 #include <net/if.h> 39 #include <net/if_dl.h> 40 #include <net/if_media.h> 41 42 #include <netinet/in.h> 43 #include <netinet/if_ether.h> 44 45 #include <net80211/ieee80211_var.h> 46 #include <net80211/ieee80211_amrr.h> 47 #include <net80211/ieee80211_radiotap.h> 48 49 #include <dev/ic/bwivar.h> 50 51 #include <dev/pci/pcireg.h> 52 #include <dev/pci/pcivar.h> 53 #include <dev/pci/pcidevs.h> 54 55 /* Base Address Register */ 56 #define BWI_PCI_BAR0 0x10 57 58 int bwi_pci_match(struct device *, void *, void *); 59 void bwi_pci_attach(struct device *, struct device *, void *); 60 int bwi_pci_detach(struct device *, int); 61 void bwi_pci_conf_write(void *, uint32_t, uint32_t); 62 uint32_t bwi_pci_conf_read(void *, uint32_t); 63 int bwi_pci_activate(struct device *, int); 64 void bwi_pci_wakeup(struct bwi_softc *); 65 66 struct bwi_pci_softc { 67 struct bwi_softc psc_bwi; 68 69 pci_chipset_tag_t psc_pc; 70 pcitag_t psc_pcitag; 71 void *psc_ih; 72 73 bus_size_t psc_mapsize; 74 }; 75 76 struct cfattach bwi_pci_ca = { 77 sizeof(struct bwi_pci_softc), bwi_pci_match, bwi_pci_attach, 78 bwi_pci_detach, bwi_pci_activate 79 }; 80 81 const struct pci_matchid bwi_pci_devices[] = { 82 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 }, 83 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 }, 84 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 }, 85 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 }, 86 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 }, 87 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4311 }, 88 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4312 }, 89 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 }, 90 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 }, 91 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG } 92 }; 93 94 int 95 bwi_pci_match(struct device *parent, void *match, void *aux) 96 { 97 struct pci_attach_args *pa = aux; 98 99 /* 100 * The second revision of the BCM4311/BCM4312 101 * chips require v4 firmware. 102 */ 103 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROADCOM && 104 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4311 || 105 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4312) && 106 PCI_REVISION(pa->pa_class) == 0x02) 107 return (0); 108 109 return (pci_matchbyid((struct pci_attach_args *)aux, bwi_pci_devices, 110 sizeof(bwi_pci_devices) / sizeof(bwi_pci_devices[0]))); 111 } 112 113 void 114 bwi_pci_attach(struct device *parent, struct device *self, void *aux) 115 { 116 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 117 struct pci_attach_args *pa = aux; 118 struct bwi_softc *sc = &psc->psc_bwi; 119 const char *intrstr = NULL; 120 pci_intr_handle_t ih; 121 pcireg_t memtype, reg; 122 123 sc->sc_dmat = pa->pa_dmat; 124 psc->psc_pc = pa->pa_pc; 125 psc->psc_pcitag = pa->pa_tag; 126 127 /* map control / status registers */ 128 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BWI_PCI_BAR0); 129 if (pci_mapreg_map(pa, BWI_PCI_BAR0, memtype, 0, &sc->sc_mem_bt, 130 &sc->sc_mem_bh, NULL, &psc->psc_mapsize, 0)) { 131 printf(": can't map mem space\n"); 132 return; 133 } 134 135 /* map interrupt */ 136 if (pci_intr_map(pa, &ih) != 0) { 137 printf(": can't map interrupt\n"); 138 return; 139 } 140 141 /* establish interrupt */ 142 intrstr = pci_intr_string(psc->psc_pc, ih); 143 psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_NET, bwi_intr, sc, 144 sc->sc_dev.dv_xname); 145 if (psc->psc_ih == NULL) { 146 printf(": can't establish interrupt"); 147 if (intrstr != NULL) 148 printf(" at %s", intrstr); 149 printf("\n"); 150 return; 151 } 152 printf(": %s", intrstr); 153 154 /* we need to access PCI config space from the driver */ 155 sc->sc_conf_write = bwi_pci_conf_write; 156 sc->sc_conf_read = bwi_pci_conf_read; 157 158 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 159 160 sc->sc_pci_revid = PCI_REVISION(pa->pa_class); 161 sc->sc_pci_did = PCI_PRODUCT(pa->pa_id); 162 sc->sc_pci_subvid = PCI_VENDOR(reg); 163 sc->sc_pci_subdid = PCI_PRODUCT(reg); 164 165 bwi_attach(sc); 166 } 167 168 int 169 bwi_pci_detach(struct device *self, int flags) 170 { 171 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 172 struct bwi_softc *sc = &psc->psc_bwi; 173 174 bwi_detach(sc); 175 pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 176 177 return (0); 178 } 179 180 int 181 bwi_pci_activate(struct device *self, int act) 182 { 183 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 184 struct bwi_softc *sc = &psc->psc_bwi; 185 struct ifnet *ifp = &sc->sc_ic.ic_if; 186 187 switch (act) { 188 case DVACT_SUSPEND: 189 if (ifp->if_flags & IFF_RUNNING) 190 bwi_stop(sc, 1); 191 break; 192 case DVACT_WAKEUP: 193 bwi_pci_wakeup(sc); 194 break; 195 } 196 197 return (0); 198 } 199 200 void 201 bwi_pci_wakeup(struct bwi_softc *sc) 202 { 203 struct ifnet *ifp = &sc->sc_ic.ic_if; 204 205 if (ifp->if_flags & IFF_UP) 206 bwi_init(ifp); 207 } 208 209 void 210 bwi_pci_conf_write(void *self, uint32_t reg, uint32_t val) 211 { 212 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 213 214 pci_conf_write(psc->psc_pc, psc->psc_pcitag, reg, val); 215 } 216 217 uint32_t 218 bwi_pci_conf_read(void *self, uint32_t reg) 219 { 220 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 221 222 return (pci_conf_read(psc->psc_pc, psc->psc_pcitag, reg)); 223 } 224