1 /* $OpenBSD: if_bwi_pci.c,v 1.16 2015/11/24 17:11:39 mpi 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 37 #include <net/if.h> 38 #include <net/if_media.h> 39 40 #include <netinet/in.h> 41 #include <netinet/if_ether.h> 42 43 #include <net80211/ieee80211_var.h> 44 #include <net80211/ieee80211_amrr.h> 45 #include <net80211/ieee80211_radiotap.h> 46 47 #include <dev/ic/bwivar.h> 48 49 #include <dev/pci/pcireg.h> 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pcidevs.h> 52 53 /* Base Address Register */ 54 #define BWI_PCI_BAR0 0x10 55 56 int bwi_pci_match(struct device *, void *, void *); 57 void bwi_pci_attach(struct device *, struct device *, void *); 58 int bwi_pci_detach(struct device *, int); 59 void bwi_pci_conf_write(void *, uint32_t, uint32_t); 60 uint32_t bwi_pci_conf_read(void *, uint32_t); 61 int bwi_pci_activate(struct device *, int); 62 void bwi_pci_wakeup(struct bwi_softc *); 63 64 struct bwi_pci_softc { 65 struct bwi_softc psc_bwi; 66 67 pci_chipset_tag_t psc_pc; 68 pcitag_t psc_pcitag; 69 void *psc_ih; 70 71 bus_size_t psc_mapsize; 72 }; 73 74 struct cfattach bwi_pci_ca = { 75 sizeof(struct bwi_pci_softc), bwi_pci_match, bwi_pci_attach, 76 bwi_pci_detach, bwi_pci_activate 77 }; 78 79 const struct pci_matchid bwi_pci_devices[] = { 80 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 }, 81 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 }, 82 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 }, 83 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 }, 84 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 }, 85 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4311 }, 86 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4312 }, 87 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 }, 88 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 }, 89 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG } 90 }; 91 92 int 93 bwi_pci_match(struct device *parent, void *match, void *aux) 94 { 95 struct pci_attach_args *pa = aux; 96 97 /* 98 * The second revision of the BCM4311/BCM4312 99 * chips require v4 firmware. 100 */ 101 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROADCOM && 102 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4311 || 103 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4312) && 104 PCI_REVISION(pa->pa_class) == 0x02) 105 return (0); 106 107 return (pci_matchbyid((struct pci_attach_args *)aux, bwi_pci_devices, 108 sizeof(bwi_pci_devices) / sizeof(bwi_pci_devices[0]))); 109 } 110 111 void 112 bwi_pci_attach(struct device *parent, struct device *self, void *aux) 113 { 114 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 115 struct pci_attach_args *pa = aux; 116 struct bwi_softc *sc = &psc->psc_bwi; 117 const char *intrstr = NULL; 118 pci_intr_handle_t ih; 119 pcireg_t memtype, reg; 120 121 sc->sc_dmat = pa->pa_dmat; 122 psc->psc_pc = pa->pa_pc; 123 psc->psc_pcitag = pa->pa_tag; 124 125 /* map control / status registers */ 126 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BWI_PCI_BAR0); 127 if (pci_mapreg_map(pa, BWI_PCI_BAR0, memtype, 0, &sc->sc_mem_bt, 128 &sc->sc_mem_bh, NULL, &psc->psc_mapsize, 0)) { 129 printf(": can't map mem space\n"); 130 return; 131 } 132 133 /* map interrupt */ 134 if (pci_intr_map(pa, &ih) != 0) { 135 printf(": can't map interrupt\n"); 136 return; 137 } 138 139 /* establish interrupt */ 140 intrstr = pci_intr_string(psc->psc_pc, ih); 141 psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_NET, bwi_intr, sc, 142 sc->sc_dev.dv_xname); 143 if (psc->psc_ih == NULL) { 144 printf(": can't establish interrupt"); 145 if (intrstr != NULL) 146 printf(" at %s", intrstr); 147 printf("\n"); 148 return; 149 } 150 printf(": %s", intrstr); 151 152 /* we need to access PCI config space from the driver */ 153 sc->sc_conf_write = bwi_pci_conf_write; 154 sc->sc_conf_read = bwi_pci_conf_read; 155 156 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 157 158 sc->sc_pci_revid = PCI_REVISION(pa->pa_class); 159 sc->sc_pci_did = PCI_PRODUCT(pa->pa_id); 160 sc->sc_pci_subvid = PCI_VENDOR(reg); 161 sc->sc_pci_subdid = PCI_PRODUCT(reg); 162 163 bwi_attach(sc); 164 } 165 166 int 167 bwi_pci_detach(struct device *self, int flags) 168 { 169 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 170 struct bwi_softc *sc = &psc->psc_bwi; 171 172 bwi_detach(sc); 173 pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 174 175 return (0); 176 } 177 178 int 179 bwi_pci_activate(struct device *self, int act) 180 { 181 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 182 struct bwi_softc *sc = &psc->psc_bwi; 183 struct ifnet *ifp = &sc->sc_ic.ic_if; 184 185 switch (act) { 186 case DVACT_SUSPEND: 187 if (ifp->if_flags & IFF_RUNNING) 188 bwi_stop(sc, 1); 189 break; 190 case DVACT_WAKEUP: 191 bwi_pci_wakeup(sc); 192 break; 193 } 194 195 return (0); 196 } 197 198 void 199 bwi_pci_wakeup(struct bwi_softc *sc) 200 { 201 struct ifnet *ifp = &sc->sc_ic.ic_if; 202 203 if (ifp->if_flags & IFF_UP) 204 bwi_init(ifp); 205 } 206 207 void 208 bwi_pci_conf_write(void *self, uint32_t reg, uint32_t val) 209 { 210 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 211 212 pci_conf_write(psc->psc_pc, psc->psc_pcitag, reg, val); 213 } 214 215 uint32_t 216 bwi_pci_conf_read(void *self, uint32_t reg) 217 { 218 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 219 220 return (pci_conf_read(psc->psc_pc, psc->psc_pcitag, reg)); 221 } 222