1 /* $OpenBSD: if_bwi_pci.c,v 1.19 2024/05/24 06:02:53 jsg 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/systm.h> 27 #include <sys/timeout.h> 28 #include <sys/device.h> 29 30 #include <machine/bus.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/ic/bwivar.h> 43 #include <dev/ic/bwireg.h> 44 45 #include <dev/pci/pcireg.h> 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcidevs.h> 48 49 /* Base Address Register */ 50 #define BWI_PCI_BAR0 0x10 51 52 int bwi_pci_match(struct device *, void *, void *); 53 void bwi_pci_attach(struct device *, struct device *, void *); 54 int bwi_pci_detach(struct device *, int); 55 void bwi_pci_conf_write(void *, uint32_t, uint32_t); 56 uint32_t bwi_pci_conf_read(void *, uint32_t); 57 int bwi_pci_activate(struct device *, int); 58 void bwi_pci_wakeup(struct bwi_softc *); 59 60 struct bwi_pci_softc { 61 struct bwi_softc psc_bwi; 62 63 pci_chipset_tag_t psc_pc; 64 pcitag_t psc_pcitag; 65 void *psc_ih; 66 67 bus_size_t psc_mapsize; 68 }; 69 70 const struct cfattach bwi_pci_ca = { 71 sizeof(struct bwi_pci_softc), bwi_pci_match, bwi_pci_attach, 72 bwi_pci_detach, bwi_pci_activate 73 }; 74 75 const struct pci_matchid bwi_pci_devices[] = { 76 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 }, 77 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 }, 78 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 }, 79 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 }, 80 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 }, 81 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4311 }, 82 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4312 }, 83 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 }, 84 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 }, 85 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG }, 86 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4331 }, 87 }; 88 89 int 90 bwi_pci_match(struct device *parent, void *match, void *aux) 91 { 92 struct pci_attach_args *pa = aux; 93 94 /* 95 * The second revision of the BCM4311/BCM4312 96 * chips require v4 firmware. 97 */ 98 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROADCOM && 99 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4311 || 100 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM4312) && 101 PCI_REVISION(pa->pa_class) == 0x02) 102 return (0); 103 104 return (pci_matchbyid((struct pci_attach_args *)aux, bwi_pci_devices, 105 sizeof(bwi_pci_devices) / sizeof(bwi_pci_devices[0]))); 106 } 107 108 void 109 bwi_reset_bcm4331(struct bwi_softc *sc) 110 { 111 int i; 112 113 /* 114 * The BCM4331 is not actually supported by this driver, but buggy EFI 115 * revisions in 2011-2012 Macs leave this chip enabled by default, 116 * causing it to emit spurious interrupts when the shared interrupt 117 * line is enabled. 118 */ 119 for (i = 0; CSR_READ_4(sc, BWI_RESET_STATUS) && i < 30; i++) 120 delay(10); 121 122 CSR_WRITE_4(sc, BWI_RESET_CTRL, BWI_RESET_CTRL_RESET); 123 CSR_READ_4(sc, BWI_RESET_CTRL); 124 delay(1); 125 CSR_WRITE_4(sc, BWI_RESET_CTRL, 0); 126 CSR_READ_4(sc, BWI_RESET_CTRL); 127 delay(10); 128 } 129 130 void 131 bwi_pci_attach(struct device *parent, struct device *self, void *aux) 132 { 133 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 134 struct pci_attach_args *pa = aux; 135 struct bwi_softc *sc = &psc->psc_bwi; 136 const char *intrstr = NULL; 137 pci_intr_handle_t ih; 138 pcireg_t memtype, reg; 139 140 sc->sc_dmat = pa->pa_dmat; 141 psc->psc_pc = pa->pa_pc; 142 psc->psc_pcitag = pa->pa_tag; 143 144 /* map control / status registers */ 145 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BWI_PCI_BAR0); 146 if (pci_mapreg_map(pa, BWI_PCI_BAR0, memtype, 0, &sc->sc_mem_bt, 147 &sc->sc_mem_bh, NULL, &psc->psc_mapsize, 0)) { 148 printf(": can't map mem space\n"); 149 return; 150 } 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 if (sc->sc_pci_did == PCI_PRODUCT_BROADCOM_BCM4331) { 164 printf(": disabling\n"); 165 bwi_reset_bcm4331(sc); 166 bus_space_unmap(sc->sc_mem_bt, sc->sc_mem_bh, psc->psc_mapsize); 167 return; 168 } 169 170 /* map interrupt */ 171 if (pci_intr_map(pa, &ih) != 0) { 172 printf(": can't map interrupt\n"); 173 return; 174 } 175 176 /* establish interrupt */ 177 intrstr = pci_intr_string(psc->psc_pc, ih); 178 psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_NET, bwi_intr, sc, 179 sc->sc_dev.dv_xname); 180 if (psc->psc_ih == NULL) { 181 printf(": can't establish interrupt"); 182 if (intrstr != NULL) 183 printf(" at %s", intrstr); 184 printf("\n"); 185 return; 186 } 187 printf(": %s", intrstr); 188 189 bwi_attach(sc); 190 } 191 192 int 193 bwi_pci_detach(struct device *self, int flags) 194 { 195 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 196 struct bwi_softc *sc = &psc->psc_bwi; 197 198 bwi_detach(sc); 199 pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 200 201 return (0); 202 } 203 204 int 205 bwi_pci_activate(struct device *self, int act) 206 { 207 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 208 struct bwi_softc *sc = &psc->psc_bwi; 209 struct ifnet *ifp = &sc->sc_ic.ic_if; 210 211 switch (act) { 212 case DVACT_SUSPEND: 213 if (ifp->if_flags & IFF_RUNNING) 214 bwi_stop(sc, 1); 215 break; 216 case DVACT_WAKEUP: 217 bwi_pci_wakeup(sc); 218 break; 219 } 220 221 return (0); 222 } 223 224 void 225 bwi_pci_wakeup(struct bwi_softc *sc) 226 { 227 struct ifnet *ifp = &sc->sc_ic.ic_if; 228 229 if (ifp->if_flags & IFF_UP) 230 bwi_init(ifp); 231 } 232 233 void 234 bwi_pci_conf_write(void *self, uint32_t reg, uint32_t val) 235 { 236 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 237 238 pci_conf_write(psc->psc_pc, psc->psc_pcitag, reg, val); 239 } 240 241 uint32_t 242 bwi_pci_conf_read(void *self, uint32_t reg) 243 { 244 struct bwi_pci_softc *psc = (struct bwi_pci_softc *)self; 245 246 return (pci_conf_read(psc->psc_pc, psc->psc_pcitag, reg)); 247 } 248