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