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