1191762Simp/* 2191762Simp * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3191762Simp * 4191762Simp * This code is derived from software contributed to The DragonFly Project 5191762Simp * by Sepherosa Ziehau <sepherosa@gmail.com> 6191762Simp * 7191762Simp * Redistribution and use in source and binary forms, with or without 8191762Simp * modification, are permitted provided that the following conditions 9191762Simp * are met: 10191762Simp * 11191762Simp * 1. Redistributions of source code must retain the above copyright 12191762Simp * notice, this list of conditions and the following disclaimer. 13191762Simp * 2. Redistributions in binary form must reproduce the above copyright 14191762Simp * notice, this list of conditions and the following disclaimer in 15191762Simp * the documentation and/or other materials provided with the 16191762Simp * distribution. 17191762Simp * 3. Neither the name of The DragonFly Project nor the names of its 18191762Simp * contributors may be used to endorse or promote products derived 19191762Simp * from this software without specific, prior written permission. 20191762Simp * 21191762Simp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22191762Simp * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23191762Simp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24191762Simp * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25191762Simp * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26191762Simp * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27191762Simp * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28191762Simp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29191762Simp * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30191762Simp * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31191762Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32191762Simp * SUCH DAMAGE. 33191762Simp * 34191762Simp * $DragonFly: src/sys/dev/netif/bwi/if_bwi.c,v 1.19 2008/02/15 11:15:38 sephe Exp $ 35191762Simp */ 36191762Simp 37191762Simp#include <sys/cdefs.h> 38191762Simp__FBSDID("$FreeBSD$"); 39191762Simp 40191762Simp#include "opt_inet.h" 41191762Simp#include "opt_bwi.h" 42191762Simp 43191762Simp#include <sys/param.h> 44191762Simp#include <sys/endian.h> 45191762Simp#include <sys/kernel.h> 46191762Simp#include <sys/bus.h> 47191762Simp#include <sys/malloc.h> 48191762Simp#include <sys/proc.h> 49191762Simp#include <sys/rman.h> 50191762Simp#include <sys/socket.h> 51191762Simp#include <sys/sockio.h> 52191762Simp#include <sys/sysctl.h> 53191762Simp#include <sys/systm.h> 54191762Simp#include <sys/taskqueue.h> 55191762Simp 56191762Simp#include <net/if.h> 57191762Simp#include <net/if_dl.h> 58191762Simp#include <net/if_media.h> 59191762Simp#include <net/if_types.h> 60191762Simp#include <net/if_arp.h> 61191762Simp#include <net/ethernet.h> 62191762Simp#include <net/if_llc.h> 63191762Simp 64191762Simp#include <net80211/ieee80211_var.h> 65191762Simp#include <net80211/ieee80211_radiotap.h> 66191762Simp#include <net80211/ieee80211_regdomain.h> 67191762Simp#include <net80211/ieee80211_phy.h> 68206358Srpaulo#include <net80211/ieee80211_ratectl.h> 69191762Simp 70191762Simp#include <net/bpf.h> 71191762Simp 72191762Simp#ifdef INET 73191762Simp#include <netinet/in.h> 74191762Simp#include <netinet/if_ether.h> 75191762Simp#endif 76191762Simp 77191762Simp#include <machine/bus.h> 78191762Simp 79191762Simp#include <dev/pci/pcivar.h> 80191762Simp#include <dev/pci/pcireg.h> 81191762Simp 82191762Simp#include <dev/bwi/bitops.h> 83191762Simp#include <dev/bwi/if_bwireg.h> 84191762Simp#include <dev/bwi/if_bwivar.h> 85191762Simp#include <dev/bwi/bwimac.h> 86191762Simp#include <dev/bwi/bwirf.h> 87191762Simp 88191762Simpstruct bwi_clock_freq { 89191762Simp u_int clkfreq_min; 90191762Simp u_int clkfreq_max; 91191762Simp}; 92191762Simp 93191762Simpstruct bwi_myaddr_bssid { 94191762Simp uint8_t myaddr[IEEE80211_ADDR_LEN]; 95191762Simp uint8_t bssid[IEEE80211_ADDR_LEN]; 96191762Simp} __packed; 97191762Simp 98191762Simpstatic struct ieee80211vap *bwi_vap_create(struct ieee80211com *, 99234753Sdim const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 100234753Sdim const uint8_t [IEEE80211_ADDR_LEN], 101234753Sdim const uint8_t [IEEE80211_ADDR_LEN]); 102191762Simpstatic void bwi_vap_delete(struct ieee80211vap *); 103191762Simpstatic void bwi_init(void *); 104191762Simpstatic int bwi_ioctl(struct ifnet *, u_long, caddr_t); 105191762Simpstatic void bwi_start(struct ifnet *); 106191762Simpstatic void bwi_start_locked(struct ifnet *); 107191762Simpstatic int bwi_raw_xmit(struct ieee80211_node *, struct mbuf *, 108191762Simp const struct ieee80211_bpf_params *); 109199197Sjhbstatic void bwi_watchdog(void *); 110191762Simpstatic void bwi_scan_start(struct ieee80211com *); 111191762Simpstatic void bwi_set_channel(struct ieee80211com *); 112191762Simpstatic void bwi_scan_end(struct ieee80211com *); 113191762Simpstatic int bwi_newstate(struct ieee80211vap *, enum ieee80211_state, int); 114191762Simpstatic void bwi_updateslot(struct ifnet *); 115191762Simpstatic int bwi_media_change(struct ifnet *); 116191762Simp 117191762Simpstatic void bwi_calibrate(void *); 118191762Simp 119191762Simpstatic int bwi_calc_rssi(struct bwi_softc *, const struct bwi_rxbuf_hdr *); 120191762Simpstatic int bwi_calc_noise(struct bwi_softc *); 121234753Sdimstatic __inline uint8_t bwi_plcp2rate(uint32_t, enum ieee80211_phytype); 122192468Ssamstatic void bwi_rx_radiotap(struct bwi_softc *, struct mbuf *, 123191762Simp struct bwi_rxbuf_hdr *, const void *, int, int, int); 124191762Simp 125191762Simpstatic void bwi_restart(void *, int); 126191762Simpstatic void bwi_init_statechg(struct bwi_softc *, int); 127191762Simpstatic void bwi_stop(struct bwi_softc *, int); 128191762Simpstatic void bwi_stop_locked(struct bwi_softc *, int); 129191762Simpstatic int bwi_newbuf(struct bwi_softc *, int, int); 130191762Simpstatic int bwi_encap(struct bwi_softc *, int, struct mbuf *, 131191762Simp struct ieee80211_node *); 132191762Simpstatic int bwi_encap_raw(struct bwi_softc *, int, struct mbuf *, 133191762Simp struct ieee80211_node *, 134191762Simp const struct ieee80211_bpf_params *); 135191762Simp 136191762Simpstatic void bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t, 137191762Simp bus_addr_t, int, int); 138191762Simpstatic void bwi_reset_rx_ring32(struct bwi_softc *, uint32_t); 139191762Simp 140191762Simpstatic int bwi_init_tx_ring32(struct bwi_softc *, int); 141191762Simpstatic int bwi_init_rx_ring32(struct bwi_softc *); 142191762Simpstatic int bwi_init_txstats32(struct bwi_softc *); 143191762Simpstatic void bwi_free_tx_ring32(struct bwi_softc *, int); 144191762Simpstatic void bwi_free_rx_ring32(struct bwi_softc *); 145191762Simpstatic void bwi_free_txstats32(struct bwi_softc *); 146191762Simpstatic void bwi_setup_rx_desc32(struct bwi_softc *, int, bus_addr_t, int); 147191762Simpstatic void bwi_setup_tx_desc32(struct bwi_softc *, struct bwi_ring_data *, 148191762Simp int, bus_addr_t, int); 149191762Simpstatic int bwi_rxeof32(struct bwi_softc *); 150191762Simpstatic void bwi_start_tx32(struct bwi_softc *, uint32_t, int); 151191762Simpstatic void bwi_txeof_status32(struct bwi_softc *); 152191762Simp 153191762Simpstatic int bwi_init_tx_ring64(struct bwi_softc *, int); 154191762Simpstatic int bwi_init_rx_ring64(struct bwi_softc *); 155191762Simpstatic int bwi_init_txstats64(struct bwi_softc *); 156191762Simpstatic void bwi_free_tx_ring64(struct bwi_softc *, int); 157191762Simpstatic void bwi_free_rx_ring64(struct bwi_softc *); 158191762Simpstatic void bwi_free_txstats64(struct bwi_softc *); 159191762Simpstatic void bwi_setup_rx_desc64(struct bwi_softc *, int, bus_addr_t, int); 160191762Simpstatic void bwi_setup_tx_desc64(struct bwi_softc *, struct bwi_ring_data *, 161191762Simp int, bus_addr_t, int); 162191762Simpstatic int bwi_rxeof64(struct bwi_softc *); 163191762Simpstatic void bwi_start_tx64(struct bwi_softc *, uint32_t, int); 164191762Simpstatic void bwi_txeof_status64(struct bwi_softc *); 165191762Simp 166191762Simpstatic int bwi_rxeof(struct bwi_softc *, int); 167191762Simpstatic void _bwi_txeof(struct bwi_softc *, uint16_t, int, int); 168191762Simpstatic void bwi_txeof(struct bwi_softc *); 169191762Simpstatic void bwi_txeof_status(struct bwi_softc *, int); 170191762Simpstatic void bwi_enable_intrs(struct bwi_softc *, uint32_t); 171191762Simpstatic void bwi_disable_intrs(struct bwi_softc *, uint32_t); 172191762Simp 173191762Simpstatic int bwi_dma_alloc(struct bwi_softc *); 174191762Simpstatic void bwi_dma_free(struct bwi_softc *); 175191762Simpstatic int bwi_dma_ring_alloc(struct bwi_softc *, bus_dma_tag_t, 176191762Simp struct bwi_ring_data *, bus_size_t, 177191762Simp uint32_t); 178191762Simpstatic int bwi_dma_mbuf_create(struct bwi_softc *); 179191762Simpstatic void bwi_dma_mbuf_destroy(struct bwi_softc *, int, int); 180191762Simpstatic int bwi_dma_txstats_alloc(struct bwi_softc *, uint32_t, bus_size_t); 181191762Simpstatic void bwi_dma_txstats_free(struct bwi_softc *); 182191762Simpstatic void bwi_dma_ring_addr(void *, bus_dma_segment_t *, int, int); 183191762Simpstatic void bwi_dma_buf_addr(void *, bus_dma_segment_t *, int, 184191762Simp bus_size_t, int); 185191762Simp 186191762Simpstatic void bwi_power_on(struct bwi_softc *, int); 187191762Simpstatic int bwi_power_off(struct bwi_softc *, int); 188191762Simpstatic int bwi_set_clock_mode(struct bwi_softc *, enum bwi_clock_mode); 189191762Simpstatic int bwi_set_clock_delay(struct bwi_softc *); 190191762Simpstatic void bwi_get_clock_freq(struct bwi_softc *, struct bwi_clock_freq *); 191191762Simpstatic int bwi_get_pwron_delay(struct bwi_softc *sc); 192191762Simpstatic void bwi_set_addr_filter(struct bwi_softc *, uint16_t, 193191762Simp const uint8_t *); 194191762Simpstatic void bwi_set_bssid(struct bwi_softc *, const uint8_t *); 195191762Simp 196191762Simpstatic void bwi_get_card_flags(struct bwi_softc *); 197191762Simpstatic void bwi_get_eaddr(struct bwi_softc *, uint16_t, uint8_t *); 198191762Simp 199191762Simpstatic int bwi_bus_attach(struct bwi_softc *); 200191762Simpstatic int bwi_bbp_attach(struct bwi_softc *); 201191762Simpstatic int bwi_bbp_power_on(struct bwi_softc *, enum bwi_clock_mode); 202191762Simpstatic void bwi_bbp_power_off(struct bwi_softc *); 203191762Simp 204191762Simpstatic const char *bwi_regwin_name(const struct bwi_regwin *); 205191762Simpstatic uint32_t bwi_regwin_disable_bits(struct bwi_softc *); 206191762Simpstatic void bwi_regwin_info(struct bwi_softc *, uint16_t *, uint8_t *); 207191762Simpstatic int bwi_regwin_select(struct bwi_softc *, int); 208191762Simp 209191762Simpstatic void bwi_led_attach(struct bwi_softc *); 210191762Simpstatic void bwi_led_newstate(struct bwi_softc *, enum ieee80211_state); 211191762Simpstatic void bwi_led_event(struct bwi_softc *, int); 212191762Simpstatic void bwi_led_blink_start(struct bwi_softc *, int, int); 213191762Simpstatic void bwi_led_blink_next(void *); 214191762Simpstatic void bwi_led_blink_end(void *); 215191762Simp 216191762Simpstatic const struct { 217191762Simp uint16_t did_min; 218191762Simp uint16_t did_max; 219191762Simp uint16_t bbp_id; 220191762Simp} bwi_bbpid_map[] = { 221191762Simp { 0x4301, 0x4301, 0x4301 }, 222191762Simp { 0x4305, 0x4307, 0x4307 }, 223234753Sdim { 0x4402, 0x4403, 0x4402 }, 224191762Simp { 0x4610, 0x4615, 0x4610 }, 225191762Simp { 0x4710, 0x4715, 0x4710 }, 226191762Simp { 0x4720, 0x4725, 0x4309 } 227191762Simp}; 228191762Simp 229191762Simpstatic const struct { 230191762Simp uint16_t bbp_id; 231191762Simp int nregwin; 232191762Simp} bwi_regwin_count[] = { 233191762Simp { 0x4301, 5 }, 234191762Simp { 0x4306, 6 }, 235191762Simp { 0x4307, 5 }, 236191762Simp { 0x4310, 8 }, 237191762Simp { 0x4401, 3 }, 238191762Simp { 0x4402, 3 }, 239191762Simp { 0x4610, 9 }, 240191762Simp { 0x4704, 9 }, 241191762Simp { 0x4710, 9 }, 242191762Simp { 0x5365, 7 } 243191762Simp}; 244191762Simp 245191762Simp#define CLKSRC(src) \ 246191762Simp[BWI_CLKSRC_ ## src] = { \ 247191762Simp .freq_min = BWI_CLKSRC_ ##src## _FMIN, \ 248191762Simp .freq_max = BWI_CLKSRC_ ##src## _FMAX \ 249191762Simp} 250191762Simp 251191762Simpstatic const struct { 252191762Simp u_int freq_min; 253191762Simp u_int freq_max; 254191762Simp} bwi_clkfreq[BWI_CLKSRC_MAX] = { 255191762Simp CLKSRC(LP_OSC), 256191762Simp CLKSRC(CS_OSC), 257191762Simp CLKSRC(PCI) 258191762Simp}; 259191762Simp 260191762Simp#undef CLKSRC 261191762Simp 262191762Simp#define VENDOR_LED_ACT(vendor) \ 263191762Simp{ \ 264191762Simp .vid = PCI_VENDOR_##vendor, \ 265191762Simp .led_act = { BWI_VENDOR_LED_ACT_##vendor } \ 266191762Simp} 267191762Simp 268191762Simpstatic const struct { 269191762Simp#define PCI_VENDOR_COMPAQ 0x0e11 270191762Simp#define PCI_VENDOR_LINKSYS 0x1737 271191762Simp uint16_t vid; 272191762Simp uint8_t led_act[BWI_LED_MAX]; 273191762Simp} bwi_vendor_led_act[] = { 274191762Simp VENDOR_LED_ACT(COMPAQ), 275191762Simp VENDOR_LED_ACT(LINKSYS) 276191762Simp#undef PCI_VENDOR_LINKSYS 277191762Simp#undef PCI_VENDOR_COMPAQ 278191762Simp}; 279191762Simp 280191762Simpstatic const uint8_t bwi_default_led_act[BWI_LED_MAX] = 281191762Simp { BWI_VENDOR_LED_ACT_DEFAULT }; 282191762Simp 283191762Simp#undef VENDOR_LED_ACT 284191762Simp 285191762Simpstatic const struct { 286191762Simp int on_dur; 287191762Simp int off_dur; 288191762Simp} bwi_led_duration[109] = { 289191762Simp [0] = { 400, 100 }, 290191762Simp [2] = { 150, 75 }, 291191762Simp [4] = { 90, 45 }, 292191762Simp [11] = { 66, 34 }, 293191762Simp [12] = { 53, 26 }, 294191762Simp [18] = { 42, 21 }, 295191762Simp [22] = { 35, 17 }, 296191762Simp [24] = { 32, 16 }, 297191762Simp [36] = { 21, 10 }, 298191762Simp [48] = { 16, 8 }, 299191762Simp [72] = { 11, 5 }, 300191762Simp [96] = { 9, 4 }, 301191762Simp [108] = { 7, 3 } 302191762Simp}; 303191762Simp 304191762Simp#ifdef BWI_DEBUG 305191762Simp#ifdef BWI_DEBUG_VERBOSE 306191762Simpstatic uint32_t bwi_debug = BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_TXPOWER; 307191762Simp#else 308191762Simpstatic uint32_t bwi_debug; 309191762Simp#endif 310191762SimpTUNABLE_INT("hw.bwi.debug", (int *)&bwi_debug); 311191762Simp#endif /* BWI_DEBUG */ 312191762Simp 313191762Simpstatic const uint8_t bwi_zero_addr[IEEE80211_ADDR_LEN]; 314191762Simp 315191762Simpuint16_t 316191762Simpbwi_read_sprom(struct bwi_softc *sc, uint16_t ofs) 317191762Simp{ 318191762Simp return CSR_READ_2(sc, ofs + BWI_SPROM_START); 319191762Simp} 320191762Simp 321191762Simpstatic __inline void 322191762Simpbwi_setup_desc32(struct bwi_softc *sc, struct bwi_desc32 *desc_array, 323191762Simp int ndesc, int desc_idx, bus_addr_t paddr, int buf_len, 324191762Simp int tx) 325191762Simp{ 326191762Simp struct bwi_desc32 *desc = &desc_array[desc_idx]; 327191762Simp uint32_t ctrl, addr, addr_hi, addr_lo; 328191762Simp 329191762Simp addr_lo = __SHIFTOUT(paddr, BWI_DESC32_A_ADDR_MASK); 330191762Simp addr_hi = __SHIFTOUT(paddr, BWI_DESC32_A_FUNC_MASK); 331191762Simp 332191762Simp addr = __SHIFTIN(addr_lo, BWI_DESC32_A_ADDR_MASK) | 333191762Simp __SHIFTIN(BWI_DESC32_A_FUNC_TXRX, BWI_DESC32_A_FUNC_MASK); 334191762Simp 335191762Simp ctrl = __SHIFTIN(buf_len, BWI_DESC32_C_BUFLEN_MASK) | 336191762Simp __SHIFTIN(addr_hi, BWI_DESC32_C_ADDRHI_MASK); 337191762Simp if (desc_idx == ndesc - 1) 338191762Simp ctrl |= BWI_DESC32_C_EOR; 339191762Simp if (tx) { 340191762Simp /* XXX */ 341191762Simp ctrl |= BWI_DESC32_C_FRAME_START | 342191762Simp BWI_DESC32_C_FRAME_END | 343191762Simp BWI_DESC32_C_INTR; 344191762Simp } 345191762Simp 346191762Simp desc->addr = htole32(addr); 347191762Simp desc->ctrl = htole32(ctrl); 348191762Simp} 349191762Simp 350191762Simpint 351191762Simpbwi_attach(struct bwi_softc *sc) 352191762Simp{ 353191762Simp struct ieee80211com *ic; 354191762Simp device_t dev = sc->sc_dev; 355191762Simp struct ifnet *ifp; 356191762Simp struct bwi_mac *mac; 357191762Simp struct bwi_phy *phy; 358191762Simp int i, error; 359191762Simp uint8_t bands; 360191762Simp uint8_t macaddr[IEEE80211_ADDR_LEN]; 361191762Simp 362191762Simp BWI_LOCK_INIT(sc); 363191762Simp 364191762Simp /* 365191762Simp * Initialize taskq and various tasks 366191762Simp */ 367191762Simp sc->sc_tq = taskqueue_create("bwi_taskq", M_NOWAIT | M_ZERO, 368191762Simp taskqueue_thread_enqueue, &sc->sc_tq); 369191762Simp taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", 370191762Simp device_get_nameunit(dev)); 371191762Simp TASK_INIT(&sc->sc_restart_task, 0, bwi_restart, sc); 372191762Simp 373191762Simp callout_init_mtx(&sc->sc_calib_ch, &sc->sc_mtx, 0); 374191762Simp 375191762Simp /* 376191762Simp * Initialize sysctl variables 377191762Simp */ 378191762Simp sc->sc_fw_version = BWI_FW_VERSION3; 379191762Simp sc->sc_led_idle = (2350 * hz) / 1000; 380191762Simp sc->sc_led_blink = 1; 381191762Simp sc->sc_txpwr_calib = 1; 382191762Simp#ifdef BWI_DEBUG 383191762Simp sc->sc_debug = bwi_debug; 384191762Simp#endif 385191762Simp bwi_power_on(sc, 1); 386191762Simp 387191762Simp error = bwi_bbp_attach(sc); 388191762Simp if (error) 389191762Simp goto fail; 390191762Simp 391191762Simp error = bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); 392191762Simp if (error) 393191762Simp goto fail; 394191762Simp 395191762Simp if (BWI_REGWIN_EXIST(&sc->sc_com_regwin)) { 396191762Simp error = bwi_set_clock_delay(sc); 397191762Simp if (error) 398191762Simp goto fail; 399191762Simp 400191762Simp error = bwi_set_clock_mode(sc, BWI_CLOCK_MODE_FAST); 401191762Simp if (error) 402191762Simp goto fail; 403191762Simp 404191762Simp error = bwi_get_pwron_delay(sc); 405191762Simp if (error) 406191762Simp goto fail; 407191762Simp } 408191762Simp 409191762Simp error = bwi_bus_attach(sc); 410191762Simp if (error) 411191762Simp goto fail; 412191762Simp 413191762Simp bwi_get_card_flags(sc); 414191762Simp 415191762Simp bwi_led_attach(sc); 416191762Simp 417191762Simp for (i = 0; i < sc->sc_nmac; ++i) { 418191762Simp struct bwi_regwin *old; 419191762Simp 420191762Simp mac = &sc->sc_mac[i]; 421191762Simp error = bwi_regwin_switch(sc, &mac->mac_regwin, &old); 422191762Simp if (error) 423191762Simp goto fail; 424191762Simp 425191762Simp error = bwi_mac_lateattach(mac); 426191762Simp if (error) 427191762Simp goto fail; 428191762Simp 429191762Simp error = bwi_regwin_switch(sc, old, NULL); 430191762Simp if (error) 431191762Simp goto fail; 432191762Simp } 433191762Simp 434191762Simp /* 435191762Simp * XXX First MAC is known to exist 436191762Simp * TODO2 437191762Simp */ 438191762Simp mac = &sc->sc_mac[0]; 439191762Simp phy = &mac->mac_phy; 440191762Simp 441191762Simp bwi_bbp_power_off(sc); 442191762Simp 443191762Simp error = bwi_dma_alloc(sc); 444191762Simp if (error) 445191762Simp goto fail; 446191762Simp 447191762Simp ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 448191762Simp if (ifp == NULL) { 449191762Simp device_printf(dev, "can not if_alloc()\n"); 450191762Simp error = ENOSPC; 451191762Simp goto fail; 452191762Simp } 453191762Simp ic = ifp->if_l2com; 454191762Simp 455191762Simp /* set these up early for if_printf use */ 456191762Simp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 457191762Simp 458191762Simp ifp->if_softc = sc; 459191762Simp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 460191762Simp ifp->if_init = bwi_init; 461191762Simp ifp->if_ioctl = bwi_ioctl; 462191762Simp ifp->if_start = bwi_start; 463207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 464207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 465191762Simp IFQ_SET_READY(&ifp->if_snd); 466199197Sjhb callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); 467191762Simp 468191762Simp /* 469191762Simp * Setup ratesets, phytype, channels and get MAC address 470191762Simp */ 471191762Simp bands = 0; 472191762Simp if (phy->phy_mode == IEEE80211_MODE_11B || 473191762Simp phy->phy_mode == IEEE80211_MODE_11G) { 474191762Simp setbit(&bands, IEEE80211_MODE_11B); 475191762Simp if (phy->phy_mode == IEEE80211_MODE_11B) { 476191762Simp ic->ic_phytype = IEEE80211_T_DS; 477191762Simp } else { 478191762Simp ic->ic_phytype = IEEE80211_T_OFDM; 479191762Simp setbit(&bands, IEEE80211_MODE_11G); 480191762Simp } 481191762Simp 482191762Simp bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, macaddr); 483191762Simp if (IEEE80211_IS_MULTICAST(macaddr)) { 484191762Simp bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, macaddr); 485191762Simp if (IEEE80211_IS_MULTICAST(macaddr)) { 486191762Simp device_printf(dev, 487191762Simp "invalid MAC address: %6D\n", 488191762Simp macaddr, ":"); 489191762Simp } 490191762Simp } 491191762Simp } else if (phy->phy_mode == IEEE80211_MODE_11A) { 492191762Simp /* TODO:11A */ 493191762Simp setbit(&bands, IEEE80211_MODE_11A); 494191762Simp error = ENXIO; 495191762Simp goto fail; 496191762Simp } else { 497191762Simp panic("unknown phymode %d\n", phy->phy_mode); 498191762Simp } 499191762Simp 500191762Simp /* Get locale */ 501191762Simp sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO), 502191762Simp BWI_SPROM_CARD_INFO_LOCALE); 503191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale); 504191762Simp /* XXX use locale */ 505191762Simp ieee80211_init_channels(ic, NULL, &bands); 506191762Simp 507191762Simp ic->ic_ifp = ifp; 508191762Simp ic->ic_caps = IEEE80211_C_STA | 509191762Simp IEEE80211_C_SHSLOT | 510191762Simp IEEE80211_C_SHPREAMBLE | 511191762Simp IEEE80211_C_WPA | 512191762Simp IEEE80211_C_BGSCAN | 513214894Sbschmidt IEEE80211_C_MONITOR; 514191762Simp ic->ic_opmode = IEEE80211_M_STA; 515191762Simp ieee80211_ifattach(ic, macaddr); 516191762Simp 517191762Simp ic->ic_headroom = sizeof(struct bwi_txbuf_hdr); 518191762Simp 519191762Simp /* override default methods */ 520191762Simp ic->ic_vap_create = bwi_vap_create; 521191762Simp ic->ic_vap_delete = bwi_vap_delete; 522191762Simp ic->ic_raw_xmit = bwi_raw_xmit; 523191762Simp ic->ic_updateslot = bwi_updateslot; 524191762Simp ic->ic_scan_start = bwi_scan_start; 525191762Simp ic->ic_scan_end = bwi_scan_end; 526191762Simp ic->ic_set_channel = bwi_set_channel; 527191762Simp 528191762Simp sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); 529191762Simp 530192468Ssam ieee80211_radiotap_attach(ic, 531192468Ssam &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), 532192468Ssam BWI_TX_RADIOTAP_PRESENT, 533192468Ssam &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 534192468Ssam BWI_RX_RADIOTAP_PRESENT); 535191762Simp 536191762Simp /* 537191762Simp * Add sysctl nodes 538191762Simp */ 539217323Smdf SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 540191762Simp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 541191762Simp "fw_version", CTLFLAG_RD, &sc->sc_fw_version, 0, 542191762Simp "Firmware version"); 543217323Smdf SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 544191762Simp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 545191762Simp "led_idle", CTLFLAG_RW, &sc->sc_led_idle, 0, 546191762Simp "# ticks before LED enters idle state"); 547191762Simp SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 548191762Simp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 549191762Simp "led_blink", CTLFLAG_RW, &sc->sc_led_blink, 0, 550191762Simp "Allow LED to blink"); 551191762Simp SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 552191762Simp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 553191762Simp "txpwr_calib", CTLFLAG_RW, &sc->sc_txpwr_calib, 0, 554191762Simp "Enable software TX power calibration"); 555191762Simp#ifdef BWI_DEBUG 556191762Simp SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 557191762Simp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 558191762Simp "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags"); 559191762Simp#endif 560191762Simp if (bootverbose) 561191762Simp ieee80211_announce(ic); 562191762Simp 563191762Simp return (0); 564191762Simpfail: 565191762Simp BWI_LOCK_DESTROY(sc); 566191762Simp return (error); 567191762Simp} 568191762Simp 569191762Simpint 570191762Simpbwi_detach(struct bwi_softc *sc) 571191762Simp{ 572191762Simp struct ifnet *ifp = sc->sc_ifp; 573191762Simp struct ieee80211com *ic = ifp->if_l2com; 574191762Simp int i; 575191762Simp 576191762Simp bwi_stop(sc, 1); 577193237Simp callout_drain(&sc->sc_led_blink_ch); 578191762Simp callout_drain(&sc->sc_calib_ch); 579199197Sjhb callout_drain(&sc->sc_watchdog_timer); 580191762Simp ieee80211_ifdetach(ic); 581191762Simp 582191762Simp for (i = 0; i < sc->sc_nmac; ++i) 583191762Simp bwi_mac_detach(&sc->sc_mac[i]); 584191762Simp bwi_dma_free(sc); 585191762Simp if_free(ifp); 586191762Simp taskqueue_free(sc->sc_tq); 587191762Simp 588191762Simp BWI_LOCK_DESTROY(sc); 589191762Simp 590191762Simp return (0); 591191762Simp} 592191762Simp 593191762Simpstatic struct ieee80211vap * 594234753Sdimbwi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 595234753Sdim enum ieee80211_opmode opmode, int flags, 596234753Sdim const uint8_t bssid[IEEE80211_ADDR_LEN], 597234753Sdim const uint8_t mac[IEEE80211_ADDR_LEN]) 598191762Simp{ 599191762Simp struct bwi_vap *bvp; 600191762Simp struct ieee80211vap *vap; 601191762Simp 602191762Simp if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 603191762Simp return NULL; 604191762Simp bvp = (struct bwi_vap *) malloc(sizeof(struct bwi_vap), 605191762Simp M_80211_VAP, M_WAITOK | M_ZERO); 606191762Simp if (bvp == NULL) 607191762Simp return NULL; 608191762Simp vap = &bvp->bv_vap; 609191762Simp /* enable s/w bmiss handling for sta mode */ 610191762Simp ieee80211_vap_setup(ic, vap, name, unit, opmode, 611191762Simp flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); 612191762Simp 613191762Simp /* override default methods */ 614191762Simp bvp->bv_newstate = vap->iv_newstate; 615191762Simp vap->iv_newstate = bwi_newstate; 616191762Simp#if 0 617191762Simp vap->iv_update_beacon = bwi_beacon_update; 618191762Simp#endif 619206358Srpaulo ieee80211_ratectl_init(vap); 620191762Simp 621191762Simp /* complete setup */ 622191762Simp ieee80211_vap_attach(vap, bwi_media_change, ieee80211_media_status); 623191762Simp ic->ic_opmode = opmode; 624191762Simp return vap; 625191762Simp} 626191762Simp 627191762Simpstatic void 628191762Simpbwi_vap_delete(struct ieee80211vap *vap) 629191762Simp{ 630191762Simp struct bwi_vap *bvp = BWI_VAP(vap); 631191762Simp 632206358Srpaulo ieee80211_ratectl_deinit(vap); 633191762Simp ieee80211_vap_detach(vap); 634191762Simp free(bvp, M_80211_VAP); 635191762Simp} 636191762Simp 637191762Simpvoid 638191762Simpbwi_suspend(struct bwi_softc *sc) 639191762Simp{ 640191762Simp bwi_stop(sc, 1); 641191762Simp} 642191762Simp 643191762Simpvoid 644191762Simpbwi_resume(struct bwi_softc *sc) 645191762Simp{ 646191762Simp struct ifnet *ifp = sc->sc_ifp; 647191762Simp 648191762Simp if (ifp->if_flags & IFF_UP) 649191762Simp bwi_init(sc); 650191762Simp} 651191762Simp 652191762Simpint 653191762Simpbwi_shutdown(struct bwi_softc *sc) 654191762Simp{ 655191762Simp bwi_stop(sc, 1); 656191762Simp return 0; 657191762Simp} 658191762Simp 659191762Simpstatic void 660191762Simpbwi_power_on(struct bwi_softc *sc, int with_pll) 661191762Simp{ 662191762Simp uint32_t gpio_in, gpio_out, gpio_en; 663191762Simp uint16_t status; 664191762Simp 665191762Simp gpio_in = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_IN, 4); 666191762Simp if (gpio_in & BWI_PCIM_GPIO_PWR_ON) 667191762Simp goto back; 668191762Simp 669191762Simp gpio_out = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4); 670191762Simp gpio_en = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, 4); 671191762Simp 672191762Simp gpio_out |= BWI_PCIM_GPIO_PWR_ON; 673191762Simp gpio_en |= BWI_PCIM_GPIO_PWR_ON; 674191762Simp if (with_pll) { 675191762Simp /* Turn off PLL first */ 676191762Simp gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; 677191762Simp gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; 678191762Simp } 679191762Simp 680191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4); 681191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, gpio_en, 4); 682191762Simp DELAY(1000); 683191762Simp 684191762Simp if (with_pll) { 685191762Simp /* Turn on PLL */ 686191762Simp gpio_out &= ~BWI_PCIM_GPIO_PLL_PWR_OFF; 687191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4); 688191762Simp DELAY(5000); 689191762Simp } 690191762Simp 691191762Simpback: 692191762Simp /* Clear "Signaled Target Abort" */ 693191762Simp status = pci_read_config(sc->sc_dev, PCIR_STATUS, 2); 694191762Simp status &= ~PCIM_STATUS_STABORT; 695191762Simp pci_write_config(sc->sc_dev, PCIR_STATUS, status, 2); 696191762Simp} 697191762Simp 698191762Simpstatic int 699191762Simpbwi_power_off(struct bwi_softc *sc, int with_pll) 700191762Simp{ 701191762Simp uint32_t gpio_out, gpio_en; 702191762Simp 703191762Simp pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_IN, 4); /* dummy read */ 704191762Simp gpio_out = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4); 705191762Simp gpio_en = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, 4); 706191762Simp 707191762Simp gpio_out &= ~BWI_PCIM_GPIO_PWR_ON; 708191762Simp gpio_en |= BWI_PCIM_GPIO_PWR_ON; 709191762Simp if (with_pll) { 710191762Simp gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; 711191762Simp gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; 712191762Simp } 713191762Simp 714191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, gpio_out, 4); 715191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_GPIO_ENABLE, gpio_en, 4); 716191762Simp return 0; 717191762Simp} 718191762Simp 719191762Simpint 720191762Simpbwi_regwin_switch(struct bwi_softc *sc, struct bwi_regwin *rw, 721191762Simp struct bwi_regwin **old_rw) 722191762Simp{ 723191762Simp int error; 724191762Simp 725191762Simp if (old_rw != NULL) 726191762Simp *old_rw = NULL; 727191762Simp 728191762Simp if (!BWI_REGWIN_EXIST(rw)) 729191762Simp return EINVAL; 730191762Simp 731191762Simp if (sc->sc_cur_regwin != rw) { 732191762Simp error = bwi_regwin_select(sc, rw->rw_id); 733191762Simp if (error) { 734191762Simp device_printf(sc->sc_dev, "can't select regwin %d\n", 735191762Simp rw->rw_id); 736191762Simp return error; 737191762Simp } 738191762Simp } 739191762Simp 740191762Simp if (old_rw != NULL) 741191762Simp *old_rw = sc->sc_cur_regwin; 742191762Simp sc->sc_cur_regwin = rw; 743191762Simp return 0; 744191762Simp} 745191762Simp 746191762Simpstatic int 747191762Simpbwi_regwin_select(struct bwi_softc *sc, int id) 748191762Simp{ 749191762Simp uint32_t win = BWI_PCIM_REGWIN(id); 750191762Simp int i; 751191762Simp 752191762Simp#define RETRY_MAX 50 753191762Simp for (i = 0; i < RETRY_MAX; ++i) { 754191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_SEL_REGWIN, win, 4); 755191762Simp if (pci_read_config(sc->sc_dev, BWI_PCIR_SEL_REGWIN, 4) == win) 756191762Simp return 0; 757191762Simp DELAY(10); 758191762Simp } 759191762Simp#undef RETRY_MAX 760191762Simp 761191762Simp return ENXIO; 762191762Simp} 763191762Simp 764191762Simpstatic void 765191762Simpbwi_regwin_info(struct bwi_softc *sc, uint16_t *type, uint8_t *rev) 766191762Simp{ 767191762Simp uint32_t val; 768191762Simp 769191762Simp val = CSR_READ_4(sc, BWI_ID_HI); 770191762Simp *type = BWI_ID_HI_REGWIN_TYPE(val); 771191762Simp *rev = BWI_ID_HI_REGWIN_REV(val); 772191762Simp 773191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "regwin: type 0x%03x, rev %d, " 774191762Simp "vendor 0x%04x\n", *type, *rev, 775191762Simp __SHIFTOUT(val, BWI_ID_HI_REGWIN_VENDOR_MASK)); 776191762Simp} 777191762Simp 778191762Simpstatic int 779191762Simpbwi_bbp_attach(struct bwi_softc *sc) 780191762Simp{ 781191762Simp#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) 782191762Simp uint16_t bbp_id, rw_type; 783191762Simp uint8_t rw_rev; 784191762Simp uint32_t info; 785191762Simp int error, nregwin, i; 786191762Simp 787191762Simp /* 788191762Simp * Get 0th regwin information 789191762Simp * NOTE: 0th regwin should exist 790191762Simp */ 791191762Simp error = bwi_regwin_select(sc, 0); 792191762Simp if (error) { 793191762Simp device_printf(sc->sc_dev, "can't select regwin 0\n"); 794191762Simp return error; 795191762Simp } 796191762Simp bwi_regwin_info(sc, &rw_type, &rw_rev); 797191762Simp 798191762Simp /* 799191762Simp * Find out BBP id 800191762Simp */ 801191762Simp bbp_id = 0; 802191762Simp info = 0; 803191762Simp if (rw_type == BWI_REGWIN_T_COM) { 804191762Simp info = CSR_READ_4(sc, BWI_INFO); 805191762Simp bbp_id = __SHIFTOUT(info, BWI_INFO_BBPID_MASK); 806191762Simp 807191762Simp BWI_CREATE_REGWIN(&sc->sc_com_regwin, 0, rw_type, rw_rev); 808191762Simp 809191762Simp sc->sc_cap = CSR_READ_4(sc, BWI_CAPABILITY); 810191762Simp } else { 811191762Simp for (i = 0; i < N(bwi_bbpid_map); ++i) { 812191762Simp if (sc->sc_pci_did >= bwi_bbpid_map[i].did_min && 813191762Simp sc->sc_pci_did <= bwi_bbpid_map[i].did_max) { 814191762Simp bbp_id = bwi_bbpid_map[i].bbp_id; 815191762Simp break; 816191762Simp } 817191762Simp } 818191762Simp if (bbp_id == 0) { 819191762Simp device_printf(sc->sc_dev, "no BBP id for device id " 820191762Simp "0x%04x\n", sc->sc_pci_did); 821191762Simp return ENXIO; 822191762Simp } 823191762Simp 824191762Simp info = __SHIFTIN(sc->sc_pci_revid, BWI_INFO_BBPREV_MASK) | 825191762Simp __SHIFTIN(0, BWI_INFO_BBPPKG_MASK); 826191762Simp } 827191762Simp 828191762Simp /* 829191762Simp * Find out number of regwins 830191762Simp */ 831191762Simp nregwin = 0; 832191762Simp if (rw_type == BWI_REGWIN_T_COM && rw_rev >= 4) { 833191762Simp nregwin = __SHIFTOUT(info, BWI_INFO_NREGWIN_MASK); 834191762Simp } else { 835191762Simp for (i = 0; i < N(bwi_regwin_count); ++i) { 836191762Simp if (bwi_regwin_count[i].bbp_id == bbp_id) { 837191762Simp nregwin = bwi_regwin_count[i].nregwin; 838191762Simp break; 839191762Simp } 840191762Simp } 841191762Simp if (nregwin == 0) { 842191762Simp device_printf(sc->sc_dev, "no number of win for " 843191762Simp "BBP id 0x%04x\n", bbp_id); 844191762Simp return ENXIO; 845191762Simp } 846191762Simp } 847191762Simp 848191762Simp /* Record BBP id/rev for later using */ 849191762Simp sc->sc_bbp_id = bbp_id; 850191762Simp sc->sc_bbp_rev = __SHIFTOUT(info, BWI_INFO_BBPREV_MASK); 851191762Simp sc->sc_bbp_pkg = __SHIFTOUT(info, BWI_INFO_BBPPKG_MASK); 852191762Simp device_printf(sc->sc_dev, "BBP: id 0x%04x, rev 0x%x, pkg %d\n", 853191762Simp sc->sc_bbp_id, sc->sc_bbp_rev, sc->sc_bbp_pkg); 854191762Simp 855191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "nregwin %d, cap 0x%08x\n", 856191762Simp nregwin, sc->sc_cap); 857191762Simp 858191762Simp /* 859191762Simp * Create rest of the regwins 860191762Simp */ 861191762Simp 862191762Simp /* Don't re-create common regwin, if it is already created */ 863191762Simp i = BWI_REGWIN_EXIST(&sc->sc_com_regwin) ? 1 : 0; 864191762Simp 865191762Simp for (; i < nregwin; ++i) { 866191762Simp /* 867191762Simp * Get regwin information 868191762Simp */ 869191762Simp error = bwi_regwin_select(sc, i); 870191762Simp if (error) { 871191762Simp device_printf(sc->sc_dev, 872191762Simp "can't select regwin %d\n", i); 873191762Simp return error; 874191762Simp } 875191762Simp bwi_regwin_info(sc, &rw_type, &rw_rev); 876191762Simp 877191762Simp /* 878191762Simp * Try attach: 879191762Simp * 1) Bus (PCI/PCIE) regwin 880191762Simp * 2) MAC regwin 881191762Simp * Ignore rest types of regwin 882191762Simp */ 883191762Simp if (rw_type == BWI_REGWIN_T_BUSPCI || 884191762Simp rw_type == BWI_REGWIN_T_BUSPCIE) { 885191762Simp if (BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { 886191762Simp device_printf(sc->sc_dev, 887191762Simp "bus regwin already exists\n"); 888191762Simp } else { 889191762Simp BWI_CREATE_REGWIN(&sc->sc_bus_regwin, i, 890191762Simp rw_type, rw_rev); 891191762Simp } 892191762Simp } else if (rw_type == BWI_REGWIN_T_MAC) { 893191762Simp /* XXX ignore return value */ 894191762Simp bwi_mac_attach(sc, i, rw_rev); 895191762Simp } 896191762Simp } 897191762Simp 898191762Simp /* At least one MAC shold exist */ 899191762Simp if (!BWI_REGWIN_EXIST(&sc->sc_mac[0].mac_regwin)) { 900191762Simp device_printf(sc->sc_dev, "no MAC was found\n"); 901191762Simp return ENXIO; 902191762Simp } 903191762Simp KASSERT(sc->sc_nmac > 0, ("no mac's")); 904191762Simp 905191762Simp /* Bus regwin must exist */ 906191762Simp if (!BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { 907191762Simp device_printf(sc->sc_dev, "no bus regwin was found\n"); 908191762Simp return ENXIO; 909191762Simp } 910191762Simp 911191762Simp /* Start with first MAC */ 912191762Simp error = bwi_regwin_switch(sc, &sc->sc_mac[0].mac_regwin, NULL); 913191762Simp if (error) 914191762Simp return error; 915191762Simp 916191762Simp return 0; 917191762Simp#undef N 918191762Simp} 919191762Simp 920191762Simpint 921191762Simpbwi_bus_init(struct bwi_softc *sc, struct bwi_mac *mac) 922191762Simp{ 923191762Simp struct bwi_regwin *old, *bus; 924191762Simp uint32_t val; 925191762Simp int error; 926191762Simp 927191762Simp bus = &sc->sc_bus_regwin; 928191762Simp KASSERT(sc->sc_cur_regwin == &mac->mac_regwin, ("not cur regwin")); 929191762Simp 930191762Simp /* 931191762Simp * Tell bus to generate requested interrupts 932191762Simp */ 933191762Simp if (bus->rw_rev < 6 && bus->rw_type == BWI_REGWIN_T_BUSPCI) { 934191762Simp /* 935191762Simp * NOTE: Read BWI_FLAGS from MAC regwin 936191762Simp */ 937191762Simp val = CSR_READ_4(sc, BWI_FLAGS); 938191762Simp 939191762Simp error = bwi_regwin_switch(sc, bus, &old); 940191762Simp if (error) 941191762Simp return error; 942191762Simp 943191762Simp CSR_SETBITS_4(sc, BWI_INTRVEC, (val & BWI_FLAGS_INTR_MASK)); 944191762Simp } else { 945191762Simp uint32_t mac_mask; 946191762Simp 947191762Simp mac_mask = 1 << mac->mac_id; 948191762Simp 949191762Simp error = bwi_regwin_switch(sc, bus, &old); 950191762Simp if (error) 951191762Simp return error; 952191762Simp 953191762Simp val = pci_read_config(sc->sc_dev, BWI_PCIR_INTCTL, 4); 954191762Simp val |= mac_mask << 8; 955191762Simp pci_write_config(sc->sc_dev, BWI_PCIR_INTCTL, val, 4); 956191762Simp } 957191762Simp 958191762Simp if (sc->sc_flags & BWI_F_BUS_INITED) 959191762Simp goto back; 960191762Simp 961191762Simp if (bus->rw_type == BWI_REGWIN_T_BUSPCI) { 962191762Simp /* 963191762Simp * Enable prefetch and burst 964191762Simp */ 965191762Simp CSR_SETBITS_4(sc, BWI_BUS_CONFIG, 966191762Simp BWI_BUS_CONFIG_PREFETCH | BWI_BUS_CONFIG_BURST); 967191762Simp 968191762Simp if (bus->rw_rev < 5) { 969191762Simp struct bwi_regwin *com = &sc->sc_com_regwin; 970191762Simp 971191762Simp /* 972191762Simp * Configure timeouts for bus operation 973191762Simp */ 974191762Simp 975191762Simp /* 976191762Simp * Set service timeout and request timeout 977191762Simp */ 978191762Simp CSR_SETBITS_4(sc, BWI_CONF_LO, 979191762Simp __SHIFTIN(BWI_CONF_LO_SERVTO, BWI_CONF_LO_SERVTO_MASK) | 980191762Simp __SHIFTIN(BWI_CONF_LO_REQTO, BWI_CONF_LO_REQTO_MASK)); 981191762Simp 982191762Simp /* 983191762Simp * If there is common regwin, we switch to that regwin 984191762Simp * and switch back to bus regwin once we have done. 985191762Simp */ 986191762Simp if (BWI_REGWIN_EXIST(com)) { 987191762Simp error = bwi_regwin_switch(sc, com, NULL); 988191762Simp if (error) 989191762Simp return error; 990191762Simp } 991191762Simp 992191762Simp /* Let bus know what we have changed */ 993191762Simp CSR_WRITE_4(sc, BWI_BUS_ADDR, BWI_BUS_ADDR_MAGIC); 994191762Simp CSR_READ_4(sc, BWI_BUS_ADDR); /* Flush */ 995191762Simp CSR_WRITE_4(sc, BWI_BUS_DATA, 0); 996191762Simp CSR_READ_4(sc, BWI_BUS_DATA); /* Flush */ 997191762Simp 998191762Simp if (BWI_REGWIN_EXIST(com)) { 999191762Simp error = bwi_regwin_switch(sc, bus, NULL); 1000191762Simp if (error) 1001191762Simp return error; 1002191762Simp } 1003191762Simp } else if (bus->rw_rev >= 11) { 1004191762Simp /* 1005191762Simp * Enable memory read multiple 1006191762Simp */ 1007191762Simp CSR_SETBITS_4(sc, BWI_BUS_CONFIG, BWI_BUS_CONFIG_MRM); 1008191762Simp } 1009191762Simp } else { 1010191762Simp /* TODO:PCIE */ 1011191762Simp } 1012191762Simp 1013191762Simp sc->sc_flags |= BWI_F_BUS_INITED; 1014191762Simpback: 1015191762Simp return bwi_regwin_switch(sc, old, NULL); 1016191762Simp} 1017191762Simp 1018191762Simpstatic void 1019191762Simpbwi_get_card_flags(struct bwi_softc *sc) 1020191762Simp{ 1021191762Simp#define PCI_VENDOR_APPLE 0x106b 1022191762Simp#define PCI_VENDOR_DELL 0x1028 1023191762Simp sc->sc_card_flags = bwi_read_sprom(sc, BWI_SPROM_CARD_FLAGS); 1024191762Simp if (sc->sc_card_flags == 0xffff) 1025191762Simp sc->sc_card_flags = 0; 1026191762Simp 1027191762Simp if (sc->sc_pci_subvid == PCI_VENDOR_DELL && 1028191762Simp sc->sc_bbp_id == BWI_BBPID_BCM4301 && 1029191762Simp sc->sc_pci_revid == 0x74) 1030191762Simp sc->sc_card_flags |= BWI_CARD_F_BT_COEXIST; 1031191762Simp 1032191762Simp if (sc->sc_pci_subvid == PCI_VENDOR_APPLE && 1033191762Simp sc->sc_pci_subdid == 0x4e && /* XXX */ 1034191762Simp sc->sc_pci_revid > 0x40) 1035191762Simp sc->sc_card_flags |= BWI_CARD_F_PA_GPIO9; 1036191762Simp 1037191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "card flags 0x%04x\n", sc->sc_card_flags); 1038191762Simp#undef PCI_VENDOR_DELL 1039191762Simp#undef PCI_VENDOR_APPLE 1040191762Simp} 1041191762Simp 1042191762Simpstatic void 1043191762Simpbwi_get_eaddr(struct bwi_softc *sc, uint16_t eaddr_ofs, uint8_t *eaddr) 1044191762Simp{ 1045191762Simp int i; 1046191762Simp 1047191762Simp for (i = 0; i < 3; ++i) { 1048191762Simp *((uint16_t *)eaddr + i) = 1049191762Simp htobe16(bwi_read_sprom(sc, eaddr_ofs + 2 * i)); 1050191762Simp } 1051191762Simp} 1052191762Simp 1053191762Simpstatic void 1054191762Simpbwi_get_clock_freq(struct bwi_softc *sc, struct bwi_clock_freq *freq) 1055191762Simp{ 1056191762Simp struct bwi_regwin *com; 1057191762Simp uint32_t val; 1058191762Simp u_int div; 1059191762Simp int src; 1060191762Simp 1061191762Simp bzero(freq, sizeof(*freq)); 1062191762Simp com = &sc->sc_com_regwin; 1063191762Simp 1064191762Simp KASSERT(BWI_REGWIN_EXIST(com), ("regwin does not exist")); 1065191762Simp KASSERT(sc->sc_cur_regwin == com, ("wrong regwin")); 1066191762Simp KASSERT(sc->sc_cap & BWI_CAP_CLKMODE, ("wrong clock mode")); 1067191762Simp 1068191762Simp /* 1069191762Simp * Calculate clock frequency 1070191762Simp */ 1071191762Simp src = -1; 1072191762Simp div = 0; 1073191762Simp if (com->rw_rev < 6) { 1074191762Simp val = pci_read_config(sc->sc_dev, BWI_PCIR_GPIO_OUT, 4); 1075191762Simp if (val & BWI_PCIM_GPIO_OUT_CLKSRC) { 1076191762Simp src = BWI_CLKSRC_PCI; 1077191762Simp div = 64; 1078191762Simp } else { 1079191762Simp src = BWI_CLKSRC_CS_OSC; 1080191762Simp div = 32; 1081191762Simp } 1082191762Simp } else if (com->rw_rev < 10) { 1083191762Simp val = CSR_READ_4(sc, BWI_CLOCK_CTRL); 1084191762Simp 1085191762Simp src = __SHIFTOUT(val, BWI_CLOCK_CTRL_CLKSRC); 1086191762Simp if (src == BWI_CLKSRC_LP_OSC) { 1087191762Simp div = 1; 1088191762Simp } else { 1089191762Simp div = (__SHIFTOUT(val, BWI_CLOCK_CTRL_FDIV) + 1) << 2; 1090191762Simp 1091191762Simp /* Unknown source */ 1092191762Simp if (src >= BWI_CLKSRC_MAX) 1093191762Simp src = BWI_CLKSRC_CS_OSC; 1094191762Simp } 1095191762Simp } else { 1096191762Simp val = CSR_READ_4(sc, BWI_CLOCK_INFO); 1097191762Simp 1098191762Simp src = BWI_CLKSRC_CS_OSC; 1099191762Simp div = (__SHIFTOUT(val, BWI_CLOCK_INFO_FDIV) + 1) << 2; 1100191762Simp } 1101191762Simp 1102191762Simp KASSERT(src >= 0 && src < BWI_CLKSRC_MAX, ("bad src %d", src)); 1103191762Simp KASSERT(div != 0, ("div zero")); 1104191762Simp 1105191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "clksrc %s\n", 1106191762Simp src == BWI_CLKSRC_PCI ? "PCI" : 1107191762Simp (src == BWI_CLKSRC_LP_OSC ? "LP_OSC" : "CS_OSC")); 1108191762Simp 1109191762Simp freq->clkfreq_min = bwi_clkfreq[src].freq_min / div; 1110191762Simp freq->clkfreq_max = bwi_clkfreq[src].freq_max / div; 1111191762Simp 1112191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "clkfreq min %u, max %u\n", 1113191762Simp freq->clkfreq_min, freq->clkfreq_max); 1114191762Simp} 1115191762Simp 1116191762Simpstatic int 1117191762Simpbwi_set_clock_mode(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) 1118191762Simp{ 1119191762Simp struct bwi_regwin *old, *com; 1120191762Simp uint32_t clk_ctrl, clk_src; 1121191762Simp int error, pwr_off = 0; 1122191762Simp 1123191762Simp com = &sc->sc_com_regwin; 1124191762Simp if (!BWI_REGWIN_EXIST(com)) 1125191762Simp return 0; 1126191762Simp 1127191762Simp if (com->rw_rev >= 10 || com->rw_rev < 6) 1128191762Simp return 0; 1129191762Simp 1130191762Simp /* 1131191762Simp * For common regwin whose rev is [6, 10), the chip 1132191762Simp * must be capable to change clock mode. 1133191762Simp */ 1134191762Simp if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) 1135191762Simp return 0; 1136191762Simp 1137191762Simp error = bwi_regwin_switch(sc, com, &old); 1138191762Simp if (error) 1139191762Simp return error; 1140191762Simp 1141191762Simp if (clk_mode == BWI_CLOCK_MODE_FAST) 1142191762Simp bwi_power_on(sc, 0); /* Don't turn on PLL */ 1143191762Simp 1144191762Simp clk_ctrl = CSR_READ_4(sc, BWI_CLOCK_CTRL); 1145191762Simp clk_src = __SHIFTOUT(clk_ctrl, BWI_CLOCK_CTRL_CLKSRC); 1146191762Simp 1147191762Simp switch (clk_mode) { 1148191762Simp case BWI_CLOCK_MODE_FAST: 1149191762Simp clk_ctrl &= ~BWI_CLOCK_CTRL_SLOW; 1150191762Simp clk_ctrl |= BWI_CLOCK_CTRL_IGNPLL; 1151191762Simp break; 1152191762Simp case BWI_CLOCK_MODE_SLOW: 1153191762Simp clk_ctrl |= BWI_CLOCK_CTRL_SLOW; 1154191762Simp break; 1155191762Simp case BWI_CLOCK_MODE_DYN: 1156191762Simp clk_ctrl &= ~(BWI_CLOCK_CTRL_SLOW | 1157191762Simp BWI_CLOCK_CTRL_IGNPLL | 1158191762Simp BWI_CLOCK_CTRL_NODYN); 1159191762Simp if (clk_src != BWI_CLKSRC_CS_OSC) { 1160191762Simp clk_ctrl |= BWI_CLOCK_CTRL_NODYN; 1161191762Simp pwr_off = 1; 1162191762Simp } 1163191762Simp break; 1164191762Simp } 1165191762Simp CSR_WRITE_4(sc, BWI_CLOCK_CTRL, clk_ctrl); 1166191762Simp 1167191762Simp if (pwr_off) 1168191762Simp bwi_power_off(sc, 0); /* Leave PLL as it is */ 1169191762Simp 1170191762Simp return bwi_regwin_switch(sc, old, NULL); 1171191762Simp} 1172191762Simp 1173191762Simpstatic int 1174191762Simpbwi_set_clock_delay(struct bwi_softc *sc) 1175191762Simp{ 1176191762Simp struct bwi_regwin *old, *com; 1177191762Simp int error; 1178191762Simp 1179191762Simp com = &sc->sc_com_regwin; 1180191762Simp if (!BWI_REGWIN_EXIST(com)) 1181191762Simp return 0; 1182191762Simp 1183191762Simp error = bwi_regwin_switch(sc, com, &old); 1184191762Simp if (error) 1185191762Simp return error; 1186191762Simp 1187191762Simp if (sc->sc_bbp_id == BWI_BBPID_BCM4321) { 1188191762Simp if (sc->sc_bbp_rev == 0) 1189191762Simp CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC0); 1190191762Simp else if (sc->sc_bbp_rev == 1) 1191191762Simp CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC1); 1192191762Simp } 1193191762Simp 1194191762Simp if (sc->sc_cap & BWI_CAP_CLKMODE) { 1195191762Simp if (com->rw_rev >= 10) { 1196191762Simp CSR_FILT_SETBITS_4(sc, BWI_CLOCK_INFO, 0xffff, 0x40000); 1197191762Simp } else { 1198191762Simp struct bwi_clock_freq freq; 1199191762Simp 1200191762Simp bwi_get_clock_freq(sc, &freq); 1201191762Simp CSR_WRITE_4(sc, BWI_PLL_ON_DELAY, 1202191762Simp howmany(freq.clkfreq_max * 150, 1000000)); 1203191762Simp CSR_WRITE_4(sc, BWI_FREQ_SEL_DELAY, 1204191762Simp howmany(freq.clkfreq_max * 15, 1000000)); 1205191762Simp } 1206191762Simp } 1207191762Simp 1208191762Simp return bwi_regwin_switch(sc, old, NULL); 1209191762Simp} 1210191762Simp 1211191762Simpstatic void 1212191762Simpbwi_init(void *xsc) 1213191762Simp{ 1214191762Simp struct bwi_softc *sc = xsc; 1215191762Simp struct ifnet *ifp = sc->sc_ifp; 1216191762Simp struct ieee80211com *ic = ifp->if_l2com; 1217191762Simp 1218191762Simp BWI_LOCK(sc); 1219191762Simp bwi_init_statechg(sc, 1); 1220191762Simp BWI_UNLOCK(sc); 1221191762Simp 1222191762Simp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1223191762Simp ieee80211_start_all(ic); /* start all vap's */ 1224191762Simp} 1225191762Simp 1226191762Simpstatic void 1227191762Simpbwi_init_statechg(struct bwi_softc *sc, int statechg) 1228191762Simp{ 1229191762Simp struct ifnet *ifp = sc->sc_ifp; 1230191762Simp struct bwi_mac *mac; 1231191762Simp int error; 1232191762Simp 1233191762Simp bwi_stop_locked(sc, statechg); 1234191762Simp 1235191762Simp bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); 1236191762Simp 1237191762Simp /* TODO: 2 MAC */ 1238191762Simp 1239191762Simp mac = &sc->sc_mac[0]; 1240191762Simp error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); 1241191762Simp if (error) { 1242191762Simp if_printf(ifp, "%s: error %d on regwin switch\n", 1243191762Simp __func__, error); 1244191762Simp goto bad; 1245191762Simp } 1246191762Simp error = bwi_mac_init(mac); 1247191762Simp if (error) { 1248191762Simp if_printf(ifp, "%s: error %d on MAC init\n", __func__, error); 1249191762Simp goto bad; 1250191762Simp } 1251191762Simp 1252191762Simp bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); 1253191762Simp 1254191762Simp bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ 1255191762Simp bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, IF_LLADDR(ifp)); 1256191762Simp 1257191762Simp bwi_mac_reset_hwkeys(mac); 1258191762Simp 1259191762Simp if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) { 1260191762Simp int i; 1261191762Simp 1262191762Simp#define NRETRY 1000 1263191762Simp /* 1264191762Simp * Drain any possible pending TX status 1265191762Simp */ 1266191762Simp for (i = 0; i < NRETRY; ++i) { 1267191762Simp if ((CSR_READ_4(sc, BWI_TXSTATUS0) & 1268191762Simp BWI_TXSTATUS0_VALID) == 0) 1269191762Simp break; 1270191762Simp CSR_READ_4(sc, BWI_TXSTATUS1); 1271191762Simp } 1272191762Simp if (i == NRETRY) 1273191762Simp if_printf(ifp, "%s: can't drain TX status\n", __func__); 1274191762Simp#undef NRETRY 1275191762Simp } 1276191762Simp 1277191762Simp if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) 1278191762Simp bwi_mac_updateslot(mac, 1); 1279191762Simp 1280191762Simp /* Start MAC */ 1281191762Simp error = bwi_mac_start(mac); 1282191762Simp if (error) { 1283191762Simp if_printf(ifp, "%s: error %d starting MAC\n", __func__, error); 1284191762Simp goto bad; 1285191762Simp } 1286191762Simp 1287191762Simp /* Clear stop flag before enabling interrupt */ 1288191762Simp sc->sc_flags &= ~BWI_F_STOP; 1289191762Simp 1290191762Simp ifp->if_drv_flags |= IFF_DRV_RUNNING; 1291199197Sjhb callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); 1292191762Simp 1293191762Simp /* Enable intrs */ 1294191762Simp bwi_enable_intrs(sc, BWI_INIT_INTRS); 1295191762Simp return; 1296191762Simpbad: 1297191762Simp bwi_stop_locked(sc, 1); 1298191762Simp} 1299191762Simp 1300191762Simpstatic int 1301191762Simpbwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1302191762Simp{ 1303191762Simp#define IS_RUNNING(ifp) \ 1304191762Simp ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 1305191762Simp struct bwi_softc *sc = ifp->if_softc; 1306191762Simp struct ieee80211com *ic = ifp->if_l2com; 1307191762Simp struct ifreq *ifr = (struct ifreq *) data; 1308191762Simp int error = 0, startall = 0; 1309191762Simp 1310191762Simp switch (cmd) { 1311191762Simp case SIOCSIFFLAGS: 1312191762Simp BWI_LOCK(sc); 1313191762Simp if (IS_RUNNING(ifp)) { 1314191762Simp struct bwi_mac *mac; 1315191762Simp int promisc = -1; 1316191762Simp 1317191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 1318191762Simp ("current regwin type %d", 1319191762Simp sc->sc_cur_regwin->rw_type)); 1320191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 1321191762Simp 1322191762Simp if ((ifp->if_flags & IFF_PROMISC) && 1323191762Simp (sc->sc_flags & BWI_F_PROMISC) == 0) { 1324191762Simp promisc = 1; 1325191762Simp sc->sc_flags |= BWI_F_PROMISC; 1326191762Simp } else if ((ifp->if_flags & IFF_PROMISC) == 0 && 1327191762Simp (sc->sc_flags & BWI_F_PROMISC)) { 1328191762Simp promisc = 0; 1329191762Simp sc->sc_flags &= ~BWI_F_PROMISC; 1330191762Simp } 1331191762Simp 1332191762Simp if (promisc >= 0) 1333191762Simp bwi_mac_set_promisc(mac, promisc); 1334191762Simp } 1335191762Simp 1336191762Simp if (ifp->if_flags & IFF_UP) { 1337191762Simp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1338191762Simp bwi_init_statechg(sc, 1); 1339191762Simp startall = 1; 1340191762Simp } 1341191762Simp } else { 1342191762Simp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1343191762Simp bwi_stop_locked(sc, 1); 1344191762Simp } 1345191762Simp BWI_UNLOCK(sc); 1346191762Simp if (startall) 1347191762Simp ieee80211_start_all(ic); 1348191762Simp break; 1349191762Simp case SIOCGIFMEDIA: 1350191762Simp error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 1351191762Simp break; 1352191762Simp case SIOCGIFADDR: 1353191762Simp error = ether_ioctl(ifp, cmd, data); 1354191762Simp break; 1355191762Simp default: 1356191762Simp error = EINVAL; 1357191762Simp break; 1358191762Simp } 1359191762Simp return error; 1360191762Simp#undef IS_RUNNING 1361191762Simp} 1362191762Simp 1363191762Simpstatic void 1364191762Simpbwi_start(struct ifnet *ifp) 1365191762Simp{ 1366191762Simp struct bwi_softc *sc = ifp->if_softc; 1367191762Simp 1368191762Simp BWI_LOCK(sc); 1369191762Simp bwi_start_locked(ifp); 1370191762Simp BWI_UNLOCK(sc); 1371191762Simp} 1372191762Simp 1373191762Simpstatic void 1374191762Simpbwi_start_locked(struct ifnet *ifp) 1375191762Simp{ 1376191762Simp struct bwi_softc *sc = ifp->if_softc; 1377191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; 1378191762Simp struct ieee80211_frame *wh; 1379191762Simp struct ieee80211_node *ni; 1380191762Simp struct ieee80211_key *k; 1381191762Simp struct mbuf *m; 1382191762Simp int trans, idx; 1383191762Simp 1384191762Simp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1385191762Simp return; 1386191762Simp 1387191762Simp trans = 0; 1388191762Simp idx = tbd->tbd_idx; 1389191762Simp 1390191762Simp while (tbd->tbd_buf[idx].tb_mbuf == NULL) { 1391191762Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ 1392191762Simp if (m == NULL) 1393191762Simp break; 1394191762Simp 1395191762Simp ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1396191762Simp wh = mtod(m, struct ieee80211_frame *); 1397191762Simp if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1398191762Simp k = ieee80211_crypto_encap(ni, m); 1399191762Simp if (k == NULL) { 1400191762Simp ieee80211_free_node(ni); 1401191762Simp m_freem(m); 1402191762Simp ifp->if_oerrors++; 1403191762Simp continue; 1404191762Simp } 1405191762Simp } 1406191762Simp wh = NULL; /* Catch any invalid use */ 1407191762Simp 1408191762Simp if (bwi_encap(sc, idx, m, ni) != 0) { 1409191762Simp /* 'm' is freed in bwi_encap() if we reach here */ 1410191762Simp if (ni != NULL) 1411191762Simp ieee80211_free_node(ni); 1412191762Simp ifp->if_oerrors++; 1413191762Simp continue; 1414191762Simp } 1415191762Simp 1416191762Simp trans = 1; 1417191762Simp tbd->tbd_used++; 1418191762Simp idx = (idx + 1) % BWI_TX_NDESC; 1419191762Simp 1420191762Simp ifp->if_opackets++; 1421191762Simp 1422191762Simp if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) { 1423191762Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1424191762Simp break; 1425191762Simp } 1426191762Simp } 1427191762Simp tbd->tbd_idx = idx; 1428191762Simp 1429191762Simp if (trans) 1430199197Sjhb sc->sc_tx_timer = 5; 1431191762Simp} 1432191762Simp 1433191762Simpstatic int 1434191762Simpbwi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 1435191762Simp const struct ieee80211_bpf_params *params) 1436191762Simp{ 1437191762Simp struct ieee80211com *ic = ni->ni_ic; 1438191762Simp struct ifnet *ifp = ic->ic_ifp; 1439191762Simp struct bwi_softc *sc = ifp->if_softc; 1440191762Simp /* XXX wme? */ 1441191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; 1442191762Simp int idx, error; 1443191762Simp 1444191762Simp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1445191762Simp ieee80211_free_node(ni); 1446191762Simp m_freem(m); 1447191762Simp return ENETDOWN; 1448191762Simp } 1449191762Simp 1450191762Simp BWI_LOCK(sc); 1451191762Simp idx = tbd->tbd_idx; 1452191762Simp KASSERT(tbd->tbd_buf[idx].tb_mbuf == NULL, ("slot %d not empty", idx)); 1453191762Simp if (params == NULL) { 1454191762Simp /* 1455191762Simp * Legacy path; interpret frame contents to decide 1456191762Simp * precisely how to send the frame. 1457191762Simp */ 1458191762Simp error = bwi_encap(sc, idx, m, ni); 1459191762Simp } else { 1460191762Simp /* 1461191762Simp * Caller supplied explicit parameters to use in 1462191762Simp * sending the frame. 1463191762Simp */ 1464191762Simp error = bwi_encap_raw(sc, idx, m, ni, params); 1465191762Simp } 1466191762Simp if (error == 0) { 1467191762Simp ifp->if_opackets++; 1468191762Simp if (++tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) 1469191762Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1470191762Simp tbd->tbd_idx = (idx + 1) % BWI_TX_NDESC; 1471199197Sjhb sc->sc_tx_timer = 5; 1472191762Simp } else { 1473191762Simp /* NB: m is reclaimed on encap failure */ 1474191762Simp ieee80211_free_node(ni); 1475191762Simp ifp->if_oerrors++; 1476191762Simp } 1477191762Simp BWI_UNLOCK(sc); 1478191762Simp return error; 1479191762Simp} 1480191762Simp 1481191762Simpstatic void 1482199197Sjhbbwi_watchdog(void *arg) 1483191762Simp{ 1484199197Sjhb struct bwi_softc *sc; 1485199197Sjhb struct ifnet *ifp; 1486191762Simp 1487199197Sjhb sc = arg; 1488199197Sjhb ifp = sc->sc_ifp; 1489199197Sjhb BWI_ASSERT_LOCKED(sc); 1490199197Sjhb if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) { 1491191762Simp if_printf(ifp, "watchdog timeout\n"); 1492191762Simp ifp->if_oerrors++; 1493191762Simp taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); 1494191762Simp } 1495199197Sjhb callout_reset(&sc->sc_watchdog_timer, hz, bwi_watchdog, sc); 1496191762Simp} 1497191762Simp 1498191762Simpstatic void 1499191762Simpbwi_stop(struct bwi_softc *sc, int statechg) 1500191762Simp{ 1501191762Simp BWI_LOCK(sc); 1502191762Simp bwi_stop_locked(sc, statechg); 1503191762Simp BWI_UNLOCK(sc); 1504191762Simp} 1505191762Simp 1506191762Simpstatic void 1507191762Simpbwi_stop_locked(struct bwi_softc *sc, int statechg) 1508191762Simp{ 1509191762Simp struct ifnet *ifp = sc->sc_ifp; 1510191762Simp struct bwi_mac *mac; 1511191762Simp int i, error, pwr_off = 0; 1512191762Simp 1513191762Simp BWI_ASSERT_LOCKED(sc); 1514191762Simp 1515191762Simp callout_stop(&sc->sc_calib_ch); 1516191762Simp callout_stop(&sc->sc_led_blink_ch); 1517191762Simp sc->sc_led_blinking = 0; 1518191762Simp sc->sc_flags |= BWI_F_STOP; 1519191762Simp 1520191762Simp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1521191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 1522191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 1523191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 1524191762Simp 1525191762Simp bwi_disable_intrs(sc, BWI_ALL_INTRS); 1526191762Simp CSR_READ_4(sc, BWI_MAC_INTR_MASK); 1527191762Simp bwi_mac_stop(mac); 1528191762Simp } 1529191762Simp 1530191762Simp for (i = 0; i < sc->sc_nmac; ++i) { 1531191762Simp struct bwi_regwin *old_rw; 1532191762Simp 1533191762Simp mac = &sc->sc_mac[i]; 1534191762Simp if ((mac->mac_flags & BWI_MAC_F_INITED) == 0) 1535191762Simp continue; 1536191762Simp 1537191762Simp error = bwi_regwin_switch(sc, &mac->mac_regwin, &old_rw); 1538191762Simp if (error) 1539191762Simp continue; 1540191762Simp 1541191762Simp bwi_mac_shutdown(mac); 1542191762Simp pwr_off = 1; 1543191762Simp 1544191762Simp bwi_regwin_switch(sc, old_rw, NULL); 1545191762Simp } 1546191762Simp 1547191762Simp if (pwr_off) 1548191762Simp bwi_bbp_power_off(sc); 1549191762Simp 1550191762Simp sc->sc_tx_timer = 0; 1551199197Sjhb callout_stop(&sc->sc_watchdog_timer); 1552191762Simp ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1553191762Simp} 1554191762Simp 1555191762Simpvoid 1556191762Simpbwi_intr(void *xsc) 1557191762Simp{ 1558191762Simp struct bwi_softc *sc = xsc; 1559191762Simp struct ifnet *ifp = sc->sc_ifp; 1560191762Simp struct bwi_mac *mac; 1561191762Simp uint32_t intr_status; 1562191762Simp uint32_t txrx_intr_status[BWI_TXRX_NRING]; 1563191762Simp int i, txrx_error, tx = 0, rx_data = -1; 1564191762Simp 1565191762Simp BWI_LOCK(sc); 1566191762Simp 1567191762Simp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 1568191762Simp (sc->sc_flags & BWI_F_STOP)) { 1569191762Simp BWI_UNLOCK(sc); 1570191762Simp return; 1571191762Simp } 1572191762Simp /* 1573191762Simp * Get interrupt status 1574191762Simp */ 1575191762Simp intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); 1576191762Simp if (intr_status == 0xffffffff) { /* Not for us */ 1577191762Simp BWI_UNLOCK(sc); 1578191762Simp return; 1579191762Simp } 1580191762Simp 1581191762Simp DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status); 1582191762Simp 1583191762Simp intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK); 1584191762Simp if (intr_status == 0) { /* Nothing is interesting */ 1585191762Simp BWI_UNLOCK(sc); 1586191762Simp return; 1587191762Simp } 1588191762Simp 1589191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 1590191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 1591191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 1592191762Simp 1593191762Simp txrx_error = 0; 1594191762Simp DPRINTF(sc, BWI_DBG_INTR, "%s\n", "TX/RX intr"); 1595191762Simp for (i = 0; i < BWI_TXRX_NRING; ++i) { 1596191762Simp uint32_t mask; 1597191762Simp 1598191762Simp if (BWI_TXRX_IS_RX(i)) 1599191762Simp mask = BWI_TXRX_RX_INTRS; 1600191762Simp else 1601191762Simp mask = BWI_TXRX_TX_INTRS; 1602191762Simp 1603191762Simp txrx_intr_status[i] = 1604191762Simp CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask; 1605191762Simp 1606191762Simp _DPRINTF(sc, BWI_DBG_INTR, ", %d 0x%08x", 1607191762Simp i, txrx_intr_status[i]); 1608191762Simp 1609191762Simp if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { 1610191762Simp if_printf(ifp, 1611191762Simp "%s: intr fatal TX/RX (%d) error 0x%08x\n", 1612191762Simp __func__, i, txrx_intr_status[i]); 1613191762Simp txrx_error = 1; 1614191762Simp } 1615191762Simp } 1616191762Simp _DPRINTF(sc, BWI_DBG_INTR, "%s\n", ""); 1617191762Simp 1618191762Simp /* 1619191762Simp * Acknowledge interrupt 1620191762Simp */ 1621191762Simp CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status); 1622191762Simp 1623191762Simp for (i = 0; i < BWI_TXRX_NRING; ++i) 1624191762Simp CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i), txrx_intr_status[i]); 1625191762Simp 1626191762Simp /* Disable all interrupts */ 1627191762Simp bwi_disable_intrs(sc, BWI_ALL_INTRS); 1628191762Simp 1629193236Simp /* 1630193236Simp * http://bcm-specs.sipsolutions.net/Interrupts 1631193236Simp * Says for this bit (0x800): 1632193236Simp * "Fatal Error 1633193236Simp * 1634193236Simp * We got this one while testing things when by accident the 1635193236Simp * template ram wasn't set to big endian when it should have 1636193236Simp * been after writing the initial values. It keeps on being 1637193236Simp * triggered, the only way to stop it seems to shut down the 1638193236Simp * chip." 1639193236Simp * 1640193236Simp * Suggesting that we should never get it and if we do we're not 1641193236Simp * feeding TX packets into the MAC correctly if we do... Apparently, 1642193236Simp * it is valid only on mac version 5 and higher, but I couldn't 1643193236Simp * find a reference for that... Since I see them from time to time 1644193236Simp * on my card, this suggests an error in the tx path still... 1645193236Simp */ 1646191762Simp if (intr_status & BWI_INTR_PHY_TXERR) { 1647191762Simp if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { 1648191762Simp if_printf(ifp, "%s: intr PHY TX error\n", __func__); 1649191762Simp taskqueue_enqueue(sc->sc_tq, &sc->sc_restart_task); 1650191762Simp BWI_UNLOCK(sc); 1651191762Simp return; 1652191762Simp } 1653191762Simp } 1654191762Simp 1655191762Simp if (txrx_error) { 1656191762Simp /* TODO: reset device */ 1657191762Simp } 1658191762Simp 1659191762Simp if (intr_status & BWI_INTR_TBTT) 1660191762Simp bwi_mac_config_ps(mac); 1661191762Simp 1662191762Simp if (intr_status & BWI_INTR_EO_ATIM) 1663191762Simp if_printf(ifp, "EO_ATIM\n"); 1664191762Simp 1665191762Simp if (intr_status & BWI_INTR_PMQ) { 1666191762Simp for (;;) { 1667191762Simp if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) == 0) 1668191762Simp break; 1669191762Simp } 1670191762Simp CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2); 1671191762Simp } 1672191762Simp 1673191762Simp if (intr_status & BWI_INTR_NOISE) 1674191762Simp if_printf(ifp, "intr noise\n"); 1675191762Simp 1676191762Simp if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) { 1677191762Simp rx_data = sc->sc_rxeof(sc); 1678191762Simp if (sc->sc_flags & BWI_F_STOP) { 1679191762Simp BWI_UNLOCK(sc); 1680191762Simp return; 1681191762Simp } 1682191762Simp } 1683191762Simp 1684191762Simp if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) { 1685191762Simp sc->sc_txeof_status(sc); 1686191762Simp tx = 1; 1687191762Simp } 1688191762Simp 1689191762Simp if (intr_status & BWI_INTR_TX_DONE) { 1690191762Simp bwi_txeof(sc); 1691191762Simp tx = 1; 1692191762Simp } 1693191762Simp 1694191762Simp /* Re-enable interrupts */ 1695191762Simp bwi_enable_intrs(sc, BWI_INIT_INTRS); 1696191762Simp 1697191762Simp if (sc->sc_blink_led != NULL && sc->sc_led_blink) { 1698191762Simp int evt = BWI_LED_EVENT_NONE; 1699191762Simp 1700191762Simp if (tx && rx_data > 0) { 1701191762Simp if (sc->sc_rx_rate > sc->sc_tx_rate) 1702191762Simp evt = BWI_LED_EVENT_RX; 1703191762Simp else 1704191762Simp evt = BWI_LED_EVENT_TX; 1705191762Simp } else if (tx) { 1706191762Simp evt = BWI_LED_EVENT_TX; 1707191762Simp } else if (rx_data > 0) { 1708191762Simp evt = BWI_LED_EVENT_RX; 1709191762Simp } else if (rx_data == 0) { 1710191762Simp evt = BWI_LED_EVENT_POLL; 1711191762Simp } 1712191762Simp 1713191762Simp if (evt != BWI_LED_EVENT_NONE) 1714191762Simp bwi_led_event(sc, evt); 1715191762Simp } 1716191762Simp 1717191762Simp BWI_UNLOCK(sc); 1718191762Simp} 1719191762Simp 1720191762Simpstatic void 1721191762Simpbwi_scan_start(struct ieee80211com *ic) 1722191762Simp{ 1723191762Simp struct bwi_softc *sc = ic->ic_ifp->if_softc; 1724191762Simp 1725191762Simp BWI_LOCK(sc); 1726191762Simp /* Enable MAC beacon promiscuity */ 1727191762Simp CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); 1728191762Simp BWI_UNLOCK(sc); 1729191762Simp} 1730191762Simp 1731191762Simpstatic void 1732191762Simpbwi_set_channel(struct ieee80211com *ic) 1733191762Simp{ 1734191762Simp struct bwi_softc *sc = ic->ic_ifp->if_softc; 1735191762Simp struct ieee80211_channel *c = ic->ic_curchan; 1736191762Simp struct bwi_mac *mac; 1737191762Simp 1738191762Simp BWI_LOCK(sc); 1739191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 1740191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 1741191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 1742191762Simp bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0); 1743191762Simp 1744191762Simp sc->sc_rates = ieee80211_get_ratetable(c); 1745191762Simp 1746191762Simp /* 1747191762Simp * Setup radio tap channel freq and flags 1748191762Simp */ 1749191762Simp sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq = 1750191762Simp htole16(c->ic_freq); 1751191762Simp sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = 1752191762Simp htole16(c->ic_flags & 0xffff); 1753191762Simp 1754191762Simp BWI_UNLOCK(sc); 1755191762Simp} 1756191762Simp 1757191762Simpstatic void 1758191762Simpbwi_scan_end(struct ieee80211com *ic) 1759191762Simp{ 1760191762Simp struct bwi_softc *sc = ic->ic_ifp->if_softc; 1761191762Simp 1762191762Simp BWI_LOCK(sc); 1763191762Simp CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_PASS_BCN); 1764191762Simp BWI_UNLOCK(sc); 1765191762Simp} 1766191762Simp 1767191762Simpstatic int 1768191762Simpbwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1769191762Simp{ 1770191762Simp struct bwi_vap *bvp = BWI_VAP(vap); 1771193310Simp struct ieee80211com *ic= vap->iv_ic; 1772193310Simp struct ifnet *ifp = ic->ic_ifp; 1773193310Simp enum ieee80211_state ostate = vap->iv_state; 1774191762Simp struct bwi_softc *sc = ifp->if_softc; 1775191762Simp struct bwi_mac *mac; 1776191762Simp int error; 1777191762Simp 1778191762Simp BWI_LOCK(sc); 1779191762Simp 1780191762Simp callout_stop(&sc->sc_calib_ch); 1781191762Simp 1782191762Simp if (nstate == IEEE80211_S_INIT) 1783191762Simp sc->sc_txpwrcb_type = BWI_TXPWR_INIT; 1784191762Simp 1785191762Simp bwi_led_newstate(sc, nstate); 1786191762Simp 1787191762Simp error = bvp->bv_newstate(vap, nstate, arg); 1788191762Simp if (error != 0) 1789191762Simp goto back; 1790191762Simp 1791193310Simp /* 1792193310Simp * Clear the BSSID when we stop a STA 1793193310Simp */ 1794193310Simp if (vap->iv_opmode == IEEE80211_M_STA) { 1795193310Simp if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) { 1796193310Simp /* 1797193310Simp * Clear out the BSSID. If we reassociate to 1798193310Simp * the same AP, this will reinialize things 1799193310Simp * correctly... 1800193310Simp */ 1801193310Simp if (ic->ic_opmode == IEEE80211_M_STA && 1802193310Simp !(sc->sc_flags & BWI_F_STOP)) 1803193310Simp bwi_set_bssid(sc, bwi_zero_addr); 1804193310Simp } 1805193310Simp } 1806193310Simp 1807191762Simp if (vap->iv_opmode == IEEE80211_M_MONITOR) { 1808191762Simp /* Nothing to do */ 1809191762Simp } else if (nstate == IEEE80211_S_RUN) { 1810191762Simp bwi_set_bssid(sc, vap->iv_bss->ni_bssid); 1811191762Simp 1812191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 1813191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 1814191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 1815191762Simp 1816191762Simp /* Initial TX power calibration */ 1817191762Simp bwi_mac_calibrate_txpower(mac, BWI_TXPWR_INIT); 1818191762Simp#ifdef notyet 1819191762Simp sc->sc_txpwrcb_type = BWI_TXPWR_FORCE; 1820191762Simp#else 1821191762Simp sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; 1822191762Simp#endif 1823191762Simp 1824191762Simp callout_reset(&sc->sc_calib_ch, hz, bwi_calibrate, sc); 1825191762Simp } 1826191762Simpback: 1827191762Simp BWI_UNLOCK(sc); 1828191762Simp 1829191762Simp return error; 1830191762Simp} 1831191762Simp 1832191762Simpstatic int 1833191762Simpbwi_media_change(struct ifnet *ifp) 1834191762Simp{ 1835191762Simp int error = ieee80211_media_change(ifp); 1836191762Simp /* NB: only the fixed rate can change and that doesn't need a reset */ 1837191762Simp return (error == ENETRESET ? 0 : error); 1838191762Simp} 1839191762Simp 1840191762Simpstatic int 1841191762Simpbwi_dma_alloc(struct bwi_softc *sc) 1842191762Simp{ 1843191762Simp int error, i, has_txstats; 1844191762Simp bus_addr_t lowaddr = 0; 1845191762Simp bus_size_t tx_ring_sz, rx_ring_sz, desc_sz = 0; 1846191762Simp uint32_t txrx_ctrl_step = 0; 1847191762Simp 1848191762Simp has_txstats = 0; 1849191762Simp for (i = 0; i < sc->sc_nmac; ++i) { 1850191762Simp if (sc->sc_mac[i].mac_flags & BWI_MAC_F_HAS_TXSTATS) { 1851191762Simp has_txstats = 1; 1852191762Simp break; 1853191762Simp } 1854191762Simp } 1855191762Simp 1856191762Simp switch (sc->sc_bus_space) { 1857191762Simp case BWI_BUS_SPACE_30BIT: 1858191762Simp case BWI_BUS_SPACE_32BIT: 1859191762Simp if (sc->sc_bus_space == BWI_BUS_SPACE_30BIT) 1860191762Simp lowaddr = BWI_BUS_SPACE_MAXADDR; 1861191762Simp else 1862191762Simp lowaddr = BUS_SPACE_MAXADDR_32BIT; 1863191762Simp desc_sz = sizeof(struct bwi_desc32); 1864191762Simp txrx_ctrl_step = 0x20; 1865191762Simp 1866191762Simp sc->sc_init_tx_ring = bwi_init_tx_ring32; 1867191762Simp sc->sc_free_tx_ring = bwi_free_tx_ring32; 1868191762Simp sc->sc_init_rx_ring = bwi_init_rx_ring32; 1869191762Simp sc->sc_free_rx_ring = bwi_free_rx_ring32; 1870191762Simp sc->sc_setup_rxdesc = bwi_setup_rx_desc32; 1871191762Simp sc->sc_setup_txdesc = bwi_setup_tx_desc32; 1872191762Simp sc->sc_rxeof = bwi_rxeof32; 1873191762Simp sc->sc_start_tx = bwi_start_tx32; 1874191762Simp if (has_txstats) { 1875191762Simp sc->sc_init_txstats = bwi_init_txstats32; 1876191762Simp sc->sc_free_txstats = bwi_free_txstats32; 1877191762Simp sc->sc_txeof_status = bwi_txeof_status32; 1878191762Simp } 1879191762Simp break; 1880191762Simp 1881191762Simp case BWI_BUS_SPACE_64BIT: 1882191762Simp lowaddr = BUS_SPACE_MAXADDR; /* XXX */ 1883191762Simp desc_sz = sizeof(struct bwi_desc64); 1884191762Simp txrx_ctrl_step = 0x40; 1885191762Simp 1886191762Simp sc->sc_init_tx_ring = bwi_init_tx_ring64; 1887191762Simp sc->sc_free_tx_ring = bwi_free_tx_ring64; 1888191762Simp sc->sc_init_rx_ring = bwi_init_rx_ring64; 1889191762Simp sc->sc_free_rx_ring = bwi_free_rx_ring64; 1890191762Simp sc->sc_setup_rxdesc = bwi_setup_rx_desc64; 1891191762Simp sc->sc_setup_txdesc = bwi_setup_tx_desc64; 1892191762Simp sc->sc_rxeof = bwi_rxeof64; 1893191762Simp sc->sc_start_tx = bwi_start_tx64; 1894191762Simp if (has_txstats) { 1895191762Simp sc->sc_init_txstats = bwi_init_txstats64; 1896191762Simp sc->sc_free_txstats = bwi_free_txstats64; 1897191762Simp sc->sc_txeof_status = bwi_txeof_status64; 1898191762Simp } 1899191762Simp break; 1900191762Simp } 1901191762Simp 1902191762Simp KASSERT(lowaddr != 0, ("lowaddr zero")); 1903191762Simp KASSERT(desc_sz != 0, ("desc_sz zero")); 1904191762Simp KASSERT(txrx_ctrl_step != 0, ("txrx_ctrl_step zero")); 1905191762Simp 1906191762Simp tx_ring_sz = roundup(desc_sz * BWI_TX_NDESC, BWI_RING_ALIGN); 1907191762Simp rx_ring_sz = roundup(desc_sz * BWI_RX_NDESC, BWI_RING_ALIGN); 1908191762Simp 1909191762Simp /* 1910191762Simp * Create top level DMA tag 1911191762Simp */ 1912191762Simp error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */ 1913191762Simp BWI_ALIGN, 0, /* alignment, bounds */ 1914191762Simp lowaddr, /* lowaddr */ 1915191762Simp BUS_SPACE_MAXADDR, /* highaddr */ 1916191762Simp NULL, NULL, /* filter, filterarg */ 1917191762Simp MAXBSIZE, /* maxsize */ 1918191762Simp BUS_SPACE_UNRESTRICTED, /* nsegments */ 1919191762Simp BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1920191762Simp BUS_DMA_ALLOCNOW, /* flags */ 1921191762Simp NULL, NULL, /* lockfunc, lockarg */ 1922191762Simp &sc->sc_parent_dtag); 1923191762Simp if (error) { 1924191762Simp device_printf(sc->sc_dev, "can't create parent DMA tag\n"); 1925191762Simp return error; 1926191762Simp } 1927191762Simp 1928191762Simp#define TXRX_CTRL(idx) (BWI_TXRX_CTRL_BASE + (idx) * txrx_ctrl_step) 1929191762Simp 1930191762Simp /* 1931191762Simp * Create TX ring DMA stuffs 1932191762Simp */ 1933191762Simp error = bus_dma_tag_create(sc->sc_parent_dtag, 1934191762Simp BWI_RING_ALIGN, 0, 1935191762Simp BUS_SPACE_MAXADDR, 1936191762Simp BUS_SPACE_MAXADDR, 1937191762Simp NULL, NULL, 1938191762Simp tx_ring_sz, 1939191762Simp 1, 1940191762Simp BUS_SPACE_MAXSIZE_32BIT, 1941191762Simp BUS_DMA_ALLOCNOW, 1942191762Simp NULL, NULL, 1943191762Simp &sc->sc_txring_dtag); 1944191762Simp if (error) { 1945191762Simp device_printf(sc->sc_dev, "can't create TX ring DMA tag\n"); 1946191762Simp return error; 1947191762Simp } 1948191762Simp 1949191762Simp for (i = 0; i < BWI_TX_NRING; ++i) { 1950191762Simp error = bwi_dma_ring_alloc(sc, sc->sc_txring_dtag, 1951191762Simp &sc->sc_tx_rdata[i], tx_ring_sz, 1952191762Simp TXRX_CTRL(i)); 1953191762Simp if (error) { 1954191762Simp device_printf(sc->sc_dev, "%dth TX ring " 1955191762Simp "DMA alloc failed\n", i); 1956191762Simp return error; 1957191762Simp } 1958191762Simp } 1959191762Simp 1960191762Simp /* 1961191762Simp * Create RX ring DMA stuffs 1962191762Simp */ 1963191762Simp error = bus_dma_tag_create(sc->sc_parent_dtag, 1964191762Simp BWI_RING_ALIGN, 0, 1965191762Simp BUS_SPACE_MAXADDR, 1966191762Simp BUS_SPACE_MAXADDR, 1967191762Simp NULL, NULL, 1968191762Simp rx_ring_sz, 1969191762Simp 1, 1970191762Simp BUS_SPACE_MAXSIZE_32BIT, 1971191762Simp BUS_DMA_ALLOCNOW, 1972191762Simp NULL, NULL, 1973191762Simp &sc->sc_rxring_dtag); 1974191762Simp if (error) { 1975191762Simp device_printf(sc->sc_dev, "can't create RX ring DMA tag\n"); 1976191762Simp return error; 1977191762Simp } 1978191762Simp 1979191762Simp error = bwi_dma_ring_alloc(sc, sc->sc_rxring_dtag, &sc->sc_rx_rdata, 1980191762Simp rx_ring_sz, TXRX_CTRL(0)); 1981191762Simp if (error) { 1982191762Simp device_printf(sc->sc_dev, "RX ring DMA alloc failed\n"); 1983191762Simp return error; 1984191762Simp } 1985191762Simp 1986191762Simp if (has_txstats) { 1987191762Simp error = bwi_dma_txstats_alloc(sc, TXRX_CTRL(3), desc_sz); 1988191762Simp if (error) { 1989191762Simp device_printf(sc->sc_dev, 1990191762Simp "TX stats DMA alloc failed\n"); 1991191762Simp return error; 1992191762Simp } 1993191762Simp } 1994191762Simp 1995191762Simp#undef TXRX_CTRL 1996191762Simp 1997191762Simp return bwi_dma_mbuf_create(sc); 1998191762Simp} 1999191762Simp 2000191762Simpstatic void 2001191762Simpbwi_dma_free(struct bwi_softc *sc) 2002191762Simp{ 2003191762Simp if (sc->sc_txring_dtag != NULL) { 2004191762Simp int i; 2005191762Simp 2006191762Simp for (i = 0; i < BWI_TX_NRING; ++i) { 2007191762Simp struct bwi_ring_data *rd = &sc->sc_tx_rdata[i]; 2008191762Simp 2009191762Simp if (rd->rdata_desc != NULL) { 2010191762Simp bus_dmamap_unload(sc->sc_txring_dtag, 2011191762Simp rd->rdata_dmap); 2012191762Simp bus_dmamem_free(sc->sc_txring_dtag, 2013191762Simp rd->rdata_desc, 2014191762Simp rd->rdata_dmap); 2015191762Simp } 2016191762Simp } 2017191762Simp bus_dma_tag_destroy(sc->sc_txring_dtag); 2018191762Simp } 2019191762Simp 2020191762Simp if (sc->sc_rxring_dtag != NULL) { 2021191762Simp struct bwi_ring_data *rd = &sc->sc_rx_rdata; 2022191762Simp 2023191762Simp if (rd->rdata_desc != NULL) { 2024191762Simp bus_dmamap_unload(sc->sc_rxring_dtag, rd->rdata_dmap); 2025191762Simp bus_dmamem_free(sc->sc_rxring_dtag, rd->rdata_desc, 2026191762Simp rd->rdata_dmap); 2027191762Simp } 2028191762Simp bus_dma_tag_destroy(sc->sc_rxring_dtag); 2029191762Simp } 2030191762Simp 2031191762Simp bwi_dma_txstats_free(sc); 2032191762Simp bwi_dma_mbuf_destroy(sc, BWI_TX_NRING, 1); 2033191762Simp 2034191762Simp if (sc->sc_parent_dtag != NULL) 2035191762Simp bus_dma_tag_destroy(sc->sc_parent_dtag); 2036191762Simp} 2037191762Simp 2038191762Simpstatic int 2039191762Simpbwi_dma_ring_alloc(struct bwi_softc *sc, bus_dma_tag_t dtag, 2040191762Simp struct bwi_ring_data *rd, bus_size_t size, 2041191762Simp uint32_t txrx_ctrl) 2042191762Simp{ 2043191762Simp int error; 2044191762Simp 2045191762Simp error = bus_dmamem_alloc(dtag, &rd->rdata_desc, 2046191762Simp BUS_DMA_WAITOK | BUS_DMA_ZERO, 2047191762Simp &rd->rdata_dmap); 2048191762Simp if (error) { 2049191762Simp device_printf(sc->sc_dev, "can't allocate DMA mem\n"); 2050191762Simp return error; 2051191762Simp } 2052191762Simp 2053191762Simp error = bus_dmamap_load(dtag, rd->rdata_dmap, rd->rdata_desc, size, 2054191762Simp bwi_dma_ring_addr, &rd->rdata_paddr, 2055191762Simp BUS_DMA_NOWAIT); 2056191762Simp if (error) { 2057191762Simp device_printf(sc->sc_dev, "can't load DMA mem\n"); 2058191762Simp bus_dmamem_free(dtag, rd->rdata_desc, rd->rdata_dmap); 2059191762Simp rd->rdata_desc = NULL; 2060191762Simp return error; 2061191762Simp } 2062191762Simp 2063191762Simp rd->rdata_txrx_ctrl = txrx_ctrl; 2064191762Simp return 0; 2065191762Simp} 2066191762Simp 2067191762Simpstatic int 2068191762Simpbwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base, 2069191762Simp bus_size_t desc_sz) 2070191762Simp{ 2071191762Simp struct bwi_txstats_data *st; 2072191762Simp bus_size_t dma_size; 2073191762Simp int error; 2074191762Simp 2075191762Simp st = malloc(sizeof(*st), M_DEVBUF, M_NOWAIT | M_ZERO); 2076191762Simp if (st == NULL) { 2077191762Simp device_printf(sc->sc_dev, "can't allocate txstats data\n"); 2078191762Simp return ENOMEM; 2079191762Simp } 2080191762Simp sc->sc_txstats = st; 2081191762Simp 2082191762Simp /* 2083191762Simp * Create TX stats descriptor DMA stuffs 2084191762Simp */ 2085191762Simp dma_size = roundup(desc_sz * BWI_TXSTATS_NDESC, BWI_RING_ALIGN); 2086191762Simp 2087191762Simp error = bus_dma_tag_create(sc->sc_parent_dtag, 2088191762Simp BWI_RING_ALIGN, 2089191762Simp 0, 2090191762Simp BUS_SPACE_MAXADDR, 2091191762Simp BUS_SPACE_MAXADDR, 2092191762Simp NULL, NULL, 2093191762Simp dma_size, 2094191762Simp 1, 2095191762Simp BUS_SPACE_MAXSIZE_32BIT, 2096191762Simp BUS_DMA_ALLOCNOW, 2097191762Simp NULL, NULL, 2098191762Simp &st->stats_ring_dtag); 2099191762Simp if (error) { 2100191762Simp device_printf(sc->sc_dev, "can't create txstats ring " 2101191762Simp "DMA tag\n"); 2102191762Simp return error; 2103191762Simp } 2104191762Simp 2105191762Simp error = bus_dmamem_alloc(st->stats_ring_dtag, &st->stats_ring, 2106191762Simp BUS_DMA_WAITOK | BUS_DMA_ZERO, 2107191762Simp &st->stats_ring_dmap); 2108191762Simp if (error) { 2109191762Simp device_printf(sc->sc_dev, "can't allocate txstats ring " 2110191762Simp "DMA mem\n"); 2111191762Simp bus_dma_tag_destroy(st->stats_ring_dtag); 2112191762Simp st->stats_ring_dtag = NULL; 2113191762Simp return error; 2114191762Simp } 2115191762Simp 2116191762Simp error = bus_dmamap_load(st->stats_ring_dtag, st->stats_ring_dmap, 2117191762Simp st->stats_ring, dma_size, 2118191762Simp bwi_dma_ring_addr, &st->stats_ring_paddr, 2119191762Simp BUS_DMA_NOWAIT); 2120191762Simp if (error) { 2121191762Simp device_printf(sc->sc_dev, "can't load txstats ring DMA mem\n"); 2122191762Simp bus_dmamem_free(st->stats_ring_dtag, st->stats_ring, 2123191762Simp st->stats_ring_dmap); 2124191762Simp bus_dma_tag_destroy(st->stats_ring_dtag); 2125191762Simp st->stats_ring_dtag = NULL; 2126191762Simp return error; 2127191762Simp } 2128191762Simp 2129191762Simp /* 2130191762Simp * Create TX stats DMA stuffs 2131191762Simp */ 2132191762Simp dma_size = roundup(sizeof(struct bwi_txstats) * BWI_TXSTATS_NDESC, 2133191762Simp BWI_ALIGN); 2134191762Simp 2135191762Simp error = bus_dma_tag_create(sc->sc_parent_dtag, 2136191762Simp BWI_ALIGN, 2137191762Simp 0, 2138191762Simp BUS_SPACE_MAXADDR, 2139191762Simp BUS_SPACE_MAXADDR, 2140191762Simp NULL, NULL, 2141191762Simp dma_size, 2142191762Simp 1, 2143191762Simp BUS_SPACE_MAXSIZE_32BIT, 2144191762Simp BUS_DMA_ALLOCNOW, 2145191762Simp NULL, NULL, 2146191762Simp &st->stats_dtag); 2147191762Simp if (error) { 2148191762Simp device_printf(sc->sc_dev, "can't create txstats DMA tag\n"); 2149191762Simp return error; 2150191762Simp } 2151191762Simp 2152191762Simp error = bus_dmamem_alloc(st->stats_dtag, (void **)&st->stats, 2153191762Simp BUS_DMA_WAITOK | BUS_DMA_ZERO, 2154191762Simp &st->stats_dmap); 2155191762Simp if (error) { 2156191762Simp device_printf(sc->sc_dev, "can't allocate txstats DMA mem\n"); 2157191762Simp bus_dma_tag_destroy(st->stats_dtag); 2158191762Simp st->stats_dtag = NULL; 2159191762Simp return error; 2160191762Simp } 2161191762Simp 2162191762Simp error = bus_dmamap_load(st->stats_dtag, st->stats_dmap, st->stats, 2163191762Simp dma_size, bwi_dma_ring_addr, &st->stats_paddr, 2164191762Simp BUS_DMA_NOWAIT); 2165191762Simp if (error) { 2166191762Simp device_printf(sc->sc_dev, "can't load txstats DMA mem\n"); 2167191762Simp bus_dmamem_free(st->stats_dtag, st->stats, st->stats_dmap); 2168191762Simp bus_dma_tag_destroy(st->stats_dtag); 2169191762Simp st->stats_dtag = NULL; 2170191762Simp return error; 2171191762Simp } 2172191762Simp 2173191762Simp st->stats_ctrl_base = ctrl_base; 2174191762Simp return 0; 2175191762Simp} 2176191762Simp 2177191762Simpstatic void 2178191762Simpbwi_dma_txstats_free(struct bwi_softc *sc) 2179191762Simp{ 2180191762Simp struct bwi_txstats_data *st; 2181191762Simp 2182191762Simp if (sc->sc_txstats == NULL) 2183191762Simp return; 2184191762Simp st = sc->sc_txstats; 2185191762Simp 2186191762Simp if (st->stats_ring_dtag != NULL) { 2187191762Simp bus_dmamap_unload(st->stats_ring_dtag, st->stats_ring_dmap); 2188191762Simp bus_dmamem_free(st->stats_ring_dtag, st->stats_ring, 2189191762Simp st->stats_ring_dmap); 2190191762Simp bus_dma_tag_destroy(st->stats_ring_dtag); 2191191762Simp } 2192191762Simp 2193191762Simp if (st->stats_dtag != NULL) { 2194191762Simp bus_dmamap_unload(st->stats_dtag, st->stats_dmap); 2195191762Simp bus_dmamem_free(st->stats_dtag, st->stats, st->stats_dmap); 2196191762Simp bus_dma_tag_destroy(st->stats_dtag); 2197191762Simp } 2198191762Simp 2199191762Simp free(st, M_DEVBUF); 2200191762Simp} 2201191762Simp 2202191762Simpstatic void 2203191762Simpbwi_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error) 2204191762Simp{ 2205191762Simp KASSERT(nseg == 1, ("too many segments\n")); 2206191762Simp *((bus_addr_t *)arg) = seg->ds_addr; 2207191762Simp} 2208191762Simp 2209191762Simpstatic int 2210191762Simpbwi_dma_mbuf_create(struct bwi_softc *sc) 2211191762Simp{ 2212191762Simp struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; 2213191762Simp int i, j, k, ntx, error; 2214191762Simp 2215191762Simp /* 2216191762Simp * Create TX/RX mbuf DMA tag 2217191762Simp */ 2218191762Simp error = bus_dma_tag_create(sc->sc_parent_dtag, 2219191762Simp 1, 2220191762Simp 0, 2221191762Simp BUS_SPACE_MAXADDR, 2222191762Simp BUS_SPACE_MAXADDR, 2223191762Simp NULL, NULL, 2224191762Simp MCLBYTES, 2225191762Simp 1, 2226191762Simp BUS_SPACE_MAXSIZE_32BIT, 2227191762Simp BUS_DMA_ALLOCNOW, 2228191762Simp NULL, NULL, 2229191762Simp &sc->sc_buf_dtag); 2230191762Simp if (error) { 2231191762Simp device_printf(sc->sc_dev, "can't create mbuf DMA tag\n"); 2232191762Simp return error; 2233191762Simp } 2234191762Simp 2235191762Simp ntx = 0; 2236191762Simp 2237191762Simp /* 2238191762Simp * Create TX mbuf DMA map 2239191762Simp */ 2240191762Simp for (i = 0; i < BWI_TX_NRING; ++i) { 2241191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; 2242191762Simp 2243191762Simp for (j = 0; j < BWI_TX_NDESC; ++j) { 2244191762Simp error = bus_dmamap_create(sc->sc_buf_dtag, 0, 2245191762Simp &tbd->tbd_buf[j].tb_dmap); 2246191762Simp if (error) { 2247191762Simp device_printf(sc->sc_dev, "can't create " 2248191762Simp "%dth tbd, %dth DMA map\n", i, j); 2249191762Simp 2250191762Simp ntx = i; 2251191762Simp for (k = 0; k < j; ++k) { 2252191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, 2253191762Simp tbd->tbd_buf[k].tb_dmap); 2254191762Simp } 2255191762Simp goto fail; 2256191762Simp } 2257191762Simp } 2258191762Simp } 2259191762Simp ntx = BWI_TX_NRING; 2260191762Simp 2261191762Simp /* 2262191762Simp * Create RX mbuf DMA map and a spare DMA map 2263191762Simp */ 2264191762Simp error = bus_dmamap_create(sc->sc_buf_dtag, 0, 2265191762Simp &rbd->rbd_tmp_dmap); 2266191762Simp if (error) { 2267191762Simp device_printf(sc->sc_dev, 2268191762Simp "can't create spare RX buf DMA map\n"); 2269191762Simp goto fail; 2270191762Simp } 2271191762Simp 2272191762Simp for (j = 0; j < BWI_RX_NDESC; ++j) { 2273191762Simp error = bus_dmamap_create(sc->sc_buf_dtag, 0, 2274191762Simp &rbd->rbd_buf[j].rb_dmap); 2275191762Simp if (error) { 2276191762Simp device_printf(sc->sc_dev, "can't create %dth " 2277191762Simp "RX buf DMA map\n", j); 2278191762Simp 2279191762Simp for (k = 0; k < j; ++k) { 2280191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, 2281191762Simp rbd->rbd_buf[j].rb_dmap); 2282191762Simp } 2283191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, 2284191762Simp rbd->rbd_tmp_dmap); 2285191762Simp goto fail; 2286191762Simp } 2287191762Simp } 2288191762Simp 2289191762Simp return 0; 2290191762Simpfail: 2291191762Simp bwi_dma_mbuf_destroy(sc, ntx, 0); 2292191762Simp return error; 2293191762Simp} 2294191762Simp 2295191762Simpstatic void 2296191762Simpbwi_dma_mbuf_destroy(struct bwi_softc *sc, int ntx, int nrx) 2297191762Simp{ 2298191762Simp int i, j; 2299191762Simp 2300191762Simp if (sc->sc_buf_dtag == NULL) 2301191762Simp return; 2302191762Simp 2303191762Simp for (i = 0; i < ntx; ++i) { 2304191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; 2305191762Simp 2306191762Simp for (j = 0; j < BWI_TX_NDESC; ++j) { 2307191762Simp struct bwi_txbuf *tb = &tbd->tbd_buf[j]; 2308191762Simp 2309191762Simp if (tb->tb_mbuf != NULL) { 2310191762Simp bus_dmamap_unload(sc->sc_buf_dtag, 2311191762Simp tb->tb_dmap); 2312191762Simp m_freem(tb->tb_mbuf); 2313191762Simp } 2314191762Simp if (tb->tb_ni != NULL) 2315191762Simp ieee80211_free_node(tb->tb_ni); 2316191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, tb->tb_dmap); 2317191762Simp } 2318191762Simp } 2319191762Simp 2320191762Simp if (nrx) { 2321191762Simp struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; 2322191762Simp 2323191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, rbd->rbd_tmp_dmap); 2324191762Simp for (j = 0; j < BWI_RX_NDESC; ++j) { 2325191762Simp struct bwi_rxbuf *rb = &rbd->rbd_buf[j]; 2326191762Simp 2327191762Simp if (rb->rb_mbuf != NULL) { 2328191762Simp bus_dmamap_unload(sc->sc_buf_dtag, 2329191762Simp rb->rb_dmap); 2330191762Simp m_freem(rb->rb_mbuf); 2331191762Simp } 2332191762Simp bus_dmamap_destroy(sc->sc_buf_dtag, rb->rb_dmap); 2333191762Simp } 2334191762Simp } 2335191762Simp 2336191762Simp bus_dma_tag_destroy(sc->sc_buf_dtag); 2337191762Simp sc->sc_buf_dtag = NULL; 2338191762Simp} 2339191762Simp 2340191762Simpstatic void 2341191762Simpbwi_enable_intrs(struct bwi_softc *sc, uint32_t enable_intrs) 2342191762Simp{ 2343191762Simp CSR_SETBITS_4(sc, BWI_MAC_INTR_MASK, enable_intrs); 2344191762Simp} 2345191762Simp 2346191762Simpstatic void 2347191762Simpbwi_disable_intrs(struct bwi_softc *sc, uint32_t disable_intrs) 2348191762Simp{ 2349191762Simp CSR_CLRBITS_4(sc, BWI_MAC_INTR_MASK, disable_intrs); 2350191762Simp} 2351191762Simp 2352191762Simpstatic int 2353191762Simpbwi_init_tx_ring32(struct bwi_softc *sc, int ring_idx) 2354191762Simp{ 2355191762Simp struct bwi_ring_data *rd; 2356191762Simp struct bwi_txbuf_data *tbd; 2357191762Simp uint32_t val, addr_hi, addr_lo; 2358191762Simp 2359191762Simp KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx)); 2360191762Simp rd = &sc->sc_tx_rdata[ring_idx]; 2361191762Simp tbd = &sc->sc_tx_bdata[ring_idx]; 2362191762Simp 2363191762Simp tbd->tbd_idx = 0; 2364191762Simp tbd->tbd_used = 0; 2365191762Simp 2366191762Simp bzero(rd->rdata_desc, sizeof(struct bwi_desc32) * BWI_TX_NDESC); 2367191762Simp bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap, 2368191762Simp BUS_DMASYNC_PREWRITE); 2369191762Simp 2370191762Simp addr_lo = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); 2371191762Simp addr_hi = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); 2372191762Simp 2373191762Simp val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | 2374191762Simp __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, 2375191762Simp BWI_TXRX32_RINGINFO_FUNC_MASK); 2376191762Simp CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, val); 2377191762Simp 2378191762Simp val = __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | 2379191762Simp BWI_TXRX32_CTRL_ENABLE; 2380191762Simp CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, val); 2381191762Simp 2382191762Simp return 0; 2383191762Simp} 2384191762Simp 2385191762Simpstatic void 2386191762Simpbwi_init_rxdesc_ring32(struct bwi_softc *sc, uint32_t ctrl_base, 2387191762Simp bus_addr_t paddr, int hdr_size, int ndesc) 2388191762Simp{ 2389191762Simp uint32_t val, addr_hi, addr_lo; 2390191762Simp 2391191762Simp addr_lo = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); 2392191762Simp addr_hi = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); 2393191762Simp 2394191762Simp val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | 2395191762Simp __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, 2396191762Simp BWI_TXRX32_RINGINFO_FUNC_MASK); 2397191762Simp CSR_WRITE_4(sc, ctrl_base + BWI_RX32_RINGINFO, val); 2398191762Simp 2399191762Simp val = __SHIFTIN(hdr_size, BWI_RX32_CTRL_HDRSZ_MASK) | 2400191762Simp __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | 2401191762Simp BWI_TXRX32_CTRL_ENABLE; 2402191762Simp CSR_WRITE_4(sc, ctrl_base + BWI_RX32_CTRL, val); 2403191762Simp 2404191762Simp CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, 2405191762Simp (ndesc - 1) * sizeof(struct bwi_desc32)); 2406191762Simp} 2407191762Simp 2408191762Simpstatic int 2409191762Simpbwi_init_rx_ring32(struct bwi_softc *sc) 2410191762Simp{ 2411191762Simp struct bwi_ring_data *rd = &sc->sc_rx_rdata; 2412191762Simp int i, error; 2413191762Simp 2414191762Simp sc->sc_rx_bdata.rbd_idx = 0; 2415191762Simp 2416191762Simp for (i = 0; i < BWI_RX_NDESC; ++i) { 2417191762Simp error = bwi_newbuf(sc, i, 1); 2418191762Simp if (error) { 2419191762Simp device_printf(sc->sc_dev, 2420191762Simp "can't allocate %dth RX buffer\n", i); 2421191762Simp return error; 2422191762Simp } 2423191762Simp } 2424191762Simp bus_dmamap_sync(sc->sc_rxring_dtag, rd->rdata_dmap, 2425191762Simp BUS_DMASYNC_PREWRITE); 2426191762Simp 2427191762Simp bwi_init_rxdesc_ring32(sc, rd->rdata_txrx_ctrl, rd->rdata_paddr, 2428191762Simp sizeof(struct bwi_rxbuf_hdr), BWI_RX_NDESC); 2429191762Simp return 0; 2430191762Simp} 2431191762Simp 2432191762Simpstatic int 2433191762Simpbwi_init_txstats32(struct bwi_softc *sc) 2434191762Simp{ 2435191762Simp struct bwi_txstats_data *st = sc->sc_txstats; 2436191762Simp bus_addr_t stats_paddr; 2437191762Simp int i; 2438191762Simp 2439191762Simp bzero(st->stats, BWI_TXSTATS_NDESC * sizeof(struct bwi_txstats)); 2440191762Simp bus_dmamap_sync(st->stats_dtag, st->stats_dmap, BUS_DMASYNC_PREWRITE); 2441191762Simp 2442191762Simp st->stats_idx = 0; 2443191762Simp 2444191762Simp stats_paddr = st->stats_paddr; 2445191762Simp for (i = 0; i < BWI_TXSTATS_NDESC; ++i) { 2446191762Simp bwi_setup_desc32(sc, st->stats_ring, BWI_TXSTATS_NDESC, i, 2447191762Simp stats_paddr, sizeof(struct bwi_txstats), 0); 2448191762Simp stats_paddr += sizeof(struct bwi_txstats); 2449191762Simp } 2450191762Simp bus_dmamap_sync(st->stats_ring_dtag, st->stats_ring_dmap, 2451191762Simp BUS_DMASYNC_PREWRITE); 2452191762Simp 2453191762Simp bwi_init_rxdesc_ring32(sc, st->stats_ctrl_base, 2454191762Simp st->stats_ring_paddr, 0, BWI_TXSTATS_NDESC); 2455191762Simp return 0; 2456191762Simp} 2457191762Simp 2458191762Simpstatic void 2459191762Simpbwi_setup_rx_desc32(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, 2460191762Simp int buf_len) 2461191762Simp{ 2462191762Simp struct bwi_ring_data *rd = &sc->sc_rx_rdata; 2463191762Simp 2464191762Simp KASSERT(buf_idx < BWI_RX_NDESC, ("buf_idx %d", buf_idx)); 2465191762Simp bwi_setup_desc32(sc, rd->rdata_desc, BWI_RX_NDESC, buf_idx, 2466191762Simp paddr, buf_len, 0); 2467191762Simp} 2468191762Simp 2469191762Simpstatic void 2470191762Simpbwi_setup_tx_desc32(struct bwi_softc *sc, struct bwi_ring_data *rd, 2471191762Simp int buf_idx, bus_addr_t paddr, int buf_len) 2472191762Simp{ 2473191762Simp KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx)); 2474191762Simp bwi_setup_desc32(sc, rd->rdata_desc, BWI_TX_NDESC, buf_idx, 2475191762Simp paddr, buf_len, 1); 2476191762Simp} 2477191762Simp 2478191762Simpstatic int 2479191762Simpbwi_init_tx_ring64(struct bwi_softc *sc, int ring_idx) 2480191762Simp{ 2481191762Simp /* TODO:64 */ 2482191762Simp return EOPNOTSUPP; 2483191762Simp} 2484191762Simp 2485191762Simpstatic int 2486191762Simpbwi_init_rx_ring64(struct bwi_softc *sc) 2487191762Simp{ 2488191762Simp /* TODO:64 */ 2489191762Simp return EOPNOTSUPP; 2490191762Simp} 2491191762Simp 2492191762Simpstatic int 2493191762Simpbwi_init_txstats64(struct bwi_softc *sc) 2494191762Simp{ 2495191762Simp /* TODO:64 */ 2496191762Simp return EOPNOTSUPP; 2497191762Simp} 2498191762Simp 2499191762Simpstatic void 2500191762Simpbwi_setup_rx_desc64(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, 2501191762Simp int buf_len) 2502191762Simp{ 2503191762Simp /* TODO:64 */ 2504191762Simp} 2505191762Simp 2506191762Simpstatic void 2507191762Simpbwi_setup_tx_desc64(struct bwi_softc *sc, struct bwi_ring_data *rd, 2508191762Simp int buf_idx, bus_addr_t paddr, int buf_len) 2509191762Simp{ 2510191762Simp /* TODO:64 */ 2511191762Simp} 2512191762Simp 2513191762Simpstatic void 2514191762Simpbwi_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg, 2515191762Simp bus_size_t mapsz __unused, int error) 2516191762Simp{ 2517191762Simp if (!error) { 2518191762Simp KASSERT(nseg == 1, ("too many segments(%d)\n", nseg)); 2519191762Simp *((bus_addr_t *)arg) = seg->ds_addr; 2520191762Simp } 2521191762Simp} 2522191762Simp 2523191762Simpstatic int 2524191762Simpbwi_newbuf(struct bwi_softc *sc, int buf_idx, int init) 2525191762Simp{ 2526191762Simp struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; 2527191762Simp struct bwi_rxbuf *rxbuf = &rbd->rbd_buf[buf_idx]; 2528191762Simp struct bwi_rxbuf_hdr *hdr; 2529191762Simp bus_dmamap_t map; 2530191762Simp bus_addr_t paddr; 2531191762Simp struct mbuf *m; 2532191762Simp int error; 2533191762Simp 2534191762Simp KASSERT(buf_idx < BWI_RX_NDESC, ("buf_idx %d", buf_idx)); 2535191762Simp 2536248078Smarius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2537191762Simp if (m == NULL) { 2538191762Simp error = ENOBUFS; 2539191762Simp 2540191762Simp /* 2541191762Simp * If the NIC is up and running, we need to: 2542191762Simp * - Clear RX buffer's header. 2543191762Simp * - Restore RX descriptor settings. 2544191762Simp */ 2545191762Simp if (init) 2546191762Simp return error; 2547191762Simp else 2548191762Simp goto back; 2549191762Simp } 2550191762Simp m->m_len = m->m_pkthdr.len = MCLBYTES; 2551191762Simp 2552191762Simp /* 2553191762Simp * Try to load RX buf into temporary DMA map 2554191762Simp */ 2555191762Simp error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, rbd->rbd_tmp_dmap, m, 2556191762Simp bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); 2557191762Simp if (error) { 2558191762Simp m_freem(m); 2559191762Simp 2560191762Simp /* 2561191762Simp * See the comment above 2562191762Simp */ 2563191762Simp if (init) 2564191762Simp return error; 2565191762Simp else 2566191762Simp goto back; 2567191762Simp } 2568191762Simp 2569191762Simp if (!init) 2570191762Simp bus_dmamap_unload(sc->sc_buf_dtag, rxbuf->rb_dmap); 2571191762Simp rxbuf->rb_mbuf = m; 2572191762Simp rxbuf->rb_paddr = paddr; 2573191762Simp 2574191762Simp /* 2575191762Simp * Swap RX buf's DMA map with the loaded temporary one 2576191762Simp */ 2577191762Simp map = rxbuf->rb_dmap; 2578191762Simp rxbuf->rb_dmap = rbd->rbd_tmp_dmap; 2579191762Simp rbd->rbd_tmp_dmap = map; 2580191762Simp 2581191762Simpback: 2582191762Simp /* 2583191762Simp * Clear RX buf header 2584191762Simp */ 2585191762Simp hdr = mtod(rxbuf->rb_mbuf, struct bwi_rxbuf_hdr *); 2586191762Simp bzero(hdr, sizeof(*hdr)); 2587191762Simp bus_dmamap_sync(sc->sc_buf_dtag, rxbuf->rb_dmap, BUS_DMASYNC_PREWRITE); 2588191762Simp 2589191762Simp /* 2590191762Simp * Setup RX buf descriptor 2591191762Simp */ 2592191762Simp sc->sc_setup_rxdesc(sc, buf_idx, rxbuf->rb_paddr, 2593191762Simp rxbuf->rb_mbuf->m_len - sizeof(*hdr)); 2594191762Simp return error; 2595191762Simp} 2596191762Simp 2597191762Simpstatic void 2598191762Simpbwi_set_addr_filter(struct bwi_softc *sc, uint16_t addr_ofs, 2599191762Simp const uint8_t *addr) 2600191762Simp{ 2601191762Simp int i; 2602191762Simp 2603191762Simp CSR_WRITE_2(sc, BWI_ADDR_FILTER_CTRL, 2604191762Simp BWI_ADDR_FILTER_CTRL_SET | addr_ofs); 2605191762Simp 2606191762Simp for (i = 0; i < (IEEE80211_ADDR_LEN / 2); ++i) { 2607191762Simp uint16_t addr_val; 2608191762Simp 2609191762Simp addr_val = (uint16_t)addr[i * 2] | 2610191762Simp (((uint16_t)addr[(i * 2) + 1]) << 8); 2611191762Simp CSR_WRITE_2(sc, BWI_ADDR_FILTER_DATA, addr_val); 2612191762Simp } 2613191762Simp} 2614191762Simp 2615191762Simpstatic int 2616191762Simpbwi_rxeof(struct bwi_softc *sc, int end_idx) 2617191762Simp{ 2618191762Simp struct bwi_ring_data *rd = &sc->sc_rx_rdata; 2619191762Simp struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; 2620191762Simp struct ifnet *ifp = sc->sc_ifp; 2621191762Simp struct ieee80211com *ic = ifp->if_l2com; 2622191762Simp int idx, rx_data = 0; 2623191762Simp 2624191762Simp idx = rbd->rbd_idx; 2625191762Simp while (idx != end_idx) { 2626191762Simp struct bwi_rxbuf *rb = &rbd->rbd_buf[idx]; 2627191762Simp struct bwi_rxbuf_hdr *hdr; 2628191762Simp struct ieee80211_frame_min *wh; 2629191762Simp struct ieee80211_node *ni; 2630191762Simp struct mbuf *m; 2631234753Sdim uint32_t plcp; 2632191762Simp uint16_t flags2; 2633191762Simp int buflen, wh_ofs, hdr_extra, rssi, noise, type, rate; 2634191762Simp 2635191762Simp m = rb->rb_mbuf; 2636191762Simp bus_dmamap_sync(sc->sc_buf_dtag, rb->rb_dmap, 2637191762Simp BUS_DMASYNC_POSTREAD); 2638191762Simp 2639191762Simp if (bwi_newbuf(sc, idx, 0)) { 2640191762Simp ifp->if_ierrors++; 2641191762Simp goto next; 2642191762Simp } 2643191762Simp 2644191762Simp hdr = mtod(m, struct bwi_rxbuf_hdr *); 2645191762Simp flags2 = le16toh(hdr->rxh_flags2); 2646191762Simp 2647191762Simp hdr_extra = 0; 2648191762Simp if (flags2 & BWI_RXH_F2_TYPE2FRAME) 2649191762Simp hdr_extra = 2; 2650191762Simp wh_ofs = hdr_extra + 6; /* XXX magic number */ 2651191762Simp 2652191762Simp buflen = le16toh(hdr->rxh_buflen); 2653191762Simp if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { 2654191762Simp if_printf(ifp, "%s: zero length data, hdr_extra %d\n", 2655191762Simp __func__, hdr_extra); 2656191762Simp ifp->if_ierrors++; 2657191762Simp m_freem(m); 2658191762Simp goto next; 2659191762Simp } 2660191762Simp 2661234753Sdim bcopy((uint8_t *)(hdr + 1) + hdr_extra, &plcp, sizeof(plcp)); 2662191762Simp rssi = bwi_calc_rssi(sc, hdr); 2663191762Simp noise = bwi_calc_noise(sc); 2664191762Simp 2665191762Simp m->m_pkthdr.rcvif = ifp; 2666191762Simp m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); 2667191762Simp m_adj(m, sizeof(*hdr) + wh_ofs); 2668191762Simp 2669191762Simp if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM) 2670234753Sdim rate = bwi_plcp2rate(plcp, IEEE80211_T_OFDM); 2671191762Simp else 2672234753Sdim rate = bwi_plcp2rate(plcp, IEEE80211_T_CCK); 2673191762Simp 2674191762Simp /* RX radio tap */ 2675192468Ssam if (ieee80211_radiotap_active(ic)) 2676234753Sdim bwi_rx_radiotap(sc, m, hdr, &plcp, rate, rssi, noise); 2677191762Simp 2678191762Simp m_adj(m, -IEEE80211_CRC_LEN); 2679191762Simp 2680191762Simp BWI_UNLOCK(sc); 2681191762Simp 2682191762Simp wh = mtod(m, struct ieee80211_frame_min *); 2683191762Simp ni = ieee80211_find_rxnode(ic, wh); 2684191762Simp if (ni != NULL) { 2685192468Ssam type = ieee80211_input(ni, m, rssi - noise, noise); 2686191762Simp ieee80211_free_node(ni); 2687191762Simp } else 2688192468Ssam type = ieee80211_input_all(ic, m, rssi - noise, noise); 2689191762Simp if (type == IEEE80211_FC0_TYPE_DATA) { 2690191762Simp rx_data = 1; 2691191762Simp sc->sc_rx_rate = rate; 2692191762Simp } 2693191762Simp 2694191762Simp BWI_LOCK(sc); 2695191762Simpnext: 2696191762Simp idx = (idx + 1) % BWI_RX_NDESC; 2697191762Simp 2698191762Simp if (sc->sc_flags & BWI_F_STOP) { 2699191762Simp /* 2700191762Simp * Take the fast lane, don't do 2701191762Simp * any damage to softc 2702191762Simp */ 2703191762Simp return -1; 2704191762Simp } 2705191762Simp } 2706191762Simp 2707191762Simp rbd->rbd_idx = idx; 2708191762Simp bus_dmamap_sync(sc->sc_rxring_dtag, rd->rdata_dmap, 2709191762Simp BUS_DMASYNC_PREWRITE); 2710191762Simp 2711191762Simp return rx_data; 2712191762Simp} 2713191762Simp 2714191762Simpstatic int 2715191762Simpbwi_rxeof32(struct bwi_softc *sc) 2716191762Simp{ 2717191762Simp uint32_t val, rx_ctrl; 2718191762Simp int end_idx, rx_data; 2719191762Simp 2720191762Simp rx_ctrl = sc->sc_rx_rdata.rdata_txrx_ctrl; 2721191762Simp 2722191762Simp val = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); 2723191762Simp end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / 2724191762Simp sizeof(struct bwi_desc32); 2725191762Simp 2726191762Simp rx_data = bwi_rxeof(sc, end_idx); 2727191762Simp if (rx_data >= 0) { 2728191762Simp CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_INDEX, 2729191762Simp end_idx * sizeof(struct bwi_desc32)); 2730191762Simp } 2731191762Simp return rx_data; 2732191762Simp} 2733191762Simp 2734191762Simpstatic int 2735191762Simpbwi_rxeof64(struct bwi_softc *sc) 2736191762Simp{ 2737191762Simp /* TODO:64 */ 2738191762Simp return 0; 2739191762Simp} 2740191762Simp 2741191762Simpstatic void 2742191762Simpbwi_reset_rx_ring32(struct bwi_softc *sc, uint32_t rx_ctrl) 2743191762Simp{ 2744191762Simp int i; 2745191762Simp 2746191762Simp CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_CTRL, 0); 2747191762Simp 2748191762Simp#define NRETRY 10 2749191762Simp 2750191762Simp for (i = 0; i < NRETRY; ++i) { 2751191762Simp uint32_t status; 2752191762Simp 2753191762Simp status = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); 2754191762Simp if (__SHIFTOUT(status, BWI_RX32_STATUS_STATE_MASK) == 2755191762Simp BWI_RX32_STATUS_STATE_DISABLED) 2756191762Simp break; 2757191762Simp 2758191762Simp DELAY(1000); 2759191762Simp } 2760191762Simp if (i == NRETRY) 2761191762Simp device_printf(sc->sc_dev, "reset rx ring timedout\n"); 2762191762Simp 2763191762Simp#undef NRETRY 2764191762Simp 2765191762Simp CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_RINGINFO, 0); 2766191762Simp} 2767191762Simp 2768191762Simpstatic void 2769191762Simpbwi_free_txstats32(struct bwi_softc *sc) 2770191762Simp{ 2771191762Simp bwi_reset_rx_ring32(sc, sc->sc_txstats->stats_ctrl_base); 2772191762Simp} 2773191762Simp 2774191762Simpstatic void 2775191762Simpbwi_free_rx_ring32(struct bwi_softc *sc) 2776191762Simp{ 2777191762Simp struct bwi_ring_data *rd = &sc->sc_rx_rdata; 2778191762Simp struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; 2779191762Simp int i; 2780191762Simp 2781191762Simp bwi_reset_rx_ring32(sc, rd->rdata_txrx_ctrl); 2782191762Simp 2783191762Simp for (i = 0; i < BWI_RX_NDESC; ++i) { 2784191762Simp struct bwi_rxbuf *rb = &rbd->rbd_buf[i]; 2785191762Simp 2786191762Simp if (rb->rb_mbuf != NULL) { 2787191762Simp bus_dmamap_unload(sc->sc_buf_dtag, rb->rb_dmap); 2788191762Simp m_freem(rb->rb_mbuf); 2789191762Simp rb->rb_mbuf = NULL; 2790191762Simp } 2791191762Simp } 2792191762Simp} 2793191762Simp 2794191762Simpstatic void 2795191762Simpbwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) 2796191762Simp{ 2797191762Simp struct bwi_ring_data *rd; 2798191762Simp struct bwi_txbuf_data *tbd; 2799191762Simp struct ifnet *ifp = sc->sc_ifp; 2800191762Simp uint32_t state, val; 2801191762Simp int i; 2802191762Simp 2803191762Simp KASSERT(ring_idx < BWI_TX_NRING, ("ring_idx %d", ring_idx)); 2804191762Simp rd = &sc->sc_tx_rdata[ring_idx]; 2805191762Simp tbd = &sc->sc_tx_bdata[ring_idx]; 2806191762Simp 2807191762Simp#define NRETRY 10 2808191762Simp 2809191762Simp for (i = 0; i < NRETRY; ++i) { 2810191762Simp val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); 2811191762Simp state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); 2812191762Simp if (state == BWI_TX32_STATUS_STATE_DISABLED || 2813191762Simp state == BWI_TX32_STATUS_STATE_IDLE || 2814191762Simp state == BWI_TX32_STATUS_STATE_STOPPED) 2815191762Simp break; 2816191762Simp 2817191762Simp DELAY(1000); 2818191762Simp } 2819191762Simp if (i == NRETRY) { 2820191762Simp if_printf(ifp, "%s: wait for TX ring(%d) stable timed out\n", 2821191762Simp __func__, ring_idx); 2822191762Simp } 2823191762Simp 2824191762Simp CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); 2825191762Simp for (i = 0; i < NRETRY; ++i) { 2826191762Simp val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); 2827191762Simp state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); 2828191762Simp if (state == BWI_TX32_STATUS_STATE_DISABLED) 2829191762Simp break; 2830191762Simp 2831191762Simp DELAY(1000); 2832191762Simp } 2833191762Simp if (i == NRETRY) 2834191762Simp if_printf(ifp, "%s: reset TX ring (%d) timed out\n", 2835191762Simp __func__, ring_idx); 2836191762Simp 2837191762Simp#undef NRETRY 2838191762Simp 2839191762Simp DELAY(1000); 2840191762Simp 2841191762Simp CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0); 2842191762Simp 2843191762Simp for (i = 0; i < BWI_TX_NDESC; ++i) { 2844191762Simp struct bwi_txbuf *tb = &tbd->tbd_buf[i]; 2845191762Simp 2846191762Simp if (tb->tb_mbuf != NULL) { 2847191762Simp bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap); 2848191762Simp m_freem(tb->tb_mbuf); 2849191762Simp tb->tb_mbuf = NULL; 2850191762Simp } 2851191762Simp if (tb->tb_ni != NULL) { 2852191762Simp ieee80211_free_node(tb->tb_ni); 2853191762Simp tb->tb_ni = NULL; 2854191762Simp } 2855191762Simp } 2856191762Simp} 2857191762Simp 2858191762Simpstatic void 2859191762Simpbwi_free_txstats64(struct bwi_softc *sc) 2860191762Simp{ 2861191762Simp /* TODO:64 */ 2862191762Simp} 2863191762Simp 2864191762Simpstatic void 2865191762Simpbwi_free_rx_ring64(struct bwi_softc *sc) 2866191762Simp{ 2867191762Simp /* TODO:64 */ 2868191762Simp} 2869191762Simp 2870191762Simpstatic void 2871191762Simpbwi_free_tx_ring64(struct bwi_softc *sc, int ring_idx) 2872191762Simp{ 2873191762Simp /* TODO:64 */ 2874191762Simp} 2875191762Simp 2876191762Simp/* XXX does not belong here */ 2877191762Simp#define IEEE80211_OFDM_PLCP_RATE_MASK __BITS(3, 0) 2878191762Simp#define IEEE80211_OFDM_PLCP_LEN_MASK __BITS(16, 5) 2879191762Simp 2880191762Simpstatic __inline void 2881191762Simpbwi_ofdm_plcp_header(uint32_t *plcp0, int pkt_len, uint8_t rate) 2882191762Simp{ 2883191762Simp uint32_t plcp; 2884191762Simp 2885191762Simp plcp = __SHIFTIN(ieee80211_rate2plcp(rate, IEEE80211_T_OFDM), 2886191762Simp IEEE80211_OFDM_PLCP_RATE_MASK) | 2887191762Simp __SHIFTIN(pkt_len, IEEE80211_OFDM_PLCP_LEN_MASK); 2888191762Simp *plcp0 = htole32(plcp); 2889191762Simp} 2890191762Simp 2891191762Simpstatic __inline void 2892191762Simpbwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *plcp, int pkt_len, 2893191762Simp uint8_t rate) 2894191762Simp{ 2895191762Simp int len, service, pkt_bitlen; 2896191762Simp 2897191762Simp pkt_bitlen = pkt_len * NBBY; 2898191762Simp len = howmany(pkt_bitlen * 2, rate); 2899191762Simp 2900191762Simp service = IEEE80211_PLCP_SERVICE_LOCKED; 2901191762Simp if (rate == (11 * 2)) { 2902191762Simp int pkt_bitlen1; 2903191762Simp 2904191762Simp /* 2905191762Simp * PLCP service field needs to be adjusted, 2906191762Simp * if TX rate is 11Mbytes/s 2907191762Simp */ 2908191762Simp pkt_bitlen1 = len * 11; 2909191762Simp if (pkt_bitlen1 - pkt_bitlen >= NBBY) 2910191762Simp service |= IEEE80211_PLCP_SERVICE_LENEXT7; 2911191762Simp } 2912191762Simp 2913191762Simp plcp->i_signal = ieee80211_rate2plcp(rate, IEEE80211_T_CCK); 2914191762Simp plcp->i_service = service; 2915191762Simp plcp->i_length = htole16(len); 2916191762Simp /* NOTE: do NOT touch i_crc */ 2917191762Simp} 2918191762Simp 2919191762Simpstatic __inline void 2920191762Simpbwi_plcp_header(const struct ieee80211_rate_table *rt, 2921191762Simp void *plcp, int pkt_len, uint8_t rate) 2922191762Simp{ 2923191762Simp enum ieee80211_phytype modtype; 2924191762Simp 2925191762Simp /* 2926191762Simp * Assume caller has zeroed 'plcp' 2927191762Simp */ 2928191762Simp modtype = ieee80211_rate2phytype(rt, rate); 2929191762Simp if (modtype == IEEE80211_T_OFDM) 2930191762Simp bwi_ofdm_plcp_header(plcp, pkt_len, rate); 2931191762Simp else if (modtype == IEEE80211_T_DS) 2932191762Simp bwi_ds_plcp_header(plcp, pkt_len, rate); 2933191762Simp else 2934191762Simp panic("unsupport modulation type %u\n", modtype); 2935191762Simp} 2936191762Simp 2937191762Simpstatic int 2938191762Simpbwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, 2939191762Simp struct ieee80211_node *ni) 2940191762Simp{ 2941191762Simp struct ieee80211vap *vap = ni->ni_vap; 2942191762Simp struct ifnet *ifp = sc->sc_ifp; 2943191762Simp struct ieee80211com *ic = ifp->if_l2com; 2944191762Simp struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; 2945191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; 2946191762Simp struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; 2947191762Simp struct bwi_mac *mac; 2948191762Simp struct bwi_txbuf_hdr *hdr; 2949191762Simp struct ieee80211_frame *wh; 2950191762Simp const struct ieee80211_txparam *tp; 2951191762Simp uint8_t rate, rate_fb; 2952191762Simp uint32_t mac_ctrl; 2953191762Simp uint16_t phy_ctrl; 2954191762Simp bus_addr_t paddr; 2955191762Simp int type, ismcast, pkt_len, error, rix; 2956191762Simp#if 0 2957191762Simp const uint8_t *p; 2958191762Simp int i; 2959191762Simp#endif 2960191762Simp 2961191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 2962191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 2963191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 2964191762Simp 2965191762Simp wh = mtod(m, struct ieee80211_frame *); 2966191762Simp type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2967191762Simp ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 2968191762Simp 2969191762Simp /* Get 802.11 frame len before prepending TX header */ 2970191762Simp pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN; 2971191762Simp 2972191762Simp /* 2973191762Simp * Find TX rate 2974191762Simp */ 2975191762Simp tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 2976191762Simp if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL)) { 2977191762Simp rate = rate_fb = tp->mgmtrate; 2978191762Simp } else if (ismcast) { 2979191762Simp rate = rate_fb = tp->mcastrate; 2980191762Simp } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 2981191762Simp rate = rate_fb = tp->ucastrate; 2982191762Simp } else { 2983206358Srpaulo rix = ieee80211_ratectl_rate(ni, NULL, pkt_len); 2984191762Simp rate = ni->ni_txrate; 2985191762Simp 2986191762Simp if (rix > 0) { 2987191762Simp rate_fb = ni->ni_rates.rs_rates[rix-1] & 2988191762Simp IEEE80211_RATE_VAL; 2989191762Simp } else { 2990191762Simp rate_fb = rate; 2991191762Simp } 2992191762Simp } 2993191762Simp tb->tb_rate[0] = rate; 2994191762Simp tb->tb_rate[1] = rate_fb; 2995191762Simp sc->sc_tx_rate = rate; 2996191762Simp 2997191762Simp /* 2998191762Simp * TX radio tap 2999191762Simp */ 3000192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 3001191762Simp sc->sc_tx_th.wt_flags = 0; 3002191762Simp if (wh->i_fc[1] & IEEE80211_FC1_WEP) 3003191762Simp sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 3004191762Simp if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_DS && 3005191762Simp (ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 3006191762Simp rate != (1 * 2)) { 3007191762Simp sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3008191762Simp } 3009191762Simp sc->sc_tx_th.wt_rate = rate; 3010191762Simp 3011192468Ssam ieee80211_radiotap_tx(vap, m); 3012191762Simp } 3013191762Simp 3014191762Simp /* 3015191762Simp * Setup the embedded TX header 3016191762Simp */ 3017248078Smarius M_PREPEND(m, sizeof(*hdr), M_NOWAIT); 3018191762Simp if (m == NULL) { 3019191762Simp if_printf(ifp, "%s: prepend TX header failed\n", __func__); 3020191762Simp return ENOBUFS; 3021191762Simp } 3022191762Simp hdr = mtod(m, struct bwi_txbuf_hdr *); 3023191762Simp 3024191762Simp bzero(hdr, sizeof(*hdr)); 3025191762Simp 3026191762Simp bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); 3027191762Simp bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); 3028191762Simp 3029191762Simp if (!ismcast) { 3030191762Simp uint16_t dur; 3031191762Simp 3032191762Simp dur = ieee80211_ack_duration(sc->sc_rates, rate, 3033191762Simp ic->ic_flags & ~IEEE80211_F_SHPREAMBLE); 3034191762Simp 3035191762Simp hdr->txh_fb_duration = htole16(dur); 3036191762Simp } 3037191762Simp 3038191762Simp hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | 3039191762Simp __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK); 3040191762Simp 3041191762Simp bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate); 3042191762Simp bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb); 3043191762Simp 3044191762Simp phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, 3045191762Simp BWI_TXH_PHY_C_ANTMODE_MASK); 3046191762Simp if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) 3047191762Simp phy_ctrl |= BWI_TXH_PHY_C_OFDM; 3048191762Simp else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && rate != (2 * 1)) 3049191762Simp phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; 3050191762Simp 3051191762Simp mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; 3052191762Simp if (!ismcast) 3053191762Simp mac_ctrl |= BWI_TXH_MAC_C_ACK; 3054191762Simp if (ieee80211_rate2phytype(sc->sc_rates, rate_fb) == IEEE80211_T_OFDM) 3055191762Simp mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; 3056191762Simp 3057191762Simp hdr->txh_mac_ctrl = htole32(mac_ctrl); 3058191762Simp hdr->txh_phy_ctrl = htole16(phy_ctrl); 3059191762Simp 3060191762Simp /* Catch any further usage */ 3061191762Simp hdr = NULL; 3062191762Simp wh = NULL; 3063191762Simp 3064191762Simp /* DMA load */ 3065191762Simp error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, 3066191762Simp bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); 3067191762Simp if (error && error != EFBIG) { 3068191762Simp if_printf(ifp, "%s: can't load TX buffer (1) %d\n", 3069191762Simp __func__, error); 3070191762Simp goto back; 3071191762Simp } 3072191762Simp 3073191762Simp if (error) { /* error == EFBIG */ 3074191762Simp struct mbuf *m_new; 3075191762Simp 3076248078Smarius m_new = m_defrag(m, M_NOWAIT); 3077191762Simp if (m_new == NULL) { 3078191762Simp if_printf(ifp, "%s: can't defrag TX buffer\n", 3079191762Simp __func__); 3080191762Simp error = ENOBUFS; 3081191762Simp goto back; 3082191762Simp } else { 3083191762Simp m = m_new; 3084191762Simp } 3085191762Simp 3086191762Simp error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, 3087191762Simp bwi_dma_buf_addr, &paddr, 3088191762Simp BUS_DMA_NOWAIT); 3089191762Simp if (error) { 3090191762Simp if_printf(ifp, "%s: can't load TX buffer (2) %d\n", 3091191762Simp __func__, error); 3092191762Simp goto back; 3093191762Simp } 3094191762Simp } 3095191762Simp error = 0; 3096191762Simp 3097191762Simp bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); 3098191762Simp 3099191762Simp tb->tb_mbuf = m; 3100191762Simp tb->tb_ni = ni; 3101191762Simp 3102191762Simp#if 0 3103191762Simp p = mtod(m, const uint8_t *); 3104191762Simp for (i = 0; i < m->m_pkthdr.len; ++i) { 3105191762Simp if (i != 0 && i % 8 == 0) 3106191762Simp printf("\n"); 3107191762Simp printf("%02x ", p[i]); 3108191762Simp } 3109191762Simp printf("\n"); 3110191762Simp#endif 3111191762Simp DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n", 3112191762Simp idx, pkt_len, m->m_pkthdr.len); 3113191762Simp 3114191762Simp /* Setup TX descriptor */ 3115191762Simp sc->sc_setup_txdesc(sc, rd, idx, paddr, m->m_pkthdr.len); 3116191762Simp bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap, 3117191762Simp BUS_DMASYNC_PREWRITE); 3118191762Simp 3119191762Simp /* Kick start */ 3120191762Simp sc->sc_start_tx(sc, rd->rdata_txrx_ctrl, idx); 3121191762Simp 3122191762Simpback: 3123191762Simp if (error) 3124191762Simp m_freem(m); 3125191762Simp return error; 3126191762Simp} 3127191762Simp 3128191762Simpstatic int 3129191762Simpbwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, 3130191762Simp struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 3131191762Simp{ 3132191762Simp struct ifnet *ifp = sc->sc_ifp; 3133192468Ssam struct ieee80211vap *vap = ni->ni_vap; 3134193073Ssam struct ieee80211com *ic = ni->ni_ic; 3135191762Simp struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; 3136191762Simp struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; 3137191762Simp struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; 3138191762Simp struct bwi_mac *mac; 3139191762Simp struct bwi_txbuf_hdr *hdr; 3140191762Simp struct ieee80211_frame *wh; 3141191762Simp uint8_t rate, rate_fb; 3142191762Simp uint32_t mac_ctrl; 3143191762Simp uint16_t phy_ctrl; 3144191762Simp bus_addr_t paddr; 3145191762Simp int ismcast, pkt_len, error; 3146191762Simp 3147191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3148191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3149191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3150191762Simp 3151191762Simp wh = mtod(m, struct ieee80211_frame *); 3152191762Simp ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 3153191762Simp 3154191762Simp /* Get 802.11 frame len before prepending TX header */ 3155191762Simp pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3156191762Simp 3157191762Simp /* 3158191762Simp * Find TX rate 3159191762Simp */ 3160191762Simp rate = params->ibp_rate0; 3161193073Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 3162193073Ssam /* XXX fall back to mcast/mgmt rate? */ 3163193079Ssam m_freem(m); 3164193073Ssam return EINVAL; 3165193073Ssam } 3166193073Ssam if (params->ibp_try1 != 0) { 3167193073Ssam rate_fb = params->ibp_rate1; 3168193073Ssam if (!ieee80211_isratevalid(ic->ic_rt, rate_fb)) { 3169193073Ssam /* XXX fall back to rate0? */ 3170193079Ssam m_freem(m); 3171193073Ssam return EINVAL; 3172193073Ssam } 3173193073Ssam } else 3174193073Ssam rate_fb = rate; 3175191762Simp tb->tb_rate[0] = rate; 3176191762Simp tb->tb_rate[1] = rate_fb; 3177191762Simp sc->sc_tx_rate = rate; 3178191762Simp 3179191762Simp /* 3180191762Simp * TX radio tap 3181191762Simp */ 3182192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 3183191762Simp sc->sc_tx_th.wt_flags = 0; 3184191762Simp /* XXX IEEE80211_BPF_CRYPTO */ 3185191762Simp if (wh->i_fc[1] & IEEE80211_FC1_WEP) 3186191762Simp sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 3187191762Simp if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 3188191762Simp sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3189191762Simp sc->sc_tx_th.wt_rate = rate; 3190191762Simp 3191192468Ssam ieee80211_radiotap_tx(vap, m); 3192191762Simp } 3193191762Simp 3194191762Simp /* 3195191762Simp * Setup the embedded TX header 3196191762Simp */ 3197248078Smarius M_PREPEND(m, sizeof(*hdr), M_NOWAIT); 3198191762Simp if (m == NULL) { 3199191762Simp if_printf(ifp, "%s: prepend TX header failed\n", __func__); 3200191762Simp return ENOBUFS; 3201191762Simp } 3202191762Simp hdr = mtod(m, struct bwi_txbuf_hdr *); 3203191762Simp 3204191762Simp bzero(hdr, sizeof(*hdr)); 3205191762Simp 3206191762Simp bcopy(wh->i_fc, hdr->txh_fc, sizeof(hdr->txh_fc)); 3207191762Simp bcopy(wh->i_addr1, hdr->txh_addr1, sizeof(hdr->txh_addr1)); 3208191762Simp 3209191762Simp mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; 3210191762Simp if (!ismcast && (params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { 3211191762Simp uint16_t dur; 3212191762Simp 3213191762Simp dur = ieee80211_ack_duration(sc->sc_rates, rate_fb, 0); 3214191762Simp 3215191762Simp hdr->txh_fb_duration = htole16(dur); 3216191762Simp mac_ctrl |= BWI_TXH_MAC_C_ACK; 3217191762Simp } 3218191762Simp 3219191762Simp hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | 3220191762Simp __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK); 3221191762Simp 3222191762Simp bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate); 3223191762Simp bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb); 3224191762Simp 3225191762Simp phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, 3226191762Simp BWI_TXH_PHY_C_ANTMODE_MASK); 3227191762Simp if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { 3228191762Simp phy_ctrl |= BWI_TXH_PHY_C_OFDM; 3229191762Simp mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; 3230191762Simp } else if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 3231191762Simp phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; 3232191762Simp 3233191762Simp hdr->txh_mac_ctrl = htole32(mac_ctrl); 3234191762Simp hdr->txh_phy_ctrl = htole16(phy_ctrl); 3235191762Simp 3236191762Simp /* Catch any further usage */ 3237191762Simp hdr = NULL; 3238191762Simp wh = NULL; 3239191762Simp 3240191762Simp /* DMA load */ 3241191762Simp error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, 3242191762Simp bwi_dma_buf_addr, &paddr, BUS_DMA_NOWAIT); 3243191762Simp if (error != 0) { 3244191762Simp struct mbuf *m_new; 3245191762Simp 3246191762Simp if (error != EFBIG) { 3247191762Simp if_printf(ifp, "%s: can't load TX buffer (1) %d\n", 3248191762Simp __func__, error); 3249191762Simp goto back; 3250191762Simp } 3251248078Smarius m_new = m_defrag(m, M_NOWAIT); 3252191762Simp if (m_new == NULL) { 3253191762Simp if_printf(ifp, "%s: can't defrag TX buffer\n", 3254191762Simp __func__); 3255191762Simp error = ENOBUFS; 3256191762Simp goto back; 3257191762Simp } 3258191762Simp m = m_new; 3259191762Simp error = bus_dmamap_load_mbuf(sc->sc_buf_dtag, tb->tb_dmap, m, 3260191762Simp bwi_dma_buf_addr, &paddr, 3261191762Simp BUS_DMA_NOWAIT); 3262191762Simp if (error) { 3263191762Simp if_printf(ifp, "%s: can't load TX buffer (2) %d\n", 3264191762Simp __func__, error); 3265191762Simp goto back; 3266191762Simp } 3267191762Simp } 3268191762Simp 3269191762Simp bus_dmamap_sync(sc->sc_buf_dtag, tb->tb_dmap, BUS_DMASYNC_PREWRITE); 3270191762Simp 3271191762Simp tb->tb_mbuf = m; 3272191762Simp tb->tb_ni = ni; 3273191762Simp 3274191762Simp DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n", 3275191762Simp idx, pkt_len, m->m_pkthdr.len); 3276191762Simp 3277191762Simp /* Setup TX descriptor */ 3278191762Simp sc->sc_setup_txdesc(sc, rd, idx, paddr, m->m_pkthdr.len); 3279191762Simp bus_dmamap_sync(sc->sc_txring_dtag, rd->rdata_dmap, 3280191762Simp BUS_DMASYNC_PREWRITE); 3281191762Simp 3282191762Simp /* Kick start */ 3283191762Simp sc->sc_start_tx(sc, rd->rdata_txrx_ctrl, idx); 3284191762Simpback: 3285191762Simp if (error) 3286191762Simp m_freem(m); 3287191762Simp return error; 3288191762Simp} 3289191762Simp 3290191762Simpstatic void 3291191762Simpbwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) 3292191762Simp{ 3293191762Simp idx = (idx + 1) % BWI_TX_NDESC; 3294191762Simp CSR_WRITE_4(sc, tx_ctrl + BWI_TX32_INDEX, 3295191762Simp idx * sizeof(struct bwi_desc32)); 3296191762Simp} 3297191762Simp 3298191762Simpstatic void 3299191762Simpbwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) 3300191762Simp{ 3301191762Simp /* TODO:64 */ 3302191762Simp} 3303191762Simp 3304191762Simpstatic void 3305191762Simpbwi_txeof_status32(struct bwi_softc *sc) 3306191762Simp{ 3307191762Simp struct ifnet *ifp = sc->sc_ifp; 3308191762Simp uint32_t val, ctrl_base; 3309191762Simp int end_idx; 3310191762Simp 3311191762Simp ctrl_base = sc->sc_txstats->stats_ctrl_base; 3312191762Simp 3313191762Simp val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS); 3314191762Simp end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / 3315191762Simp sizeof(struct bwi_desc32); 3316191762Simp 3317191762Simp bwi_txeof_status(sc, end_idx); 3318191762Simp 3319191762Simp CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, 3320191762Simp end_idx * sizeof(struct bwi_desc32)); 3321191762Simp 3322191762Simp if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) 3323191762Simp ifp->if_start(ifp); 3324191762Simp} 3325191762Simp 3326191762Simpstatic void 3327191762Simpbwi_txeof_status64(struct bwi_softc *sc) 3328191762Simp{ 3329191762Simp /* TODO:64 */ 3330191762Simp} 3331191762Simp 3332191762Simpstatic void 3333191762Simp_bwi_txeof(struct bwi_softc *sc, uint16_t tx_id, int acked, int data_txcnt) 3334191762Simp{ 3335191762Simp struct ifnet *ifp = sc->sc_ifp; 3336191762Simp struct bwi_txbuf_data *tbd; 3337191762Simp struct bwi_txbuf *tb; 3338191762Simp int ring_idx, buf_idx; 3339191762Simp struct ieee80211_node *ni; 3340206358Srpaulo struct ieee80211vap *vap; 3341191762Simp 3342191762Simp if (tx_id == 0) { 3343191762Simp if_printf(ifp, "%s: zero tx id\n", __func__); 3344191762Simp return; 3345191762Simp } 3346191762Simp 3347191762Simp ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK); 3348191762Simp buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK); 3349191762Simp 3350191762Simp KASSERT(ring_idx == BWI_TX_DATA_RING, ("ring_idx %d", ring_idx)); 3351191762Simp KASSERT(buf_idx < BWI_TX_NDESC, ("buf_idx %d", buf_idx)); 3352191762Simp 3353191762Simp tbd = &sc->sc_tx_bdata[ring_idx]; 3354191762Simp KASSERT(tbd->tbd_used > 0, ("tbd_used %d", tbd->tbd_used)); 3355191762Simp tbd->tbd_used--; 3356191762Simp 3357191762Simp tb = &tbd->tbd_buf[buf_idx]; 3358191762Simp DPRINTF(sc, BWI_DBG_TXEOF, "txeof idx %d, " 3359191762Simp "acked %d, data_txcnt %d, ni %p\n", 3360191762Simp buf_idx, acked, data_txcnt, tb->tb_ni); 3361191762Simp 3362191762Simp bus_dmamap_unload(sc->sc_buf_dtag, tb->tb_dmap); 3363191762Simp 3364191762Simp ni = tb->tb_ni; 3365191762Simp if (tb->tb_ni != NULL) { 3366191762Simp const struct bwi_txbuf_hdr *hdr = 3367191762Simp mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *); 3368206370Srpaulo vap = ni->ni_vap; 3369191762Simp 3370191762Simp /* NB: update rate control only for unicast frames */ 3371191762Simp if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) { 3372191762Simp /* 3373191762Simp * Feed back 'acked and data_txcnt'. Note that the 3374191762Simp * generic AMRR code only understands one tx rate 3375191762Simp * and the estimator doesn't handle real retry counts 3376191762Simp * well so to avoid over-aggressive downshifting we 3377191762Simp * treat any number of retries as "1". 3378191762Simp */ 3379206358Srpaulo ieee80211_ratectl_tx_complete(vap, ni, 3380206358Srpaulo (data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS : 3381206358Srpaulo IEEE80211_RATECTL_TX_FAILURE, &acked, NULL); 3382191762Simp } 3383191762Simp 3384191762Simp /* 3385191762Simp * Do any tx complete callback. Note this must 3386191762Simp * be done before releasing the node reference. 3387191762Simp */ 3388191762Simp if (tb->tb_mbuf->m_flags & M_TXCB) 3389191762Simp ieee80211_process_callback(ni, tb->tb_mbuf, !acked); 3390191762Simp 3391191762Simp ieee80211_free_node(tb->tb_ni); 3392191762Simp tb->tb_ni = NULL; 3393191762Simp } 3394191762Simp m_freem(tb->tb_mbuf); 3395191762Simp tb->tb_mbuf = NULL; 3396191762Simp 3397191762Simp if (tbd->tbd_used == 0) 3398199197Sjhb sc->sc_tx_timer = 0; 3399191762Simp 3400191762Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3401191762Simp} 3402191762Simp 3403191762Simpstatic void 3404191762Simpbwi_txeof_status(struct bwi_softc *sc, int end_idx) 3405191762Simp{ 3406191762Simp struct bwi_txstats_data *st = sc->sc_txstats; 3407191762Simp int idx; 3408191762Simp 3409191762Simp bus_dmamap_sync(st->stats_dtag, st->stats_dmap, BUS_DMASYNC_POSTREAD); 3410191762Simp 3411191762Simp idx = st->stats_idx; 3412191762Simp while (idx != end_idx) { 3413191762Simp const struct bwi_txstats *stats = &st->stats[idx]; 3414191762Simp 3415191762Simp if ((stats->txs_flags & BWI_TXS_F_PENDING) == 0) { 3416191762Simp int data_txcnt; 3417191762Simp 3418191762Simp data_txcnt = __SHIFTOUT(stats->txs_txcnt, 3419191762Simp BWI_TXS_TXCNT_DATA); 3420191762Simp _bwi_txeof(sc, le16toh(stats->txs_id), 3421191762Simp stats->txs_flags & BWI_TXS_F_ACKED, 3422191762Simp data_txcnt); 3423191762Simp } 3424191762Simp idx = (idx + 1) % BWI_TXSTATS_NDESC; 3425191762Simp } 3426191762Simp st->stats_idx = idx; 3427191762Simp} 3428191762Simp 3429191762Simpstatic void 3430191762Simpbwi_txeof(struct bwi_softc *sc) 3431191762Simp{ 3432191762Simp struct ifnet *ifp = sc->sc_ifp; 3433191762Simp 3434191762Simp for (;;) { 3435191762Simp uint32_t tx_status0, tx_status1; 3436191762Simp uint16_t tx_id; 3437191762Simp int data_txcnt; 3438191762Simp 3439191762Simp tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS0); 3440191762Simp if ((tx_status0 & BWI_TXSTATUS0_VALID) == 0) 3441191762Simp break; 3442191762Simp tx_status1 = CSR_READ_4(sc, BWI_TXSTATUS1); 3443191762Simp 3444191762Simp tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS0_TXID_MASK); 3445191762Simp data_txcnt = __SHIFTOUT(tx_status0, 3446191762Simp BWI_TXSTATUS0_DATA_TXCNT_MASK); 3447191762Simp 3448191762Simp if (tx_status0 & (BWI_TXSTATUS0_AMPDU | BWI_TXSTATUS0_PENDING)) 3449191762Simp continue; 3450191762Simp 3451191762Simp _bwi_txeof(sc, le16toh(tx_id), tx_status0 & BWI_TXSTATUS0_ACKED, 3452191762Simp data_txcnt); 3453191762Simp } 3454191762Simp 3455191762Simp if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) 3456191762Simp ifp->if_start(ifp); 3457191762Simp} 3458191762Simp 3459191762Simpstatic int 3460191762Simpbwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) 3461191762Simp{ 3462191762Simp bwi_power_on(sc, 1); 3463191762Simp return bwi_set_clock_mode(sc, clk_mode); 3464191762Simp} 3465191762Simp 3466191762Simpstatic void 3467191762Simpbwi_bbp_power_off(struct bwi_softc *sc) 3468191762Simp{ 3469191762Simp bwi_set_clock_mode(sc, BWI_CLOCK_MODE_SLOW); 3470191762Simp bwi_power_off(sc, 1); 3471191762Simp} 3472191762Simp 3473191762Simpstatic int 3474191762Simpbwi_get_pwron_delay(struct bwi_softc *sc) 3475191762Simp{ 3476191762Simp struct bwi_regwin *com, *old; 3477191762Simp struct bwi_clock_freq freq; 3478191762Simp uint32_t val; 3479191762Simp int error; 3480191762Simp 3481191762Simp com = &sc->sc_com_regwin; 3482191762Simp KASSERT(BWI_REGWIN_EXIST(com), ("no regwin")); 3483191762Simp 3484191762Simp if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) 3485191762Simp return 0; 3486191762Simp 3487191762Simp error = bwi_regwin_switch(sc, com, &old); 3488191762Simp if (error) 3489191762Simp return error; 3490191762Simp 3491191762Simp bwi_get_clock_freq(sc, &freq); 3492191762Simp 3493191762Simp val = CSR_READ_4(sc, BWI_PLL_ON_DELAY); 3494191762Simp sc->sc_pwron_delay = howmany((val + 2) * 1000000, freq.clkfreq_min); 3495191762Simp DPRINTF(sc, BWI_DBG_ATTACH, "power on delay %u\n", sc->sc_pwron_delay); 3496191762Simp 3497191762Simp return bwi_regwin_switch(sc, old, NULL); 3498191762Simp} 3499191762Simp 3500191762Simpstatic int 3501191762Simpbwi_bus_attach(struct bwi_softc *sc) 3502191762Simp{ 3503191762Simp struct bwi_regwin *bus, *old; 3504191762Simp int error; 3505191762Simp 3506191762Simp bus = &sc->sc_bus_regwin; 3507191762Simp 3508191762Simp error = bwi_regwin_switch(sc, bus, &old); 3509191762Simp if (error) 3510191762Simp return error; 3511191762Simp 3512191762Simp if (!bwi_regwin_is_enabled(sc, bus)) 3513191762Simp bwi_regwin_enable(sc, bus, 0); 3514191762Simp 3515191762Simp /* Disable interripts */ 3516191762Simp CSR_WRITE_4(sc, BWI_INTRVEC, 0); 3517191762Simp 3518191762Simp return bwi_regwin_switch(sc, old, NULL); 3519191762Simp} 3520191762Simp 3521191762Simpstatic const char * 3522191762Simpbwi_regwin_name(const struct bwi_regwin *rw) 3523191762Simp{ 3524191762Simp switch (rw->rw_type) { 3525191762Simp case BWI_REGWIN_T_COM: 3526191762Simp return "COM"; 3527191762Simp case BWI_REGWIN_T_BUSPCI: 3528191762Simp return "PCI"; 3529191762Simp case BWI_REGWIN_T_MAC: 3530191762Simp return "MAC"; 3531191762Simp case BWI_REGWIN_T_BUSPCIE: 3532191762Simp return "PCIE"; 3533191762Simp } 3534191762Simp panic("unknown regwin type 0x%04x\n", rw->rw_type); 3535191762Simp return NULL; 3536191762Simp} 3537191762Simp 3538191762Simpstatic uint32_t 3539191762Simpbwi_regwin_disable_bits(struct bwi_softc *sc) 3540191762Simp{ 3541191762Simp uint32_t busrev; 3542191762Simp 3543191762Simp /* XXX cache this */ 3544191762Simp busrev = __SHIFTOUT(CSR_READ_4(sc, BWI_ID_LO), BWI_ID_LO_BUSREV_MASK); 3545191762Simp DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_MISC, 3546191762Simp "bus rev %u\n", busrev); 3547191762Simp 3548191762Simp if (busrev == BWI_BUSREV_0) 3549191762Simp return BWI_STATE_LO_DISABLE1; 3550191762Simp else if (busrev == BWI_BUSREV_1) 3551191762Simp return BWI_STATE_LO_DISABLE2; 3552191762Simp else 3553191762Simp return (BWI_STATE_LO_DISABLE1 | BWI_STATE_LO_DISABLE2); 3554191762Simp} 3555191762Simp 3556191762Simpint 3557191762Simpbwi_regwin_is_enabled(struct bwi_softc *sc, struct bwi_regwin *rw) 3558191762Simp{ 3559191762Simp uint32_t val, disable_bits; 3560191762Simp 3561191762Simp disable_bits = bwi_regwin_disable_bits(sc); 3562191762Simp val = CSR_READ_4(sc, BWI_STATE_LO); 3563191762Simp 3564191762Simp if ((val & (BWI_STATE_LO_CLOCK | 3565191762Simp BWI_STATE_LO_RESET | 3566191762Simp disable_bits)) == BWI_STATE_LO_CLOCK) { 3567191762Simp DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is enabled\n", 3568191762Simp bwi_regwin_name(rw)); 3569191762Simp return 1; 3570191762Simp } else { 3571191762Simp DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is disabled\n", 3572191762Simp bwi_regwin_name(rw)); 3573191762Simp return 0; 3574191762Simp } 3575191762Simp} 3576191762Simp 3577191762Simpvoid 3578191762Simpbwi_regwin_disable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) 3579191762Simp{ 3580191762Simp uint32_t state_lo, disable_bits; 3581191762Simp int i; 3582191762Simp 3583191762Simp state_lo = CSR_READ_4(sc, BWI_STATE_LO); 3584191762Simp 3585191762Simp /* 3586191762Simp * If current regwin is in 'reset' state, it was already disabled. 3587191762Simp */ 3588191762Simp if (state_lo & BWI_STATE_LO_RESET) { 3589191762Simp DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, 3590191762Simp "%s was already disabled\n", bwi_regwin_name(rw)); 3591191762Simp return; 3592191762Simp } 3593191762Simp 3594191762Simp disable_bits = bwi_regwin_disable_bits(sc); 3595191762Simp 3596191762Simp /* 3597191762Simp * Disable normal clock 3598191762Simp */ 3599191762Simp state_lo = BWI_STATE_LO_CLOCK | disable_bits; 3600191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3601191762Simp 3602191762Simp /* 3603191762Simp * Wait until normal clock is disabled 3604191762Simp */ 3605191762Simp#define NRETRY 1000 3606191762Simp for (i = 0; i < NRETRY; ++i) { 3607191762Simp state_lo = CSR_READ_4(sc, BWI_STATE_LO); 3608191762Simp if (state_lo & disable_bits) 3609191762Simp break; 3610191762Simp DELAY(10); 3611191762Simp } 3612191762Simp if (i == NRETRY) { 3613191762Simp device_printf(sc->sc_dev, "%s disable clock timeout\n", 3614191762Simp bwi_regwin_name(rw)); 3615191762Simp } 3616191762Simp 3617191762Simp for (i = 0; i < NRETRY; ++i) { 3618191762Simp uint32_t state_hi; 3619191762Simp 3620191762Simp state_hi = CSR_READ_4(sc, BWI_STATE_HI); 3621191762Simp if ((state_hi & BWI_STATE_HI_BUSY) == 0) 3622191762Simp break; 3623191762Simp DELAY(10); 3624191762Simp } 3625191762Simp if (i == NRETRY) { 3626191762Simp device_printf(sc->sc_dev, "%s wait BUSY unset timeout\n", 3627191762Simp bwi_regwin_name(rw)); 3628191762Simp } 3629191762Simp#undef NRETRY 3630191762Simp 3631191762Simp /* 3632191762Simp * Reset and disable regwin with gated clock 3633191762Simp */ 3634191762Simp state_lo = BWI_STATE_LO_RESET | disable_bits | 3635191762Simp BWI_STATE_LO_CLOCK | BWI_STATE_LO_GATED_CLOCK | 3636191762Simp __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); 3637191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3638191762Simp 3639191762Simp /* Flush pending bus write */ 3640191762Simp CSR_READ_4(sc, BWI_STATE_LO); 3641191762Simp DELAY(1); 3642191762Simp 3643191762Simp /* Reset and disable regwin */ 3644191762Simp state_lo = BWI_STATE_LO_RESET | disable_bits | 3645191762Simp __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); 3646191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3647191762Simp 3648191762Simp /* Flush pending bus write */ 3649191762Simp CSR_READ_4(sc, BWI_STATE_LO); 3650191762Simp DELAY(1); 3651191762Simp} 3652191762Simp 3653191762Simpvoid 3654191762Simpbwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) 3655191762Simp{ 3656191762Simp uint32_t state_lo, state_hi, imstate; 3657191762Simp 3658191762Simp bwi_regwin_disable(sc, rw, flags); 3659191762Simp 3660191762Simp /* Reset regwin with gated clock */ 3661191762Simp state_lo = BWI_STATE_LO_RESET | 3662191762Simp BWI_STATE_LO_CLOCK | 3663191762Simp BWI_STATE_LO_GATED_CLOCK | 3664191762Simp __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); 3665191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3666191762Simp 3667191762Simp /* Flush pending bus write */ 3668191762Simp CSR_READ_4(sc, BWI_STATE_LO); 3669191762Simp DELAY(1); 3670191762Simp 3671191762Simp state_hi = CSR_READ_4(sc, BWI_STATE_HI); 3672191762Simp if (state_hi & BWI_STATE_HI_SERROR) 3673191762Simp CSR_WRITE_4(sc, BWI_STATE_HI, 0); 3674191762Simp 3675191762Simp imstate = CSR_READ_4(sc, BWI_IMSTATE); 3676191762Simp if (imstate & (BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT)) { 3677191762Simp imstate &= ~(BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT); 3678191762Simp CSR_WRITE_4(sc, BWI_IMSTATE, imstate); 3679191762Simp } 3680191762Simp 3681191762Simp /* Enable regwin with gated clock */ 3682191762Simp state_lo = BWI_STATE_LO_CLOCK | 3683191762Simp BWI_STATE_LO_GATED_CLOCK | 3684191762Simp __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); 3685191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3686191762Simp 3687191762Simp /* Flush pending bus write */ 3688191762Simp CSR_READ_4(sc, BWI_STATE_LO); 3689191762Simp DELAY(1); 3690191762Simp 3691191762Simp /* Enable regwin with normal clock */ 3692191762Simp state_lo = BWI_STATE_LO_CLOCK | 3693191762Simp __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); 3694191762Simp CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); 3695191762Simp 3696191762Simp /* Flush pending bus write */ 3697191762Simp CSR_READ_4(sc, BWI_STATE_LO); 3698191762Simp DELAY(1); 3699191762Simp} 3700191762Simp 3701191762Simpstatic void 3702191762Simpbwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) 3703191762Simp{ 3704191762Simp struct ifnet *ifp = sc->sc_ifp; 3705191762Simp struct bwi_mac *mac; 3706191762Simp struct bwi_myaddr_bssid buf; 3707191762Simp const uint8_t *p; 3708191762Simp uint32_t val; 3709191762Simp int n, i; 3710191762Simp 3711191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3712191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3713191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3714191762Simp 3715191762Simp bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); 3716191762Simp 3717191762Simp bcopy(IF_LLADDR(ifp), buf.myaddr, sizeof(buf.myaddr)); 3718191762Simp bcopy(bssid, buf.bssid, sizeof(buf.bssid)); 3719191762Simp 3720191762Simp n = sizeof(buf) / sizeof(val); 3721191762Simp p = (const uint8_t *)&buf; 3722191762Simp for (i = 0; i < n; ++i) { 3723191762Simp int j; 3724191762Simp 3725191762Simp val = 0; 3726191762Simp for (j = 0; j < sizeof(val); ++j) 3727191762Simp val |= ((uint32_t)(*p++)) << (j * 8); 3728191762Simp 3729191762Simp TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val); 3730191762Simp } 3731191762Simp} 3732191762Simp 3733191762Simpstatic void 3734191762Simpbwi_updateslot(struct ifnet *ifp) 3735191762Simp{ 3736191762Simp struct bwi_softc *sc = ifp->if_softc; 3737191762Simp struct ieee80211com *ic = ifp->if_l2com; 3738191762Simp struct bwi_mac *mac; 3739191762Simp 3740191762Simp BWI_LOCK(sc); 3741191762Simp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3742191762Simp DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); 3743191762Simp 3744191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3745191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3746191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3747191762Simp 3748191762Simp bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT)); 3749191762Simp } 3750191762Simp BWI_UNLOCK(sc); 3751191762Simp} 3752191762Simp 3753191762Simpstatic void 3754191762Simpbwi_calibrate(void *xsc) 3755191762Simp{ 3756191762Simp struct bwi_softc *sc = xsc; 3757191762Simp#ifdef INVARIANTS 3758191762Simp struct ifnet *ifp = sc->sc_ifp; 3759191762Simp struct ieee80211com *ic = ifp->if_l2com; 3760191762Simp#endif 3761191762Simp struct bwi_mac *mac; 3762191762Simp 3763191762Simp BWI_ASSERT_LOCKED(sc); 3764191762Simp 3765191762Simp KASSERT(ic->ic_opmode != IEEE80211_M_MONITOR, 3766191762Simp ("opmode %d", ic->ic_opmode)); 3767191762Simp 3768191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3769191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3770191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3771191762Simp 3772191762Simp bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type); 3773191762Simp sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; 3774191762Simp 3775191762Simp /* XXX 15 seconds */ 3776191762Simp callout_reset(&sc->sc_calib_ch, hz * 15, bwi_calibrate, sc); 3777191762Simp} 3778191762Simp 3779191762Simpstatic int 3780191762Simpbwi_calc_rssi(struct bwi_softc *sc, const struct bwi_rxbuf_hdr *hdr) 3781191762Simp{ 3782191762Simp struct bwi_mac *mac; 3783191762Simp 3784191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3785191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3786191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3787191762Simp 3788191762Simp return bwi_rf_calc_rssi(mac, hdr); 3789191762Simp} 3790191762Simp 3791191762Simpstatic int 3792191762Simpbwi_calc_noise(struct bwi_softc *sc) 3793191762Simp{ 3794191762Simp struct bwi_mac *mac; 3795191762Simp 3796191762Simp KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC, 3797191762Simp ("current regwin type %d", sc->sc_cur_regwin->rw_type)); 3798191762Simp mac = (struct bwi_mac *)sc->sc_cur_regwin; 3799191762Simp 3800191762Simp return bwi_rf_calc_noise(mac); 3801191762Simp} 3802191762Simp 3803191762Simpstatic __inline uint8_t 3804234753Sdimbwi_plcp2rate(const uint32_t plcp0, enum ieee80211_phytype type) 3805191762Simp{ 3806234753Sdim uint32_t plcp = le32toh(plcp0) & IEEE80211_OFDM_PLCP_RATE_MASK; 3807234753Sdim return (ieee80211_plcp2rate(plcp, type)); 3808191762Simp} 3809191762Simp 3810191762Simpstatic void 3811192468Ssambwi_rx_radiotap(struct bwi_softc *sc, struct mbuf *m, 3812191762Simp struct bwi_rxbuf_hdr *hdr, const void *plcp, int rate, int rssi, int noise) 3813191762Simp{ 3814191762Simp const struct ieee80211_frame_min *wh; 3815191762Simp 3816191762Simp sc->sc_rx_th.wr_flags = IEEE80211_RADIOTAP_F_FCS; 3817191762Simp if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_SHPREAMBLE) 3818191762Simp sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3819191762Simp 3820191762Simp wh = mtod(m, const struct ieee80211_frame_min *); 3821191762Simp if (wh->i_fc[1] & IEEE80211_FC1_WEP) 3822191762Simp sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP; 3823191762Simp 3824191762Simp sc->sc_rx_th.wr_tsf = hdr->rxh_tsf; /* No endian convertion */ 3825191762Simp sc->sc_rx_th.wr_rate = rate; 3826191762Simp sc->sc_rx_th.wr_antsignal = rssi; 3827191762Simp sc->sc_rx_th.wr_antnoise = noise; 3828191762Simp} 3829191762Simp 3830191762Simpstatic void 3831191762Simpbwi_led_attach(struct bwi_softc *sc) 3832191762Simp{ 3833191762Simp const uint8_t *led_act = NULL; 3834191762Simp uint16_t gpio, val[BWI_LED_MAX]; 3835191762Simp int i; 3836191762Simp 3837191762Simp#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) 3838191762Simp 3839191762Simp for (i = 0; i < N(bwi_vendor_led_act); ++i) { 3840191762Simp if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) { 3841191762Simp led_act = bwi_vendor_led_act[i].led_act; 3842191762Simp break; 3843191762Simp } 3844191762Simp } 3845191762Simp if (led_act == NULL) 3846191762Simp led_act = bwi_default_led_act; 3847191762Simp 3848191762Simp#undef N 3849191762Simp 3850191762Simp gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01); 3851191762Simp val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0); 3852191762Simp val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1); 3853191762Simp 3854191762Simp gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO23); 3855191762Simp val[2] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_2); 3856191762Simp val[3] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_3); 3857191762Simp 3858191762Simp for (i = 0; i < BWI_LED_MAX; ++i) { 3859191762Simp struct bwi_led *led = &sc->sc_leds[i]; 3860191762Simp 3861191762Simp if (val[i] == 0xff) { 3862191762Simp led->l_act = led_act[i]; 3863191762Simp } else { 3864191762Simp if (val[i] & BWI_LED_ACT_LOW) 3865191762Simp led->l_flags |= BWI_LED_F_ACTLOW; 3866191762Simp led->l_act = __SHIFTOUT(val[i], BWI_LED_ACT_MASK); 3867191762Simp } 3868191762Simp led->l_mask = (1 << i); 3869191762Simp 3870191762Simp if (led->l_act == BWI_LED_ACT_BLINK_SLOW || 3871191762Simp led->l_act == BWI_LED_ACT_BLINK_POLL || 3872191762Simp led->l_act == BWI_LED_ACT_BLINK) { 3873191762Simp led->l_flags |= BWI_LED_F_BLINK; 3874191762Simp if (led->l_act == BWI_LED_ACT_BLINK_POLL) 3875191762Simp led->l_flags |= BWI_LED_F_POLLABLE; 3876191762Simp else if (led->l_act == BWI_LED_ACT_BLINK_SLOW) 3877191762Simp led->l_flags |= BWI_LED_F_SLOW; 3878191762Simp 3879191762Simp if (sc->sc_blink_led == NULL) { 3880191762Simp sc->sc_blink_led = led; 3881191762Simp if (led->l_flags & BWI_LED_F_SLOW) 3882191762Simp BWI_LED_SLOWDOWN(sc->sc_led_idle); 3883191762Simp } 3884191762Simp } 3885191762Simp 3886191762Simp DPRINTF(sc, BWI_DBG_LED | BWI_DBG_ATTACH, 3887191762Simp "%dth led, act %d, lowact %d\n", i, 3888191762Simp led->l_act, led->l_flags & BWI_LED_F_ACTLOW); 3889191762Simp } 3890199197Sjhb callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0); 3891191762Simp} 3892191762Simp 3893191762Simpstatic __inline uint16_t 3894191762Simpbwi_led_onoff(const struct bwi_led *led, uint16_t val, int on) 3895191762Simp{ 3896191762Simp if (led->l_flags & BWI_LED_F_ACTLOW) 3897191762Simp on = !on; 3898191762Simp if (on) 3899191762Simp val |= led->l_mask; 3900191762Simp else 3901191762Simp val &= ~led->l_mask; 3902191762Simp return val; 3903191762Simp} 3904191762Simp 3905191762Simpstatic void 3906191762Simpbwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) 3907191762Simp{ 3908191762Simp struct ifnet *ifp = sc->sc_ifp; 3909191762Simp struct ieee80211com *ic = ifp->if_l2com; 3910191762Simp uint16_t val; 3911191762Simp int i; 3912191762Simp 3913191762Simp if (nstate == IEEE80211_S_INIT) { 3914191762Simp callout_stop(&sc->sc_led_blink_ch); 3915191762Simp sc->sc_led_blinking = 0; 3916191762Simp } 3917191762Simp 3918191762Simp if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 3919191762Simp return; 3920191762Simp 3921191762Simp val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); 3922191762Simp for (i = 0; i < BWI_LED_MAX; ++i) { 3923191762Simp struct bwi_led *led = &sc->sc_leds[i]; 3924191762Simp int on; 3925191762Simp 3926191762Simp if (led->l_act == BWI_LED_ACT_UNKN || 3927191762Simp led->l_act == BWI_LED_ACT_NULL) 3928191762Simp continue; 3929191762Simp 3930191762Simp if ((led->l_flags & BWI_LED_F_BLINK) && 3931191762Simp nstate != IEEE80211_S_INIT) 3932191762Simp continue; 3933191762Simp 3934191762Simp switch (led->l_act) { 3935191762Simp case BWI_LED_ACT_ON: /* Always on */ 3936191762Simp on = 1; 3937191762Simp break; 3938191762Simp case BWI_LED_ACT_OFF: /* Always off */ 3939191762Simp case BWI_LED_ACT_5GHZ: /* TODO: 11A */ 3940191762Simp on = 0; 3941191762Simp break; 3942191762Simp default: 3943191762Simp on = 1; 3944191762Simp switch (nstate) { 3945191762Simp case IEEE80211_S_INIT: 3946191762Simp on = 0; 3947191762Simp break; 3948191762Simp case IEEE80211_S_RUN: 3949191762Simp if (led->l_act == BWI_LED_ACT_11G && 3950191762Simp ic->ic_curmode != IEEE80211_MODE_11G) 3951191762Simp on = 0; 3952191762Simp break; 3953191762Simp default: 3954191762Simp if (led->l_act == BWI_LED_ACT_ASSOC) 3955191762Simp on = 0; 3956191762Simp break; 3957191762Simp } 3958191762Simp break; 3959191762Simp } 3960191762Simp 3961191762Simp val = bwi_led_onoff(led, val, on); 3962191762Simp } 3963191762Simp CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); 3964191762Simp} 3965191762Simpstatic void 3966191762Simpbwi_led_event(struct bwi_softc *sc, int event) 3967191762Simp{ 3968191762Simp struct bwi_led *led = sc->sc_blink_led; 3969191762Simp int rate; 3970191762Simp 3971191762Simp if (event == BWI_LED_EVENT_POLL) { 3972191762Simp if ((led->l_flags & BWI_LED_F_POLLABLE) == 0) 3973191762Simp return; 3974191762Simp if (ticks - sc->sc_led_ticks < sc->sc_led_idle) 3975191762Simp return; 3976191762Simp } 3977191762Simp 3978191762Simp sc->sc_led_ticks = ticks; 3979191762Simp if (sc->sc_led_blinking) 3980191762Simp return; 3981191762Simp 3982191762Simp switch (event) { 3983191762Simp case BWI_LED_EVENT_RX: 3984191762Simp rate = sc->sc_rx_rate; 3985191762Simp break; 3986191762Simp case BWI_LED_EVENT_TX: 3987191762Simp rate = sc->sc_tx_rate; 3988191762Simp break; 3989191762Simp case BWI_LED_EVENT_POLL: 3990191762Simp rate = 0; 3991191762Simp break; 3992191762Simp default: 3993191762Simp panic("unknown LED event %d\n", event); 3994191762Simp break; 3995191762Simp } 3996191762Simp bwi_led_blink_start(sc, bwi_led_duration[rate].on_dur, 3997191762Simp bwi_led_duration[rate].off_dur); 3998191762Simp} 3999191762Simp 4000191762Simpstatic void 4001191762Simpbwi_led_blink_start(struct bwi_softc *sc, int on_dur, int off_dur) 4002191762Simp{ 4003191762Simp struct bwi_led *led = sc->sc_blink_led; 4004191762Simp uint16_t val; 4005191762Simp 4006191762Simp val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); 4007191762Simp val = bwi_led_onoff(led, val, 1); 4008191762Simp CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); 4009191762Simp 4010191762Simp if (led->l_flags & BWI_LED_F_SLOW) { 4011191762Simp BWI_LED_SLOWDOWN(on_dur); 4012191762Simp BWI_LED_SLOWDOWN(off_dur); 4013191762Simp } 4014191762Simp 4015191762Simp sc->sc_led_blinking = 1; 4016191762Simp sc->sc_led_blink_offdur = off_dur; 4017191762Simp 4018191762Simp callout_reset(&sc->sc_led_blink_ch, on_dur, bwi_led_blink_next, sc); 4019191762Simp} 4020191762Simp 4021191762Simpstatic void 4022191762Simpbwi_led_blink_next(void *xsc) 4023191762Simp{ 4024191762Simp struct bwi_softc *sc = xsc; 4025191762Simp uint16_t val; 4026191762Simp 4027191762Simp val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); 4028191762Simp val = bwi_led_onoff(sc->sc_blink_led, val, 0); 4029191762Simp CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); 4030191762Simp 4031191762Simp callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur, 4032191762Simp bwi_led_blink_end, sc); 4033191762Simp} 4034191762Simp 4035191762Simpstatic void 4036191762Simpbwi_led_blink_end(void *xsc) 4037191762Simp{ 4038191762Simp struct bwi_softc *sc = xsc; 4039191762Simp sc->sc_led_blinking = 0; 4040191762Simp} 4041191762Simp 4042191762Simpstatic void 4043191762Simpbwi_restart(void *xsc, int pending) 4044191762Simp{ 4045191762Simp struct bwi_softc *sc = xsc; 4046191762Simp struct ifnet *ifp = sc->sc_ifp; 4047191762Simp 4048191762Simp if_printf(ifp, "%s begin, help!\n", __func__); 4049191762Simp BWI_LOCK(sc); 4050191762Simp bwi_init_statechg(xsc, 0); 4051191762Simp#if 0 4052191762Simp bwi_start_locked(ifp); 4053191762Simp#endif 4054193238Simp BWI_UNLOCK(sc); 4055191762Simp} 4056