diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 6d38948f0f1e..c807e32d6d81 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -101,50 +101,13 @@ static void bcm47xx_machine_halt(void) } #ifdef CONFIG_BCM47XX_SSB -static int bcm47xx_get_invariants(struct ssb_bus *bus, - struct ssb_init_invariants *iv) -{ - char buf[20]; - int len, err; - - /* Fill boardinfo structure */ - memset(&iv->boardinfo, 0 , sizeof(struct ssb_boardinfo)); - - len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf)); - if (len > 0) { - err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor); - if (err) - pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n", - buf); - } - if (!iv->boardinfo.vendor) - iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; - - len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf)); - if (len > 0) { - err = kstrtou16(strim(buf), 0, &iv->boardinfo.type); - if (err) - pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n", - buf); - } - - memset(&iv->sprom, 0, sizeof(struct ssb_sprom)); - bcm47xx_fill_sprom(&iv->sprom, NULL, false); - - if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) - iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); - - return 0; -} - static void __init bcm47xx_register_ssb(void) { int err; char buf[100]; struct ssb_mipscore *mcore; - err = ssb_bus_ssbbus_register(&bcm47xx_bus.ssb, SSB_ENUM_BASE, - bcm47xx_get_invariants); + err = ssb_bus_host_soc_register(&bcm47xx_bus.ssb, SSB_ENUM_BASE); if (err) panic("Failed to initialize SSB bus (err %d)", err); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 59d8d0d14824..c466f752b067 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -668,11 +668,36 @@ static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env) core->id.rev, core->id.class); } +static unsigned int bcma_bus_registered; + +/* + * If built-in, bus has to be registered early, before any driver calls + * bcma_driver_register. + * Otherwise registering driver would trigger BUG in driver_register. + */ +static int __init bcma_init_bus_register(void) +{ + int err; + + if (bcma_bus_registered) + return 0; + + err = bus_register(&bcma_bus_type); + if (!err) + bcma_bus_registered = 1; + + return err; +} +#ifndef MODULE +fs_initcall(bcma_init_bus_register); +#endif + +/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */ static int __init bcma_modinit(void) { int err; - err = bus_register(&bcma_bus_type); + err = bcma_init_bus_register(); if (err) return err; @@ -691,7 +716,7 @@ static int __init bcma_modinit(void) return err; } -fs_initcall(bcma_modinit); +module_init(bcma_modinit); static void __exit bcma_modexit(void) { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 39fe4f3350aa..2bdf5408b0d9 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1139,7 +1139,7 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, { struct ath10k *ar = file->private_data; char buf[64]; - u8 amsdu = 3, ampdu = 64; + u8 amsdu, ampdu; unsigned int len; mutex_lock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bcb364d5d49f..b4bdeb07a012 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -250,7 +250,8 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP && - arvif->vif->type != NL80211_IFTYPE_ADHOC)) + arvif->vif->type != NL80211_IFTYPE_ADHOC && + arvif->vif->type != NL80211_IFTYPE_MESH_POINT)) return -EINVAL; spin_lock_bh(&ar->data_lock); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2a44d63a03cd..a7c3d299639b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4312,34 +4312,58 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb) ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); } -static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, - u32 num_units, u32 unit_len) +static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, + u32 num_units, u32 unit_len) { dma_addr_t paddr; - u32 pool_size; + u32 pool_size = 0; int idx = ar->wmi.num_mem_chunks; + void *vaddr = NULL; - pool_size = num_units * round_up(unit_len, 4); + if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks)) + return -ENOMEM; - if (!pool_size) - return -EINVAL; + while (!vaddr && num_units) { + pool_size = num_units * round_up(unit_len, 4); + if (!pool_size) + return -EINVAL; - ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev, - pool_size, - &paddr, - GFP_KERNEL); - if (!ar->wmi.mem_chunks[idx].vaddr) { - ath10k_warn(ar, "failed to allocate memory chunk\n"); + vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN); + if (!vaddr) + num_units /= 2; + } + + if (!num_units) + return -ENOMEM; + + paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE); + if (dma_mapping_error(ar->dev, paddr)) { + kfree(vaddr); return -ENOMEM; } - memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size); - + ar->wmi.mem_chunks[idx].vaddr = vaddr; ar->wmi.mem_chunks[idx].paddr = paddr; ar->wmi.mem_chunks[idx].len = pool_size; ar->wmi.mem_chunks[idx].req_id = req_id; ar->wmi.num_mem_chunks++; + return num_units; +} + +static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, + u32 num_units, u32 unit_len) +{ + int ret; + + while (num_units) { + ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len); + if (ret < 0) + return ret; + + num_units -= ret; + } + return 0; } @@ -7717,10 +7741,11 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar) /* free the host memory chunks requested by firmware */ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - dma_free_coherent(ar->dev, - ar->wmi.mem_chunks[i].len, - ar->wmi.mem_chunks[i].vaddr, - ar->wmi.mem_chunks[i].paddr); + dma_unmap_single(ar->dev, + ar->wmi.mem_chunks[i].paddr, + ar->wmi.mem_chunks[i].len, + DMA_TO_DEVICE); + kfree(ar->wmi.mem_chunks[i].vaddr); } ar->wmi.num_mem_chunks = 0; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 342563a3706f..3d946d8b2db2 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -767,7 +767,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; - rc_flags = info->control.rates[0].flags; + rc_flags = bf->rates[0].flags; hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0); diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 81ac8c59f0ec..7f3f94fbf157 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3930,8 +3930,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff; - ar->hw.tx_ant = 2; - ar->hw.rx_ant = 2; + ar->hw.tx_ant = 0x3; /* mask, 2 antenna */ + ar->hw.rx_ant = 0x3; } else { ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index fffb65b3e652..65c31da43c47 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2222,8 +2222,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, } if (status) { - ath6kl_err("failed to get pending recv messages: %d\n", - status); + if (status != -ECANCELED) + ath6kl_err("failed to get pending recv messages: %d\n", + status); /* cleanup any packets in sync completion queue */ list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) { diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6ae0734f86e0..da557dc742e6 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -954,8 +954,10 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name); ret = request_firmware(&fw, filename, ar->dev); - if (ret) + if (ret) { + ath6kl_err("Failed request firmware, rv: %d\n", ret); return ret; + } data = fw->data; len = fw->size; @@ -964,11 +966,15 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1; if (len < magic_len) { + ath6kl_err("Magic length is invalid, len: %zd magic_len: %zd\n", + len, magic_len); ret = -EINVAL; goto out; } if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) { + ath6kl_err("Magic is invalid, magic_len: %zd\n", + magic_len); ret = -EINVAL; goto out; } @@ -987,7 +993,12 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) len -= sizeof(*hdr); data += sizeof(*hdr); + ath6kl_dbg(ATH6KL_DBG_BOOT, "ie-id: %d len: %zd (0x%zx)\n", + ie_id, ie_len, ie_len); + if (len < ie_len) { + ath6kl_err("IE len is invalid, len: %zd ie_len: %zd ie-id: %d\n", + len, ie_len, ie_id); ret = -EINVAL; goto out; } @@ -1008,6 +1019,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); if (ar->fw_otp == NULL) { + ath6kl_err("fw_otp cannot be allocated\n"); ret = -ENOMEM; goto out; } @@ -1025,6 +1037,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->fw = vmalloc(ie_len); if (ar->fw == NULL) { + ath6kl_err("fw storage cannot be allocated, len: %zd\n", ie_len); ret = -ENOMEM; goto out; } @@ -1039,6 +1052,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); if (ar->fw_patch == NULL) { + ath6kl_err("fw_patch storage cannot be allocated, len: %zd\n", ie_len); ret = -ENOMEM; goto out; } diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index fee0cadb0f5e..40fa915d6f35 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,3 +176,14 @@ config ATH9K_HTC_DEBUGFS depends on ATH9K_HTC && DEBUG_FS ---help--- Say Y, if you need access to ath9k_htc's statistics. + +config ATH9K_HWRNG + bool "Random number generator support" + depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) + default y + ---help--- + This option incorporates the ADC register output as a source of + randomness into Linux entropy pool (/dev/urandom and /dev/random) + + Say Y, feeds the entropy directly from the WiFi driver to the input + pool. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index ecda613c2d54..76f9dc37500b 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o ath9k-$(CONFIG_ATH9K_WOW) += wow.o +ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b42f4a963ef4..5294595da5a7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "common.h" #include "debug.h" @@ -981,6 +982,7 @@ struct ath_softc { struct ath_offchannel offchannel; struct ath_chanctx *next_chan; struct completion go_beacon; + struct timespec last_event_time; #endif unsigned long driver_data; @@ -1040,6 +1042,11 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif + +#ifdef CONFIG_ATH9K_HWRNG + u32 rng_last; + struct task_struct *rng_task; +#endif }; /********/ @@ -1062,6 +1069,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc, } #endif /* CONFIG_ATH9K_TX99 */ +/***************************/ +/* Random Number Generator */ +/***************************/ +#ifdef CONFIG_ATH9K_HWRNG +void ath9k_rng_start(struct ath_softc *sc); +void ath9k_rng_stop(struct ath_softc *sc); +#else +static inline void ath9k_rng_start(struct ath_softc *sc) +{ +} + +static inline void ath9k_rng_stop(struct ath_softc *sc) +{ +} +#endif + static inline void ath_read_cachesize(struct ath_common *common, int *csz) { common->bus_ops->read_cachesize(common, csz); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index f50a6bc5d06e..5cf0cd7cb2d1 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -148,7 +148,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, ath_assign_seq(common, skb); - if (vif->p2p) + /* Always assign NOA attr when MCC enabled */ + if (ath9k_is_chanctx_enabled()) ath9k_beacon_add_noa(sc, avp, skb); bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 90f5773a1a61..50e614b915f1 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -226,6 +226,20 @@ static const char *chanctx_state_string(enum ath_chanctx_state state) } } +static const u32 chanctx_event_delta(struct ath_softc *sc) +{ + u64 ms; + struct timespec ts, *old; + + getrawmonotonic(&ts); + old = &sc->last_event_time; + ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + ms -= old->tv_sec * 1000 + old->tv_nsec / 1000000; + sc->last_event_time = ts; + + return (u32)ms; +} + void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -356,14 +370,16 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; + unsigned long timeout; ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); tsf_time -= ath9k_hw_gettsf32(ah); - tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; - mod_timer(&sc->sched.timer, jiffies + tsf_time); + timeout = msecs_to_jiffies(tsf_time / 1000) + 1; + mod_timer(&sc->sched.timer, jiffies + timeout); ath_dbg(common, CHAN_CTX, - "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time)); + "Setup chanctx timer with timeout: %d (%d) ms\n", + tsf_time / 1000, jiffies_to_msecs(timeout)); } static void ath_chanctx_handle_bmiss(struct ath_softc *sc, @@ -403,7 +419,7 @@ static void ath_chanctx_offchannel_noa(struct ath_softc *sc, avp->offchannel_duration = sc->sched.offchannel_duration; ath_dbg(common, CHAN_CTX, - "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n", + "offchannel noa_duration: %d, noa_start: %u, noa_index: %d\n", avp->offchannel_duration, avp->offchannel_start, avp->noa_index); @@ -443,7 +459,7 @@ static void ath_chanctx_set_periodic_noa(struct ath_softc *sc, avp->periodic_noa = true; ath_dbg(common, CHAN_CTX, - "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", + "noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n", avp->noa_duration, avp->noa_start, avp->noa_index, @@ -464,7 +480,7 @@ static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc, avp->noa_duration = duration + sc->sched.channel_switch_time; ath_dbg(common, CHAN_CTX, - "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", + "oneshot noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n", avp->noa_duration, avp->noa_start, avp->noa_index, @@ -487,10 +503,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, spin_lock_bh(&sc->chan_lock); - ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n", + ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s, delta: %u ms\n", sc->cur_chan->chandef.center_freq1, chanctx_event_string(ev), - chanctx_state_string(sc->sched.state)); + chanctx_state_string(sc->sched.state), + chanctx_event_delta(sc)); switch (ev) { case ATH_CHANCTX_EVENT_BEACON_PREPARE: @@ -1099,6 +1116,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + skb->priority = 7; skb_set_queue_mapping(skb, IEEE80211_AC_VO); if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { dev_kfree_skb_any(skb); @@ -1401,8 +1419,9 @@ void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx) static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - s32 tsf, target_tsf; + u32 tsf, target_tsf; if (!avp || !avp->noa.has_next_tsf) return; @@ -1414,11 +1433,17 @@ static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) target_tsf = avp->noa.next_tsf; if (!avp->noa.absent) target_tsf -= ATH_P2P_PS_STOP_TIME; + else + target_tsf += ATH_P2P_PS_STOP_TIME; if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) target_tsf = tsf + ATH_P2P_PS_STOP_TIME; - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); + ath_dbg(common, CHAN_CTX, "%s absent %d tsf 0x%08X next_tsf 0x%08X (%dms)\n", + __func__, avp->noa.absent, tsf, target_tsf, + (target_tsf - tsf) / 1000); + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, target_tsf, 1000000); } static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) @@ -1433,6 +1458,10 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) return; sc->p2p_ps_vif = avp; + + if (sc->ps_flags & PS_BEACON_SYNC) + return; + tsf = ath9k_hw_gettsf32(sc->sc_ah); ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); ath9k_update_p2p_ps_timer(sc, avp); @@ -1495,6 +1524,8 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, noa->index = avp->noa_index; noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); + if (noa->oppps_ctwindow) + noa->oppps_ctwindow |= BIT(7); if (avp->noa_duration) { if (avp->periodic_noa) { @@ -1536,6 +1567,8 @@ void ath9k_p2p_ps_timer(void *priv) tsf = ath9k_hw_gettsf32(sc->sc_ah); if (!avp->noa.absent) tsf += ATH_P2P_PS_STOP_TIME; + else + tsf -= ATH_P2P_PS_STOP_TIME; if (!avp->noa.has_next_tsf || avp->noa.next_tsf - tsf > BIT(31)) @@ -1571,8 +1604,7 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc, spin_lock_bh(&sc->sc_pcu_lock); spin_lock_irqsave(&sc->sc_pm_lock, flags); - if (!(sc->ps_flags & PS_BEACON_SYNC)) - ath9k_update_p2p_ps(sc, vif); + ath9k_update_p2p_ps(sc, vif); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); spin_unlock_bh(&sc->sc_pcu_lock); } diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 6ad44470d0f2..01d6d3205a65 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -18,30 +18,16 @@ #define FUDGE 2 -/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ -static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) -{ - u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; - - tsf_mod = tsf & (BIT(10) - 1); - tsf_hi = tsf >> 32; - tsf_lo = ((u32) tsf) >> 10; - - mod_hi = tsf_hi % div_tu; - mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; - - return (mod_lo << 10) | tsf_mod; -} - static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, unsigned int interval) { - unsigned int offset; + unsigned int offset, divisor; tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); - offset = ath9k_mod_tsf64_tu(tsf, interval); + divisor = TU_TO_USEC(interval); + div_u64_rem(tsf, divisor, &offset); - return (u32) tsf + TU_TO_USEC(interval) - offset; + return (u32) tsf + divisor - offset; } /* diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index cc81482c934d..f8c5065e5f5f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -138,6 +138,80 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) return ret; } +int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size) +{ + u16 magic; + u16 *eepdata; + int i; + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + ath_err(common, "Reading Magic # failed\n"); + return -EIO; + } + + if (magic == AR5416_EEPROM_MAGIC) { + *swap_needed = false; + } else if (swab16(magic) == AR5416_EEPROM_MAGIC) { + if (ah->ah_flags & AH_NO_EEP_SWAP) { + ath_info(common, + "Ignoring endianness difference in EEPROM magic bytes.\n"); + + *swap_needed = false; + } else { + *swap_needed = true; + } + } else { + ath_err(common, + "Invalid EEPROM Magic (0x%04x).\n", magic); + return -EINVAL; + } + + eepdata = (u16 *)(&ah->eeprom); + + if (*swap_needed) { + ath_dbg(common, EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); + + for (i = 0; i < size; i++) + eepdata[i] = swab16(eepdata[i]); + } + + return 0; +} + +bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size) +{ + u32 i, sum = 0; + u16 *eepdata = (u16 *)(&ah->eeprom); + struct ath_common *common = ath9k_hw_common(ah); + + for (i = 0; i < size; i++) + sum ^= eepdata[i]; + + if (sum != 0xffff) { + ath_err(common, "Bad EEPROM checksum 0x%x\n", sum); + return false; + } + + return true; +} + +bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (ah->eep_ops->get_eeprom_ver(ah) != version || + ah->eep_ops->get_eeprom_rev(ah) < minrev) { + ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n", + ah->eep_ops->get_eeprom_ver(ah), + ah->eep_ops->get_eeprom_rev(ah)); + return -EINVAL; + } + + return true; +} + void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 40d4f62d0f16..4465c6566f20 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -664,6 +664,9 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); +int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size); +bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size); +bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev); void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, int eep_start_loc, int size); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 4773da6dc6f2..5da0826bf1be 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -177,74 +177,30 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, } #endif - -#undef SIZE_EEPROM_4K - static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { -#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr; + u32 el; + bool need_swap; + int i, err; - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } - - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_4K); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.map4k.baseEepHeader.length); + el = swab16(eep->baseEepHeader.length); else - el = ah->eeprom.map4k.baseEepHeader.length; + el = eep->baseEepHeader.length; - if (el > sizeof(struct ar5416_eeprom_4k)) - el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_4K); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { u32 integer; u16 word; - ath_dbg(common, EEPROM, - "EEPROM Endianness is not native.. Changing\n"); - word = swab16(eep->baseEepHeader.length); eep->baseEepHeader.length = word; @@ -283,17 +239,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) } } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } return 0; -#undef EEPROM_4K_SIZE } +#undef SIZE_EEPROM_4K + static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 6ca33dfde1fd..1a019a39eda1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -177,59 +177,24 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) { - u32 sum = 0, el, integer; - u16 temp, word, magic, magic2, *eepdata; - int i, addr; - bool need_swap = false; + u32 el, integer; + u16 word; + int i, err; + bool need_swap; struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct ath_common *common = ath9k_hw_common(ah); - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } - - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *)(&ah->eeprom); - - for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.map9287.baseEepHeader.length); + el = swab16(eep->baseEepHeader.length); else - el = ah->eeprom.map9287.baseEepHeader.length; + el = eep->baseEepHeader.length; - if (el > sizeof(struct ar9287_eeprom)) - el = sizeof(struct ar9287_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_AR9287); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { word = swab16(eep->baseEepHeader.length); @@ -270,16 +235,15 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) } } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER - || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } return 0; } +#undef SIZE_EEPROM_AR9287 + static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 056f516bf017..959682f7909c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -126,8 +126,6 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) return __ath9k_hw_def_fill_eeprom(ah); } -#undef SIZE_EEPROM_DEF - #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_header *modal_hdr) @@ -257,59 +255,31 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, } #endif - static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct ath_common *common = ath9k_hw_common(ah); - u16 *eepdata, temp, magic; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; + u32 el; + bool need_swap; + int i, err; - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } - - if (swab16(magic) == AR5416_EEPROM_MAGIC && - !(ah->ah_flags & AH_NO_EEP_SWAP)) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_DEF); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.def.baseEepHeader.length); + el = swab16(eep->baseEepHeader.length); else - el = ah->eeprom.def.baseEepHeader.length; + el = eep->baseEepHeader.length; - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_DEF); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { u32 integer, j; u16 word; - ath_dbg(common, EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); - word = swab16(eep->baseEepHeader.length); eep->baseEepHeader.length = word; @@ -356,12 +326,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } /* Enable fixup for AR_AN_TOP2 if necessary */ if ((ah->hw_version.devid == AR9280_DEVID_PCI) && @@ -376,6 +343,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) return 0; } +#undef SIZE_EEPROM_DEF + static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 41382f89abe1..257f46ed4a04 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2299,10 +2299,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, else nextTbtt = bs->bs_nexttbtt; - ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim); - ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt); - ath_dbg(common, BEACON, "beacon period %d\n", beaconintval); - ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod); + ath_dbg(common, BEACON, "next DTIM %u\n", bs->bs_nextdtim); + ath_dbg(common, BEACON, "next beacon %u\n", nextTbtt); + ath_dbg(common, BEACON, "beacon period %u\n", beaconintval); + ath_dbg(common, BEACON, "DTIM period %u\n", dtimperiod); ENABLE_REGWRITE_BUFFER(ah); @@ -2761,9 +2761,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) ENABLE_REGWRITE_BUFFER(ah); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER; - REG_WRITE(ah, AR_RX_FILTER, bits); phybits = 0; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d184e682e636..c1b33fdcca08 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_restore(sc); + ath9k_rng_start(sc); + return 0; } @@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); + ath9k_rng_stop(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 994daf6c6297..32160fca876a 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -424,6 +424,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) AR_SREV_9561(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; + if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) + rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER; + if (ath9k_is_chanctx_enabled() && test_bit(ATH_OP_SCANNING, &common->op_flags)) rfilt |= ATH9K_RX_FILTER_BEACON; diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c new file mode 100644 index 000000000000..c9cb2aad7b6f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "ath9k.h" +#include "hw.h" +#include "ar9003_phy.h" + +#define ATH9K_RNG_BUF_SIZE 320 +#define ATH9K_RNG_ENTROPY(x) (((x) * 8 * 320) >> 10) /* quality: 320/1024 */ + +static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) +{ + int i, j; + u32 v1, v2, rng_last = sc->rng_last; + struct ath_hw *ah = sc->sc_ah; + + ath9k_ps_wakeup(sc); + + REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); + REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); + + for (i = 0, j = 0; i < buf_size; i++) { + v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; + v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; + + /* wait for data ready */ + if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff && + v2 != 0xffff) + buf[j++] = (v1 << 16) | v2; + + rng_last = v2; + } + + ath9k_ps_restore(sc); + + sc->rng_last = rng_last; + + return j << 2; +} + +static int ath9k_rng_kthread(void *data) +{ + int bytes_read; + struct ath_softc *sc = data; + u32 *rng_buf; + + rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL); + if (!rng_buf) + goto out; + + while (!kthread_should_stop()) { + bytes_read = ath9k_rng_data_read(sc, rng_buf, + ATH9K_RNG_BUF_SIZE); + if (unlikely(!bytes_read)) { + msleep_interruptible(10); + continue; + } + + /* sleep until entropy bits under write_wakeup_threshold */ + add_hwgenerator_randomness((void *)rng_buf, bytes_read, + ATH9K_RNG_ENTROPY(bytes_read)); + } + + kfree(rng_buf); +out: + sc->rng_task = NULL; + + return 0; +} + +void ath9k_rng_start(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (sc->rng_task) + return; + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + + sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng"); + if (IS_ERR(sc->rng_task)) + sc->rng_task = NULL; +} + +void ath9k_rng_stop(struct ath_softc *sc) +{ + if (sc->rng_task) + kthread_stop(sc->rng_task); +} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3e3dac3d7060..fe795fc5288c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1473,11 +1473,14 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *txtid; struct ath_txq *txq; struct ath_node *an; u8 density; + ath_dbg(common, XMIT, "%s called\n", __func__); + an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); txq = txtid->txq; @@ -1512,10 +1515,13 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = txtid->txq; + ath_dbg(common, XMIT, "%s called\n", __func__); + ath_txq_lock(sc, txq); txtid->active = false; ath_tx_flush_tid(sc, txtid); @@ -1526,11 +1532,14 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, struct ath_node *an) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *tid; struct ath_txq *txq; bool buffered; int tidno; + ath_dbg(common, XMIT, "%s called\n", __func__); + for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { @@ -1555,10 +1564,13 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *tid; struct ath_txq *txq; int tidno; + ath_dbg(common, XMIT, "%s called\n", __func__); + for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { @@ -1579,10 +1591,13 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tidno) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *tid; struct ath_node *an; struct ath_txq *txq; + ath_dbg(common, XMIT, "%s called\n", __func__); + an = (struct ath_node *)sta->drv_priv; tid = ATH_AN_2_TID(an, tidno); txq = tid->txq; @@ -2316,6 +2331,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, queue = ieee80211_is_data_present(hdr->frame_control); + /* If chanctx, queue all null frames while NOA could be there */ + if (ath9k_is_chanctx_enabled() && + ieee80211_is_nullfunc(hdr->frame_control) && + !txctl->force_channel) + queue = true; + /* Force queueing of all frames that belong to a virtual interface on * a different channel context, to ensure that they are sent on the * correct channel. @@ -2894,7 +2915,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, if (skb_headroom(skb) < padsize) { ath_dbg(common, XMIT, "tx99 padding failed\n"); - return -EINVAL; + return -EINVAL; } skb_push(skb, padsize); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 48687f128dc6..09b4daebab9d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -781,8 +781,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_bcast_fini(wil); - /* prevent NAPI from being scheduled */ + /* prevent NAPI from being scheduled and prevent wmi commands */ + mutex_lock(&wil->wmi_mutex); bitmap_zero(wil->status, wil_status_last); + mutex_unlock(&wil->wmi_mutex); if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6ed26baca0e5..e3ea74cdd4aa 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -228,6 +228,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); /* wait till FW finish with previous command */ for (retry = 5; retry > 0; retry--) { + if (!test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "WMI: cannot send command while FW not ready\n"); + return -EAGAIN; + } r->tail = wil_r(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.tail)); if (next_head != r->tail) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 771c5819a6e3..17658b326a6c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -91,6 +91,10 @@ #define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 #define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20 +#define BRCMF_SCAN_CHANNEL_TIME 40 +#define BRCMF_SCAN_UNASSOC_TIME 40 +#define BRCMF_SCAN_PASSIVE_TIME 120 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -392,15 +396,23 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, { int iftype_num[NUM_NL80211_IFTYPES]; struct brcmf_cfg80211_vif *pos; + bool check_combos = false; + int ret = 0; memset(&iftype_num[0], 0, sizeof(iftype_num)); list_for_each_entry(pos, &cfg->vif_list, list) - if (pos == vif) + if (pos == vif) { iftype_num[new_type]++; - else + } else { + /* concurrent interfaces so need check combinations */ + check_combos = true; iftype_num[pos->wdev.iftype]++; + } - return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); + if (check_combos) + ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); + + return ret; } static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, @@ -1027,11 +1039,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, struct brcmf_if *ifp = vif->ifp; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int; u32 passive_scan; bool escan_req; bool spec_scan; s32 err; + struct brcmf_ssid_le ssid_le; u32 SSID_len; brcmf_dbg(SCAN, "START ESCAN\n"); @@ -1084,13 +1096,13 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, } else { brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n", ssids->ssid, ssids->ssid_len); - memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); - SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); - sr->ssid_le.SSID_len = cpu_to_le32(0); + memset(&ssid_le, 0, sizeof(ssid_le)); + SSID_len = min_t(u8, sizeof(ssid_le.SSID), ssids->ssid_len); + ssid_le.SSID_len = cpu_to_le32(0); spec_scan = false; if (SSID_len) { - memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); - sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); + memcpy(ssid_le.SSID, ssids->ssid, SSID_len); + ssid_le.SSID_len = cpu_to_le32(SSID_len); spec_scan = true; } else brcmf_dbg(SCAN, "Broadcast scan\n"); @@ -1103,12 +1115,12 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, goto scan_out; } brcmf_scan_config_mpc(ifp, 0); - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, - &sr->ssid_le, sizeof(sr->ssid_le)); + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &ssid_le, + sizeof(ssid_le)); if (err) { if (err == -EBUSY) brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n", - sr->ssid_le.SSID); + ssid_le.SSID); else brcmf_err("WLC_SCAN error (%d)\n", err); @@ -1261,17 +1273,17 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) brcmf_dbg(TRACE, "Enter\n"); - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { + if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n "); err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); if (err) { brcmf_err("WLC_DISASSOC failed (%d)\n", err); } - clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); - cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, - true, GFP_KERNEL); - + if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) || + (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) + cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, + true, GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); @@ -2685,8 +2697,8 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg) return err; } -static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, const u8 *bssid) +static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, + struct net_device *ndev, const u8 *bssid) { struct wiphy *wiphy = cfg_to_wiphy(cfg); struct ieee80211_channel *notify_channel; @@ -2731,6 +2743,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, band = wiphy->bands[IEEE80211_BAND_5GHZ]; freq = ieee80211_channel_to_frequency(ch.chnum, band->band); + cfg->channel = freq; notify_channel = ieee80211_get_channel(wiphy, freq); notify_capability = le16_to_cpu(bi->capability); @@ -3219,26 +3232,22 @@ exit: } static __used s32 -brcmf_update_pmklist(struct net_device *ndev, - struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) +brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { - int i, j; - u32 pmkid_len; + struct brcmf_pmk_list_le *pmk_list; + int i; + u32 npmk; + s32 err; - pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); + pmk_list = &cfg->pmk_list; + npmk = le32_to_cpu(pmk_list->npmk); - brcmf_dbg(CONN, "No of elements %d\n", pmkid_len); - for (i = 0; i < pmkid_len; i++) { - brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID); - for (j = 0; j < WLAN_PMKID_LEN; j++) - brcmf_dbg(CONN, "%02x\n", - pmk_list->pmkids.pmkid[i].PMKID[j]); - } + brcmf_dbg(CONN, "No of elements %d\n", npmk); + for (i = 0; i < npmk; i++) + brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid); - if (!err) - brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info", - (char *)pmk_list, sizeof(*pmk_list)); + err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list, + sizeof(*pmk_list)); return err; } @@ -3249,34 +3258,37 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); - struct pmkid_list *pmkids = &cfg->pmk_list->pmkids; - s32 err = 0; - u32 pmkid_len, i; + struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; + s32 err; + u32 npmk, i; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) return -EIO; - pmkid_len = le32_to_cpu(pmkids->npmkid); - for (i = 0; i < pmkid_len; i++) - if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) + npmk = le32_to_cpu(cfg->pmk_list.npmk); + for (i = 0; i < npmk; i++) + if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) break; - if (i < WL_NUM_PMKIDS_MAX) { - memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); - memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); - if (i == pmkid_len) { - pmkid_len++; - pmkids->npmkid = cpu_to_le32(pmkid_len); + if (i < BRCMF_MAXPMKID) { + memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN); + memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + if (i == npmk) { + npmk++; + cfg->pmk_list.npmk = cpu_to_le32(npmk); } - } else - err = -EINVAL; + } else { + brcmf_err("Too many PMKSA entries cached %d\n", npmk); + return -EINVAL; + } - brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - pmkids->pmkid[pmkid_len].BSSID); - for (i = 0; i < WLAN_PMKID_LEN; i++) - brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); + brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid); + for (i = 0; i < WLAN_PMKID_LEN; i += 4) + brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i], + pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2], + pmk[npmk].pmkid[i + 3]); - err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); + err = brcmf_update_pmklist(cfg, ifp); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -3284,50 +3296,39 @@ brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, static s32 brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_pmksa *pmksa) + struct cfg80211_pmksa *pmksa) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); - struct pmkid_list pmkid; - s32 err = 0; - u32 pmkid_len, i; + struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; + s32 err; + u32 npmk, i; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) return -EIO; - memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); - memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); + brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid); - brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID); - for (i = 0; i < WLAN_PMKID_LEN; i++) - brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]); - - pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid); - for (i = 0; i < pmkid_len; i++) - if (!memcmp - (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID, - ETH_ALEN)) + npmk = le32_to_cpu(cfg->pmk_list.npmk); + for (i = 0; i < npmk; i++) + if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN)) break; - if ((pmkid_len > 0) - && (i < pmkid_len)) { - memset(&cfg->pmk_list->pmkids.pmkid[i], 0, - sizeof(struct pmkid)); - for (; i < (pmkid_len - 1); i++) { - memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, - &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID, - ETH_ALEN); - memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, - &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID, + if ((npmk > 0) && (i < npmk)) { + for (; i < (npmk - 1); i++) { + memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN); + memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid, WLAN_PMKID_LEN); } - cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1); - } else - err = -EINVAL; + memset(&pmk[i], 0, sizeof(*pmk)); + cfg->pmk_list.npmk = cpu_to_le32(npmk - 1); + } else { + brcmf_err("Cache entry not found\n"); + return -EINVAL; + } - err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); + err = brcmf_update_pmklist(cfg, ifp); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -3339,14 +3340,14 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); - s32 err = 0; + s32 err; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) return -EIO; - memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list)); - err = brcmf_update_pmklist(ndev, cfg->pmk_list, err); + memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list)); + err = brcmf_update_pmklist(cfg, ifp); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -5071,9 +5072,9 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, } else if (brcmf_is_linkup(e)) { brcmf_dbg(CONN, "Linkup\n"); if (brcmf_is_ibssmode(ifp->vif)) { + brcmf_inform_ibss(cfg, ndev, e->addr); chan = ieee80211_get_channel(cfg->wiphy, cfg->channel); memcpy(profile->bssid, e->addr, ETH_ALEN); - wl_inform_ibss(cfg, ndev, e->addr); cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL); clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); @@ -5199,7 +5200,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; conf->retry_long = (u32)-1; - conf->tx_power = -1; } static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) @@ -5246,8 +5246,6 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) cfg->escan_ioctl_buf = NULL; kfree(cfg->extra_buf); cfg->extra_buf = NULL; - kfree(cfg->pmk_list); - cfg->pmk_list = NULL; } static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -5261,9 +5259,6 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!cfg->extra_buf) goto init_priv_mem_out; - cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); - if (!cfg->pmk_list) - goto init_priv_mem_out; return 0; @@ -5357,37 +5352,27 @@ roam_setup_done: } static s32 -brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time, - s32 scan_unassoc_time, s32 scan_passive_time) +brcmf_dongle_scantime(struct brcmf_if *ifp) { s32 err = 0; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, - scan_assoc_time); + BRCMF_SCAN_CHANNEL_TIME); if (err) { - if (err == -EOPNOTSUPP) - brcmf_dbg(INFO, "Scan assoc time is not supported\n"); - else - brcmf_err("Scan assoc time error (%d)\n", err); + brcmf_err("Scan assoc time error (%d)\n", err); goto dongle_scantime_out; } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME, - scan_unassoc_time); + BRCMF_SCAN_UNASSOC_TIME); if (err) { - if (err == -EOPNOTSUPP) - brcmf_dbg(INFO, "Scan unassoc time is not supported\n"); - else - brcmf_err("Scan unassoc time error (%d)\n", err); + brcmf_err("Scan unassoc time error (%d)\n", err); goto dongle_scantime_out; } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME, - scan_passive_time); + BRCMF_SCAN_PASSIVE_TIME); if (err) { - if (err == -EOPNOTSUPP) - brcmf_dbg(INFO, "Scan passive time is not supported\n"); - else - brcmf_err("Scan passive time error (%d)\n", err); + brcmf_err("Scan passive time error (%d)\n", err); goto dongle_scantime_out; } @@ -5978,7 +5963,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; - wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; + wiphy->max_num_pmkids = BRCMF_MAXPMKID; err = brcmf_setup_ifmodes(wiphy, ifp); if (err) @@ -6007,8 +5992,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | WIPHY_FLAG_OFFCHAN_TX | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_SUPPORTS_TDLS; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; if (!brcmf_roamoff) wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; wiphy->mgmt_stypes = brcmf_txrx_stypes; @@ -6089,8 +6075,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) /* make sure RF is ready for work */ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); - brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME, - WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); + brcmf_dongle_scantime(ifp); power_mode = cfg->pwr_save ? PM_FAST : PM_OFF; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode); @@ -6401,13 +6386,15 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, goto wiphy_unreg_out; } - err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); - if (err) { - brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); - wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; - } else { - brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT, - brcmf_notify_tdls_peer_event); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) { + err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); + if (err) { + brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; + } else { + brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT, + brcmf_notify_tdls_peer_event); + } } /* (re-) activate FWEH event handling */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index d492163e4de9..c17b6d584fe0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -21,7 +21,6 @@ #include #define WL_NUM_SCAN_MAX 10 -#define WL_NUM_PMKIDS_MAX MAXPMKID #define WL_TLV_INFO_MAX 1024 #define WL_BSS_INFO_MAX 2048 #define WL_ASSOC_INFO_MAX 512 /* assoc related fil max buf */ @@ -29,10 +28,6 @@ #define WL_ROAM_TRIGGER_LEVEL -75 #define WL_ROAM_DELTA 20 -#define WL_SCAN_CHANNEL_TIME 40 -#define WL_SCAN_UNASSOC_TIME 40 -#define WL_SCAN_PASSIVE_TIME 120 - #define WL_ESCAN_BUF_SIZE (1024 * 64) #define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */ @@ -99,19 +94,6 @@ struct brcmf_cfg80211_conf { u32 rts_threshold; u32 retry_short; u32 retry_long; - s32 tx_power; - struct ieee80211_channel channel; -}; - -/* basic structure of scan request */ -struct brcmf_cfg80211_scan_req { - struct brcmf_ssid_le ssid_le; -}; - -/* basic structure of information element */ -struct brcmf_cfg80211_ie { - u16 offset; - u8 buf[WL_TLV_INFO_MAX]; }; /* security information with currently associated ap */ @@ -213,12 +195,6 @@ struct brcmf_cfg80211_assoc_ielen_le { __le32 resp_len; }; -/* wpa2 pmk list */ -struct brcmf_cfg80211_pmk_list { - struct pmkid_list pmkids; - struct pmkid foo[MAXPMKID - 1]; -}; - /* dongle escan state */ enum wl_escan_state { WL_ESCAN_STATE_IDLE, @@ -234,87 +210,6 @@ struct escan_info { struct cfg80211_scan_request *request); }; -/** - * struct brcmf_pno_param_le - PNO scan configuration parameters - * - * @version: PNO parameters version. - * @scan_freq: scan frequency. - * @lost_network_timeout: #sec. to declare discovered network as lost. - * @flags: Bit field to control features of PFN such as sort criteria auto - * enable switch and background scan. - * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort - * criteria. - * @bestn: number of best networks in each scan. - * @mscan: number of scans recorded. - * @repeat: minimum number of scan intervals before scan frequency changes - * in adaptive scan. - * @exp: exponent of 2 for maximum scan interval. - * @slow_freq: slow scan period. - */ -struct brcmf_pno_param_le { - __le32 version; - __le32 scan_freq; - __le32 lost_network_timeout; - __le16 flags; - __le16 rssi_margin; - u8 bestn; - u8 mscan; - u8 repeat; - u8 exp; - __le32 slow_freq; -}; - -/** - * struct brcmf_pno_net_param_le - scan parameters per preferred network. - * - * @ssid: ssid name and its length. - * @flags: bit2: hidden. - * @infra: BSS vs IBSS. - * @auth: Open vs Closed. - * @wpa_auth: WPA type. - * @wsec: wsec value. - */ -struct brcmf_pno_net_param_le { - struct brcmf_ssid_le ssid; - __le32 flags; - __le32 infra; - __le32 auth; - __le32 wpa_auth; - __le32 wsec; -}; - -/** - * struct brcmf_pno_net_info_le - information per found network. - * - * @bssid: BSS network identifier. - * @channel: channel number only. - * @SSID_len: length of ssid. - * @SSID: ssid characters. - * @RSSI: receive signal strength (in dBm). - * @timestamp: age in seconds. - */ -struct brcmf_pno_net_info_le { - u8 bssid[ETH_ALEN]; - u8 channel; - u8 SSID_len; - u8 SSID[32]; - __le16 RSSI; - __le16 timestamp; -}; - -/** - * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event. - * - * @version: PNO version identifier. - * @status: indicates completion status of PNO scan. - * @count: amount of brcmf_pno_net_info_le entries appended. - */ -struct brcmf_pno_scanresults_le { - __le32 version; - __le32 status; - __le32 count; -}; - /** * struct brcmf_cfg80211_vif_event - virtual interface event information. * @@ -341,9 +236,7 @@ struct brcmf_cfg80211_vif_event { * @scan_request: cfg80211 scan request object. * @usr_sync: mainly for dongle up/down synchronization. * @bss_list: bss_list holding scanned ap information. - * @scan_req_int: internal scan request object. * @bss_info: bss information for cfg80211 layer. - * @ie: information element object for internal purpose. * @conn_info: association info. * @pmk_list: wpa2 pmk list. * @scan_status: scan activity on the dongle. @@ -376,11 +269,9 @@ struct brcmf_cfg80211_info { struct brcmf_btcoex_info *btcoex; struct cfg80211_scan_request *scan_request; struct mutex usr_sync; - struct brcmf_cfg80211_scan_req scan_req_int; struct wl_cfg80211_bss_info *bss_info; - struct brcmf_cfg80211_ie ie; struct brcmf_cfg80211_connect_info conn_info; - struct brcmf_cfg80211_pmk_list *pmk_list; + struct brcmf_pmk_list_le pmk_list; unsigned long scan_status; struct brcmf_pub *pub; u32 channel; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index ba5249403036..d9d1ca4b93ec 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -138,6 +138,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode"); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable"); if (brcmf_feature_disable) { brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 538175882c8a..13906568bc2d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -25,6 +25,7 @@ * WOWL: Wake-On-WLAN. * P2P: peer-to-peer * RSDB: Real Simultaneous Dual Band + * TDLS: Tunneled Direct Link Setup */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -32,7 +33,8 @@ BRCMF_FEAT_DEF(PNO) \ BRCMF_FEAT_DEF(WOWL) \ BRCMF_FEAT_DEF(P2P) \ - BRCMF_FEAT_DEF(RSDB) + BRCMF_FEAT_DEF(RSDB) \ + BRCMF_FEAT_DEF(TDLS) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 18483e782bfe..94d34ad3a6e6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -126,6 +126,8 @@ #define BRCMF_TXBF_SU_BFR_CAP BIT(0) #define BRCMF_TXBF_MU_BFR_CAP BIT(1) +#define BRCMF_MAXPMKID 16 /* max # PMKID cache entries */ + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1, @@ -646,4 +648,107 @@ struct brcmf_wowl_wakeind_le { __le32 ucode_wakeind; }; +/** + * struct brcmf_pmksa - PMK Security Association + * + * @bssid: The AP's BSSID. + * @pmkid: he PMK material itself. + */ +struct brcmf_pmksa { + u8 bssid[ETH_ALEN]; + u8 pmkid[WLAN_PMKID_LEN]; +}; + +/** + * struct brcmf_pmk_list_le - List of pmksa's. + * + * @npmk: Number of pmksa's. + * @pmk: PMK SA information. + */ +struct brcmf_pmk_list_le { + __le32 npmk; + struct brcmf_pmksa pmk[BRCMF_MAXPMKID]; +}; + +/** + * struct brcmf_pno_param_le - PNO scan configuration parameters + * + * @version: PNO parameters version. + * @scan_freq: scan frequency. + * @lost_network_timeout: #sec. to declare discovered network as lost. + * @flags: Bit field to control features of PFN such as sort criteria auto + * enable switch and background scan. + * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort + * criteria. + * @bestn: number of best networks in each scan. + * @mscan: number of scans recorded. + * @repeat: minimum number of scan intervals before scan frequency changes + * in adaptive scan. + * @exp: exponent of 2 for maximum scan interval. + * @slow_freq: slow scan period. + */ +struct brcmf_pno_param_le { + __le32 version; + __le32 scan_freq; + __le32 lost_network_timeout; + __le16 flags; + __le16 rssi_margin; + u8 bestn; + u8 mscan; + u8 repeat; + u8 exp; + __le32 slow_freq; +}; + +/** + * struct brcmf_pno_net_param_le - scan parameters per preferred network. + * + * @ssid: ssid name and its length. + * @flags: bit2: hidden. + * @infra: BSS vs IBSS. + * @auth: Open vs Closed. + * @wpa_auth: WPA type. + * @wsec: wsec value. + */ +struct brcmf_pno_net_param_le { + struct brcmf_ssid_le ssid; + __le32 flags; + __le32 infra; + __le32 auth; + __le32 wpa_auth; + __le32 wsec; +}; + +/** + * struct brcmf_pno_net_info_le - information per found network. + * + * @bssid: BSS network identifier. + * @channel: channel number only. + * @SSID_len: length of ssid. + * @SSID: ssid characters. + * @RSSI: receive signal strength (in dBm). + * @timestamp: age in seconds. + */ +struct brcmf_pno_net_info_le { + u8 bssid[ETH_ALEN]; + u8 channel; + u8 SSID_len; + u8 SSID[32]; + __le16 RSSI; + __le16 timestamp; +}; + +/** + * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event. + * + * @version: PNO version identifier. + * @status: indicates completion status of PNO scan. + * @count: amount of brcmf_pno_net_info_le entries appended. + */ +struct brcmf_pno_scanresults_le { + __le32 version; + __le32 status; + __le32 count; +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index ffdc7f82df4b..e5f5fac9f9b3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -1609,10 +1609,11 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp, { struct brcmf_fws_info *fws = ifp->drvr->fws; - brcmf_fws_lock(fws); - if (fws) + if (fws) { + brcmf_fws_lock(fws); fws->bcmc_credit_check = true; - brcmf_fws_unlock(fws); + brcmf_fws_unlock(fws); + } return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 44e618f9d890..5df91386e13a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -473,8 +473,7 @@ static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf) static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf) { msgbuf->ctl_completed = true; - if (waitqueue_active(&msgbuf->ioctl_resp_wait)) - wake_up(&msgbuf->ioctl_resp_wait); + wake_up(&msgbuf->ioctl_resp_wait); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index b5a4247604f3..3d2d790d3ad6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -46,6 +46,7 @@ enum brcmf_pcie_state { BRCMF_FW_NVRAM_DEF(43602, "brcmfmac43602-pcie.bin", "brcmfmac43602-pcie.txt"); BRCMF_FW_NVRAM_DEF(4350, "brcmfmac4350-pcie.bin", "brcmfmac4350-pcie.txt"); +BRCMF_FW_NVRAM_DEF(4350C, "brcmfmac4350c2-pcie.bin", "brcmfmac4350c2-pcie.txt"); BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-pcie.bin", "brcmfmac4356-pcie.txt"); BRCMF_FW_NVRAM_DEF(43570, "brcmfmac43570-pcie.bin", "brcmfmac43570-pcie.txt"); BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt"); @@ -56,7 +57,8 @@ BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFFFF, 4350), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), @@ -1873,7 +1875,7 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev) struct brcmf_pciedev_info *devinfo; struct brcmf_bus *bus; - brcmf_err("Enter\n"); + brcmf_dbg(PCIE, "Enter\n"); bus = dev_get_drvdata(dev); devinfo = bus->bus_priv.pcie->devinfo; @@ -1904,7 +1906,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) struct pci_dev *pdev; int err; - brcmf_err("Enter\n"); + brcmf_dbg(PCIE, "Enter\n"); bus = dev_get_drvdata(dev); devinfo = bus->bus_priv.pcie->devinfo; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 9fa3a3a0f12c..ceb2a754308e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1678,8 +1678,7 @@ static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, static int brcmf_sdio_dcmd_resp_wake(struct brcmf_sdio *bus) { - if (waitqueue_active(&bus->dcmd_resp_wait)) - wake_up_interruptible(&bus->dcmd_resp_wait); + wake_up_interruptible(&bus->dcmd_resp_wait); return 0; } @@ -2003,8 +2002,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) static void brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus) { - if (waitqueue_active(&bus->ctrl_wait)) - wake_up_interruptible(&bus->ctrl_wait); + wake_up_interruptible(&bus->ctrl_wait); return; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index ccde5599c401..66c26a92b29c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -196,8 +196,7 @@ static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo) static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) { - if (waitqueue_active(&devinfo->ioctl_resp_wait)) - wake_up(&devinfo->ioctl_resp_wait); + wake_up(&devinfo->ioctl_resp_wait); } static void @@ -1453,6 +1452,7 @@ static struct usb_device_id brcmf_usb_devid_table[] = { BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID), + { USB_DEVICE(BRCM_USB_VENDOR_ID_LG, BRCM_USB_43242_LG_DEVICE_ID) }, /* special entry for device with firmware loaded and running */ BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID), { /* end: all zeroes */ } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index 635ae034c7e5..38bd5890bd53 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -177,8 +177,8 @@ static bool brcms_c_country_valid(const char *ccode) * only allow ascii alpha uppercase for the first 2 * chars. */ - if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && - (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A)) + if (!((ccode[0] & 0x80) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && + (ccode[1] & 0x80) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A)) return false; /* diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 4092d2789979..699f2c2782ee 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -21,6 +21,7 @@ #include #define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c +#define BRCM_USB_VENDOR_ID_LG 0x043e #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM /* Chipcommon Core Chip IDs */ @@ -57,6 +58,7 @@ #define BRCM_USB_43143_DEVICE_ID 0xbd1e #define BRCM_USB_43236_DEVICE_ID 0xbd17 #define BRCM_USB_43242_DEVICE_ID 0xbd1f +#define BRCM_USB_43242_LG_DEVICE_ID 0x3101 #define BRCM_USB_43569_DEVICE_ID 0xbd27 #define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 76b5d3a86294..3f68dd5ecd11 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -237,9 +237,6 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define WPA2_AUTH_RESERVED4 0x0400 #define WPA2_AUTH_RESERVED5 0x0800 -/* pmkid */ -#define MAXPMKID 16 - #define DOT11_DEFAULT_RTS_LEN 2347 #define DOT11_DEFAULT_FRAG_LEN 2346 @@ -251,24 +248,4 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define HT_CAP_RX_STBC_NO 0x0 #define HT_CAP_RX_STBC_ONE_STREAM 0x1 -struct pmkid { - u8 BSSID[ETH_ALEN]; - u8 PMKID[WLAN_PMKID_LEN]; -}; - -struct pmkid_list { - __le32 npmkid; - struct pmkid pmkid[1]; -}; - -struct pmkid_cand { - u8 BSSID[ETH_ALEN]; - u8 preauth; -}; - -struct pmkid_cand_list { - u32 npmkid_cand; - struct pmkid_cand pmkid_cand[1]; -}; - #endif /* _BRCMU_WIFI_H_ */ diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 887114582583..eb5cb603bc52 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -1865,14 +1865,14 @@ il_send_add_sta(struct il_priv *il, struct il_addsta_cmd *sta, u8 flags) cmd.len = il->ops->build_addsta_hcmd(sta, data); ret = il_send_cmd(il, &cmd); - - if (ret || (flags & CMD_ASYNC)) + if (ret) return ret; + if (flags & CMD_ASYNC) + return 0; + + pkt = (struct il_rx_pkt *)cmd.reply_page; + ret = il_process_add_sta_resp(il, sta, pkt, true); - if (ret == 0) { - pkt = (struct il_rx_pkt *)cmd.reply_page; - ret = il_process_add_sta_resp(il, sta, pkt, true); - } il_free_pages(il, cmd.reply_page); return ret; @@ -3602,7 +3602,7 @@ il_is_ht40_tx_allowed(struct il_priv *il, struct ieee80211_sta_ht_cap *ht_cap) } EXPORT_SYMBOL(il_is_ht40_tx_allowed); -static u16 +static u16 noinline il_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) { u16 new_val; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index 991def878881..9de277c6c420 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -473,13 +473,4 @@ do { \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ -extern const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1]; - -static inline const char *iwl_dvm_get_cmd_string(u8 cmd) -{ - const char *s = iwl_dvm_cmd_strings[cmd]; - if (s) - return s; - return "UNKNOWN"; -} #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c index 9be636268848..07a4c644fb9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c @@ -311,7 +311,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv, /* If previous beacon had too many false alarms, * give it some extra margin by reducing sensitivity again * (but don't go below measured energy of desired Rx) */ - if (IWL_FA_TOO_MANY == data->nrg_prev_state) { + if (data->nrg_prev_state == IWL_FA_TOO_MANY) { IWL_DEBUG_CALIB(priv, "... increasing margin\n"); if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN)) data->nrg_th_cck -= NRG_MARGIN; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index b15e44f8d1bd..74c51615244e 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -22,7 +22,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -32,7 +32,9 @@ #include #include #include + #include "iwl-debug.h" +#include "iwl-trans.h" #include "iwl-io.h" #include "dev.h" #include "agn.h" @@ -438,7 +440,7 @@ static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file, if (priv->rx_handlers_stats[cnt] > 0) pos += scnprintf(buf + pos, bufsz - pos, "\tRx handler[%36s]:\t\t %u\n", - iwl_dvm_get_cmd_string(cnt), + iwl_get_cmd_string(priv->trans, (u32)cnt), priv->rx_handlers_stats[cnt]); } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 0ba3e56d6015..1a7ead753eee 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.h b/drivers/net/wireless/intel/iwlwifi/dvm/led.h index 1c6b2252d0f2..75f74edd018f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index a612fbe66377..bee1c03ee259 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -1262,7 +1262,7 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_FW_ERROR, &priv->status)) { IWL_ERR(priv, "Command %s failed: FW Error\n", - iwl_dvm_get_cmd_string(cmd->id)); + iwl_get_cmd_string(priv->trans, cmd->id)); return -EIO; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index a9d8b51419b4..29ea1c6705b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -115,6 +115,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, WANT_MONITOR_VIF); + if (priv->trans->max_skb_frags) + hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; + hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 41f3aa17475e..f62c2d727ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -22,7 +23,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -69,6 +70,93 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search. + * A warning will be triggered on violation. + */ +static const struct iwl_hcmd_names iwl_dvm_cmd_names[] = { + HCMD_NAME(REPLY_ALIVE), + HCMD_NAME(REPLY_ERROR), + HCMD_NAME(REPLY_ECHO), + HCMD_NAME(REPLY_RXON), + HCMD_NAME(REPLY_RXON_ASSOC), + HCMD_NAME(REPLY_QOS_PARAM), + HCMD_NAME(REPLY_RXON_TIMING), + HCMD_NAME(REPLY_ADD_STA), + HCMD_NAME(REPLY_REMOVE_STA), + HCMD_NAME(REPLY_REMOVE_ALL_STA), + HCMD_NAME(REPLY_TX), + HCMD_NAME(REPLY_TXFIFO_FLUSH), + HCMD_NAME(REPLY_WEPKEY), + HCMD_NAME(REPLY_LEDS_CMD), + HCMD_NAME(REPLY_TX_LINK_QUALITY_CMD), + HCMD_NAME(COEX_PRIORITY_TABLE_CMD), + HCMD_NAME(COEX_MEDIUM_NOTIFICATION), + HCMD_NAME(COEX_EVENT_CMD), + HCMD_NAME(TEMPERATURE_NOTIFICATION), + HCMD_NAME(CALIBRATION_CFG_CMD), + HCMD_NAME(CALIBRATION_RES_NOTIFICATION), + HCMD_NAME(CALIBRATION_COMPLETE_NOTIFICATION), + HCMD_NAME(REPLY_QUIET_CMD), + HCMD_NAME(REPLY_CHANNEL_SWITCH), + HCMD_NAME(CHANNEL_SWITCH_NOTIFICATION), + HCMD_NAME(REPLY_SPECTRUM_MEASUREMENT_CMD), + HCMD_NAME(SPECTRUM_MEASURE_NOTIFICATION), + HCMD_NAME(POWER_TABLE_CMD), + HCMD_NAME(PM_SLEEP_NOTIFICATION), + HCMD_NAME(PM_DEBUG_STATISTIC_NOTIFIC), + HCMD_NAME(REPLY_SCAN_CMD), + HCMD_NAME(REPLY_SCAN_ABORT_CMD), + HCMD_NAME(SCAN_START_NOTIFICATION), + HCMD_NAME(SCAN_RESULTS_NOTIFICATION), + HCMD_NAME(SCAN_COMPLETE_NOTIFICATION), + HCMD_NAME(BEACON_NOTIFICATION), + HCMD_NAME(REPLY_TX_BEACON), + HCMD_NAME(WHO_IS_AWAKE_NOTIFICATION), + HCMD_NAME(REPLY_TX_POWER_DBM_CMD), + HCMD_NAME(QUIET_NOTIFICATION), + HCMD_NAME(REPLY_TX_PWR_TABLE_CMD), + HCMD_NAME(REPLY_TX_POWER_DBM_CMD_V1), + HCMD_NAME(TX_ANT_CONFIGURATION_CMD), + HCMD_NAME(MEASURE_ABORT_NOTIFICATION), + HCMD_NAME(REPLY_BT_CONFIG), + HCMD_NAME(REPLY_STATISTICS_CMD), + HCMD_NAME(STATISTICS_NOTIFICATION), + HCMD_NAME(REPLY_CARD_STATE_CMD), + HCMD_NAME(CARD_STATE_NOTIFICATION), + HCMD_NAME(MISSED_BEACONS_NOTIFICATION), + HCMD_NAME(REPLY_CT_KILL_CONFIG_CMD), + HCMD_NAME(SENSITIVITY_CMD), + HCMD_NAME(REPLY_PHY_CALIBRATION_CMD), + HCMD_NAME(REPLY_WIPAN_PARAMS), + HCMD_NAME(REPLY_WIPAN_RXON), + HCMD_NAME(REPLY_WIPAN_RXON_TIMING), + HCMD_NAME(REPLY_WIPAN_RXON_ASSOC), + HCMD_NAME(REPLY_WIPAN_QOS_PARAM), + HCMD_NAME(REPLY_WIPAN_WEPKEY), + HCMD_NAME(REPLY_WIPAN_P2P_CHANNEL_SWITCH), + HCMD_NAME(REPLY_WIPAN_NOA_NOTIFICATION), + HCMD_NAME(REPLY_WIPAN_DEACTIVATION_COMPLETE), + HCMD_NAME(REPLY_RX_PHY_CMD), + HCMD_NAME(REPLY_RX_MPDU_CMD), + HCMD_NAME(REPLY_RX), + HCMD_NAME(REPLY_COMPRESSED_BA), + HCMD_NAME(REPLY_BT_COEX_PRIO_TABLE), + HCMD_NAME(REPLY_BT_COEX_PROT_ENV), + HCMD_NAME(REPLY_BT_COEX_PROFILE_NOTIF), + HCMD_NAME(REPLY_D3_CONFIG), + HCMD_NAME(REPLY_WOWLAN_PATTERNS), + HCMD_NAME(REPLY_WOWLAN_WAKEUP_FILTER), + HCMD_NAME(REPLY_WOWLAN_TSC_RSC_PARAMS), + HCMD_NAME(REPLY_WOWLAN_TKIP_PARAMS), + HCMD_NAME(REPLY_WOWLAN_KEK_KCK_MATERIAL), + HCMD_NAME(REPLY_WOWLAN_GET_STATUS), +}; + +static const struct iwl_hcmd_arr iwl_dvm_groups[] = { + [0x0] = HCMD_ARR(iwl_dvm_cmd_names), +}; + static const struct iwl_op_mode_ops iwl_dvm_ops; void iwl_update_chain_flags(struct iwl_priv *priv) @@ -341,7 +429,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); /* Make sure device is powered up for SRAM reads */ - if (!iwl_trans_grab_nic_access(priv->trans, false, ®_flags)) + if (!iwl_trans_grab_nic_access(priv->trans, ®_flags)) return; /* Set starting address; reads will auto-increment */ @@ -1244,7 +1332,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED; - trans_cfg.command_names = iwl_dvm_cmd_strings; + trans_cfg.command_groups = iwl_dvm_groups; + trans_cfg.command_groups_size = ARRAY_SIZE(iwl_dvm_groups); + trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < @@ -1265,6 +1355,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); + trans->command_groups = trans_cfg.command_groups; + trans->command_groups_size = trans_cfg.command_groups_size; /* At this point both hw and priv are allocated. */ @@ -1639,7 +1731,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); /* Make sure device is powered up for SRAM reads */ - if (!iwl_trans_grab_nic_access(trans, false, ®_flags)) + if (!iwl_trans_grab_nic_access(trans, ®_flags)) return pos; /* Set starting address; reads will auto-increment */ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index cef921c1a623..ee7505537c96 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h index f6bd25cad203..c5fe44584613 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 4a45b0b594c7..52ab1e012e8f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. @@ -22,7 +23,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -32,91 +33,13 @@ #include #include #include + +#include "iwl-trans.h" #include "iwl-io.h" #include "dev.h" #include "calib.h" #include "agn.h" -#define IWL_CMD_ENTRY(x) [x] = #x - -const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1] = { - IWL_CMD_ENTRY(REPLY_ALIVE), - IWL_CMD_ENTRY(REPLY_ERROR), - IWL_CMD_ENTRY(REPLY_ECHO), - IWL_CMD_ENTRY(REPLY_RXON), - IWL_CMD_ENTRY(REPLY_RXON_ASSOC), - IWL_CMD_ENTRY(REPLY_QOS_PARAM), - IWL_CMD_ENTRY(REPLY_RXON_TIMING), - IWL_CMD_ENTRY(REPLY_ADD_STA), - IWL_CMD_ENTRY(REPLY_REMOVE_STA), - IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA), - IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH), - IWL_CMD_ENTRY(REPLY_WEPKEY), - IWL_CMD_ENTRY(REPLY_TX), - IWL_CMD_ENTRY(REPLY_LEDS_CMD), - IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD), - IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD), - IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION), - IWL_CMD_ENTRY(COEX_EVENT_CMD), - IWL_CMD_ENTRY(REPLY_QUIET_CMD), - IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH), - IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD), - IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION), - IWL_CMD_ENTRY(POWER_TABLE_CMD), - IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION), - IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC), - IWL_CMD_ENTRY(REPLY_SCAN_CMD), - IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD), - IWL_CMD_ENTRY(SCAN_START_NOTIFICATION), - IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION), - IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION), - IWL_CMD_ENTRY(BEACON_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_TX_BEACON), - IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION), - IWL_CMD_ENTRY(QUIET_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD), - IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_BT_CONFIG), - IWL_CMD_ENTRY(REPLY_STATISTICS_CMD), - IWL_CMD_ENTRY(STATISTICS_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD), - IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION), - IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD), - IWL_CMD_ENTRY(SENSITIVITY_CMD), - IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD), - IWL_CMD_ENTRY(REPLY_RX_PHY_CMD), - IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD), - IWL_CMD_ENTRY(REPLY_COMPRESSED_BA), - IWL_CMD_ENTRY(CALIBRATION_CFG_CMD), - IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION), - IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD), - IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION), - IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD), - IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF), - IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE), - IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV), - IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS), - IWL_CMD_ENTRY(REPLY_WIPAN_RXON), - IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING), - IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC), - IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM), - IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY), - IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH), - IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION), - IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE), - IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS), - IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER), - IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS), - IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS), - IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL), - IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS), - IWL_CMD_ENTRY(REPLY_D3_CONFIG), -}; -#undef IWL_CMD_ENTRY - /****************************************************************************** * * Generic RX handler implementations @@ -1095,7 +1018,9 @@ void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi, } else { /* No handling needed */ IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", - iwl_dvm_get_cmd_string(pkt->hdr.cmd), + iwl_get_cmd_string(priv->trans, + iwl_cmd_id(pkt->hdr.cmd, + 0, 0)), pkt->hdr.cmd); } } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 85ceceb34fcc..2d47cb24c48b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -20,7 +20,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c index 648159495bbc..81a2ddbe9569 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c @@ -22,7 +22,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c index 0fa67d3b7235..8e9768a553e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c index c4736c8834c5..5b73492e7ff7 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -184,7 +184,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) priv->thermal_throttle.ct_kill_toggle = true; } iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); - if (iwl_trans_grab_nic_access(priv->trans, false, &flags)) + if (iwl_trans_grab_nic_access(priv->trans, &flags)) iwl_trans_release_nic_access(priv->trans, &flags); /* Reschedule the ct_kill timer to occur in diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h index 507726534b84..d324e9be9cbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_tt_setting_h__ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index bddd19769035..59e2001c39f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -22,7 +22,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -383,6 +383,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, sta, fc); memset(&info->status, 0, sizeof(info->status)); + memset(info->driver_data, 0, sizeof(info->driver_data)); info->driver_data[0] = ctx; info->driver_data[1] = dev_cmd; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index 390ee4d303db..fd9064bf389a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 89a25cffb060..dee4458b408d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index a784bb64ef63..0d2aa1d9a50f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -83,7 +83,7 @@ static const struct iwl_base_params iwl9000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000, - .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_queues = 31, .pll_cfg_val = 0, .shadow_ram_support = true, .led_compensation = 57, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 6a4c0c236d10..f99048135fb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 543abeaffcf0..163b21bc20cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c index 09feff4fa226..b1c3b0d0fcc6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h index e8dbb24d993d..110333208450 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index bde023316b4a..d80312b46f16 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -51,6 +52,22 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_printk("[%s] TX frame data", __get_str(dev)) ); +TRACE_EVENT(iwlwifi_dev_tx_tso_chunk, + TP_PROTO(const struct device *dev, + u8 *data_src, size_t data_len), + TP_ARGS(dev, data_src, data_len), + TP_STRUCT__entry( + DEV_ENTRY + + __dynamic_array(u8, data, data_len) + ), + TP_fast_assign( + DEV_ASSIGN; + memcpy(__get_dynamic_array(data), data_src, data_len); + ), + TP_printk("[%s] TX frame data", __get_str(dev)) +); + TRACE_EVENT(iwlwifi_dev_rx_data, TP_PROTO(const struct device *dev, const struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index eb4b99a1c8cd..22786d7dc00a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -20,7 +20,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c index 90987d6f348e..1d9dd153ef1c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h index b87acd6a229b..f4d3cd010087 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 16756f0eaba8..7acb49075683 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -594,7 +594,8 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, static int iwl_parse_tlv_firmware(struct iwl_drv *drv, const struct firmware *ucode_raw, struct iwl_firmware_pieces *pieces, - struct iwl_ucode_capabilities *capa) + struct iwl_ucode_capabilities *capa, + bool *usniffer_images) { struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; struct iwl_ucode_tlv *tlv; @@ -607,7 +608,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, char buildstr[25]; u32 build, paging_mem_size; int num_of_cpus; - bool usniffer_images = false; bool usniffer_req = false; bool gscan_capa = false; @@ -980,7 +980,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, break; } case IWL_UCODE_TLV_SEC_RT_USNIFFER: - usniffer_images = true; + *usniffer_images = true; iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR_USNIFFER, tlv_len); @@ -1031,7 +1031,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, } } - if (usniffer_req && !usniffer_images) { + if (usniffer_req && !*usniffer_images) { IWL_ERR(drv, "user selected to work with usniffer but usniffer image isn't available in ucode package\n"); return -EINVAL; @@ -1192,6 +1192,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) u32 api_ver; int i; bool load_module = false; + bool usniffer_images = false; fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = @@ -1229,7 +1230,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces); else err = iwl_parse_tlv_firmware(drv, ucode_raw, pieces, - &fw->ucode_capa); + &fw->ucode_capa, &usniffer_images); if (err) goto try_again; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index cda746b33db1..f6eacfdbc265 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -69,7 +69,7 @@ /* for all modules */ #define DRV_NAME "iwlwifi" #define DRV_COPYRIGHT "Copyright(c) 2003- 2015 Intel Corporation" -#define DRV_AUTHOR "" +#define DRV_AUTHOR "" /* radio config bits (actual values from NVM definition) */ #define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index b395854a94d9..c15f5be85197 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -454,11 +454,11 @@ static void iwl_eeprom_enhanced_txpower(struct device *dev, TXP_CHECK_AND_PRINT(COMMON_TYPE), txp->flags); IWL_DEBUG_EEPROM(dev, - "\t\t chain_A: 0x%02x chain_B: 0X%02x chain_C: 0X%02x\n", + "\t\t chain_A: %d chain_B: %d chain_C: %d\n", txp->chain_a_max, txp->chain_b_max, txp->chain_c_max); IWL_DEBUG_EEPROM(dev, - "\t\t MIMO2: 0x%02x MIMO3: 0x%02x High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n", + "\t\t MIMO2: %d MIMO3: %d High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n", txp->mimo2_max, txp->mimo3_max, ((txp->delta_20_in_40 & 0xf0) >> 4), (txp->delta_20_in_40 & 0x0f)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index e08319a3ed1b..d2294ad67023 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 603c8945871b..32c8f84ae519 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -82,7 +82,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { u32 value = 0x5a5a5a5a; unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { value = iwl_read32(trans, reg); iwl_trans_release_nic_access(trans, &flags); } @@ -95,7 +95,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write32(trans, reg, value); iwl_trans_release_nic_access(trans, &flags); } @@ -138,7 +138,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) unsigned long flags; u32 val = 0x5a5a5a5a; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { val = iwl_read_prph_no_grab(trans, ofs); iwl_trans_release_nic_access(trans, &flags); } @@ -150,7 +150,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write_prph_no_grab(trans, ofs, val); iwl_trans_release_nic_access(trans, &flags); } @@ -176,7 +176,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write_prph_no_grab(trans, ofs, iwl_read_prph_no_grab(trans, ofs) | mask); @@ -190,7 +190,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, { unsigned long flags; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write_prph_no_grab(trans, ofs, (iwl_read_prph_no_grab(trans, ofs) & mask) | bits); @@ -204,7 +204,7 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) unsigned long flags; u32 val; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { val = iwl_read_prph_no_grab(trans, ofs); iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); iwl_trans_release_nic_access(trans, &flags); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 9baf9ef8bdfb..fd42f63f5e84 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 2a58d6833224..b49eda8150bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -123,6 +123,8 @@ struct iwl_cfg; * received on the RSS queue(s). The queue parameter indicates which of the * RSS queues received this frame; it will always be non-zero. * This method must not sleep. + * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set + * completes. Must be atomic. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. @@ -155,6 +157,8 @@ struct iwl_op_mode_ops { struct iwl_rx_cmd_buffer *rxb); void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, unsigned int queue); + void (*async_cb)(struct iwl_op_mode *op_mode, + const struct iwl_device_cmd *cmd); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); @@ -203,6 +207,13 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode, op_mode->ops->rx_rss(op_mode, napi, rxb, queue); } +static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode, + const struct iwl_device_cmd *cmd) +{ + if (op_mode->ops->async_cb) + op_mode->ops->async_cb(op_mode, cmd); +} + static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, int queue) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c index a105455b6a24..4a4dea08751c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h index 9ee18d0d2d01..24103877eab0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 3ab777f79e4f..9da7dc49549c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index ccd317b6408f..6069a9ff53fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -61,7 +61,10 @@ * *****************************************************************************/ #include +#include + #include "iwl-trans.h" +#include "iwl-drv.h" struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, @@ -112,3 +115,91 @@ void iwl_trans_free(struct iwl_trans *trans) kmem_cache_destroy(trans->dev_cmd_pool); kfree(trans); } + +int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) +{ + int ret; + + if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && + test_bit(STATUS_RFKILL, &trans->status))) + return -ERFKILL; + + if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) + return -EIO; + + if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) { + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } + + if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) && + !(cmd->flags & CMD_ASYNC))) + return -EINVAL; + + if (!(cmd->flags & CMD_ASYNC)) + lock_map_acquire_read(&trans->sync_cmd_lockdep_map); + + ret = trans->ops->send_cmd(trans, cmd); + + if (!(cmd->flags & CMD_ASYNC)) + lock_map_release(&trans->sync_cmd_lockdep_map); + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); + +/* Comparator for struct iwl_hcmd_names. + * Used in the binary search over a list of host commands. + * + * @key: command_id that we're looking for. + * @elt: struct iwl_hcmd_names candidate for match. + * + * @return 0 iff equal. + */ +static int iwl_hcmd_names_cmp(const void *key, const void *elt) +{ + const struct iwl_hcmd_names *name = elt; + u8 cmd1 = *(u8 *)key; + u8 cmd2 = name->cmd_id; + + return (cmd1 - cmd2); +} + +const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id) +{ + u8 grp, cmd; + struct iwl_hcmd_names *ret; + const struct iwl_hcmd_arr *arr; + size_t size = sizeof(struct iwl_hcmd_names); + + grp = iwl_cmd_groupid(id); + cmd = iwl_cmd_opcode(id); + + if (!trans->command_groups || grp >= trans->command_groups_size || + !trans->command_groups[grp].arr) + return "UNKNOWN"; + + arr = &trans->command_groups[grp]; + ret = bsearch(&cmd, arr->arr, arr->size, size, iwl_hcmd_names_cmp); + if (!ret) + return "UNKNOWN"; + return ret->cmd_name; +} +IWL_EXPORT_SYMBOL(iwl_get_cmd_string); + +int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans) +{ + int i, j; + const struct iwl_hcmd_arr *arr; + + for (i = 0; i < trans->command_groups_size; i++) { + arr = &trans->command_groups[i]; + if (!arr->arr) + continue; + for (j = 0; j < arr->size - 1; j++) + if (arr->arr[j].cmd_id > arr->arr[j + 1].cmd_id) + return -1; + } + return 0; +} +IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 3d089ae171b7..81b7cb71e001 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -68,6 +68,7 @@ #include #include /* for page_address */ #include +#include #include "iwl-debug.h" #include "iwl-config.h" @@ -248,6 +249,8 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle. * @CMD_WAKE_UP_TRANS: The command response should wake up the trans * (i.e. mark it as non-idle). + * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be + * called after this command completes. Valid only with CMD_ASYNC. * @CMD_TB_BITMAP_POS: Position of the first bit for the TB bitmap. We need to * check that we leave enough room for the TBs bitmap which needs 20 bits. */ @@ -259,6 +262,7 @@ enum CMD_MODE { CMD_SEND_IN_IDLE = BIT(4), CMD_MAKE_TRANS_IDLE = BIT(5), CMD_WAKE_UP_TRANS = BIT(6), + CMD_WANT_ASYNC_CALLBACK = BIT(7), CMD_TB_BITMAP_POS = 11, }; @@ -377,6 +381,11 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) #define MAX_NO_RECLAIM_CMDS 6 +/* + * The first entry in driver_data array in ieee80211_tx_info + * that can be used by the transport. + */ +#define IWL_TRANS_FIRST_DRIVER_DATA 2 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) /* @@ -439,6 +448,22 @@ iwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size) } } +struct iwl_hcmd_names { + u8 cmd_id; + const char *const cmd_name; +}; + +#define HCMD_NAME(x) \ + { .cmd_id = x, .cmd_name = #x } + +struct iwl_hcmd_arr { + const struct iwl_hcmd_names *arr; + int size; +}; + +#define HCMD_ARR(x) \ + { .arr = x, .size = ARRAY_SIZE(x) } + /** * struct iwl_trans_config - transport configuration * @@ -458,8 +483,10 @@ iwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size) * in DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue * @wide_cmd_header: firmware supports wide host command header - * @command_names: array of command names, must be 256 entries - * (one for each command); for debugging only + * @sw_csum_tx: transport should compute the TCP checksum + * @command_groups: array of command groups, each member is an array of the + * commands in the group; for debugging only + * @command_groups_size: number of command groups, to avoid illegal access * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until * we get the ALIVE from the uCode */ @@ -476,8 +503,10 @@ struct iwl_trans_config { bool bc_table_dword; bool scd_set_active; bool wide_cmd_header; - const char *const *command_names; - + bool sw_csum_tx; + const struct iwl_hcmd_arr *command_groups; + int command_groups_size; + u32 sdio_adma_addr; }; @@ -528,7 +557,11 @@ struct iwl_trans_txq_scd_cfg { * If RFkill is asserted in the middle of a SYNC host command, it must * return -ERFKILL straight away. * May sleep only if CMD_ASYNC is not set - * @tx: send an skb + * @tx: send an skb. The transport relies on the op_mode to zero the + * the ieee80211_tx_info->driver_data. If the MPDU is an A-MSDU, all + * the CSUM will be taken care of (TCP CSUM and IP header in case of + * IPv4). If the MPDU is a single MSDU, the op_mode must compute the IP + * header if it is IPv4. * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. * Must be atomic @@ -542,6 +575,11 @@ struct iwl_trans_txq_scd_cfg { * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. * @freeze_txq_timer: prevents the timer of the queue from firing until the * queue is set to awake. Must be atomic. + * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note + * that the transport needs to refcount the calls since this function + * will be called several times with block = true, and then the queues + * need to be unblocked only after the same number of calls with + * block = false. * @write8: write a u8 to a register at offset ofs from the BAR * @write32: write a u32 to a register at offset ofs from the BAR * @read32: read a u32 register at offset ofs from the BAR @@ -600,6 +638,7 @@ struct iwl_trans_ops { int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); + void (*block_txq_ptrs)(struct iwl_trans *trans, bool block); void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); @@ -613,8 +652,7 @@ struct iwl_trans_ops { void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); void (*set_pmi)(struct iwl_trans *trans, bool state); - bool (*grab_nic_access)(struct iwl_trans *trans, bool silent, - unsigned long *flags); + bool (*grab_nic_access)(struct iwl_trans *trans, unsigned long *flags); void (*release_nic_access)(struct iwl_trans *trans, unsigned long *flags); void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, @@ -641,18 +679,61 @@ enum iwl_trans_state { }; /** - * enum iwl_d0i3_mode - d0i3 mode + * DOC: Platform power management * - * @IWL_D0I3_MODE_OFF - d0i3 is disabled - * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle - * (e.g. no active references) - * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend - * (in case of 'any' trigger) + * There are two types of platform power management: system-wide + * (WoWLAN) and runtime. + * + * In system-wide power management the entire platform goes into a low + * power state (e.g. idle or suspend to RAM) at the same time and the + * device is configured as a wakeup source for the entire platform. + * This is usually triggered by userspace activity (e.g. the user + * presses the suspend button or a power management daemon decides to + * put the platform in low power mode). The device's behavior in this + * mode is dictated by the wake-on-WLAN configuration. + * + * In runtime power management, only the devices which are themselves + * idle enter a low power state. This is done at runtime, which means + * that the entire system is still running normally. This mode is + * usually triggered automatically by the device driver and requires + * the ability to enter and exit the low power modes in a very short + * time, so there is not much impact in usability. + * + * The terms used for the device's behavior are as follows: + * + * - D0: the device is fully powered and the host is awake; + * - D3: the device is in low power mode and only reacts to + * specific events (e.g. magic-packet received or scan + * results found); + * - D0I3: the device is in low power mode and reacts to any + * activity (e.g. RX); + * + * These terms reflect the power modes in the firmware and are not to + * be confused with the physical device power state. The NIC can be + * in D0I3 mode even if, for instance, the PCI device is in D3 state. */ -enum iwl_d0i3_mode { - IWL_D0I3_MODE_OFF = 0, - IWL_D0I3_MODE_ON_IDLE, - IWL_D0I3_MODE_ON_SUSPEND, + +/** + * enum iwl_plat_pm_mode - platform power management mode + * + * This enumeration describes the device's platform power management + * behavior when in idle mode (i.e. runtime power management) or when + * in system-wide suspend (i.e WoWLAN). + * + * @IWL_PLAT_PM_MODE_DISABLED: power management is disabled for this + * device. At runtime, this means that nothing happens and the + * device always remains in active. In system-wide suspend mode, + * it means that the all connections will be closed automatically + * by mac80211 before the platform is suspended. + * @IWL_PLAT_PM_MODE_D3: the device goes into D3 mode (i.e. WoWLAN). + * For runtime power management, this mode is not officially + * supported. + * @IWL_PLAT_PM_MODE_D0I3: the device goes into D0I3 mode. + */ +enum iwl_plat_pm_mode { + IWL_PLAT_PM_MODE_DISABLED, + IWL_PLAT_PM_MODE_D3, + IWL_PLAT_PM_MODE_D0I3, }; /** @@ -692,6 +773,12 @@ enum iwl_d0i3_mode { * the opmode. * @paging_download_buf: Buffer used for copying all of the pages before * downloading them to the FW. The buffer is allocated in the opmode + * @system_pm_mode: the system-wide power management mode in use. + * This mode is set dynamically, depending on the WoWLAN values + * configured from the userspace at runtime. + * @runtime_pm_mode: the runtime power management mode in use. This + * mode is set during the initialization phase and is not + * supposed to change during runtime. */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -711,6 +798,9 @@ struct iwl_trans { bool pm_support; bool ltr_enabled; + const struct iwl_hcmd_arr *command_groups; + int command_groups_size; + u8 num_rx_queues; /* The following fields are internal only */ @@ -739,21 +829,24 @@ struct iwl_trans { struct iwl_fw_paging *paging_db; void *paging_download_buf; - enum iwl_d0i3_mode d0i3_mode; - - bool wowlan_d0i3; + enum iwl_plat_pm_mode system_pm_mode; + enum iwl_plat_pm_mode runtime_pm_mode; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __aligned(sizeof(void *)); }; +const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id); +int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans); + static inline void iwl_trans_configure(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg) { trans->op_mode = trans_cfg->op_mode; trans->ops->configure(trans, trans_cfg); + WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg)); } static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power) @@ -880,34 +973,6 @@ iwl_trans_dump_data(struct iwl_trans *trans, return trans->ops->dump_data(trans, trigger); } -static inline int iwl_trans_send_cmd(struct iwl_trans *trans, - struct iwl_host_cmd *cmd) -{ - int ret; - - if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status))) - return -ERFKILL; - - if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) - return -EIO; - - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return -EIO; - } - - if (!(cmd->flags & CMD_ASYNC)) - lock_map_acquire_read(&trans->sync_cmd_lockdep_map); - - ret = trans->ops->send_cmd(trans, cmd); - - if (!(cmd->flags & CMD_ASYNC)) - lock_map_release(&trans->sync_cmd_lockdep_map); - - return ret; -} - static inline struct iwl_device_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { @@ -920,6 +985,8 @@ iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) (dev_cmd_ptr + trans->dev_cmd_headroom); } +int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); + static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, struct iwl_device_cmd *dev_cmd) { @@ -934,8 +1001,10 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) return -EIO; - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } return trans->ops->tx(trans, skb, dev_cmd, queue); } @@ -943,8 +1012,10 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn, struct sk_buff_head *skbs) { - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return; + } trans->ops->reclaim(trans, queue, ssn, skbs); } @@ -962,8 +1033,10 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, { might_sleep(); - if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return; + } trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } @@ -1003,18 +1076,34 @@ static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, unsigned long txqs, bool freeze) { - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return; + } if (trans->ops->freeze_txq_timer) trans->ops->freeze_txq_timer(trans, txqs, freeze); } +static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans, + bool block) +{ + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return; + } + + if (trans->ops->block_txq_ptrs) + trans->ops->block_txq_ptrs(trans, block); +} + static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, u32 txqs) { - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } return trans->ops->wait_tx_queue_empty(trans, txqs); } @@ -1092,9 +1181,9 @@ iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) trans->ops->set_bits_mask(trans, reg, mask, value); } -#define iwl_trans_grab_nic_access(trans, silent, flags) \ +#define iwl_trans_grab_nic_access(trans, flags) \ __cond_lock(nic_access, \ - likely((trans)->ops->grab_nic_access(trans, silent, flags))) + likely((trans)->ops->grab_nic_access(trans, flags))) static inline void __releases(nic_access) iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 2c0d20f2a918..23e7e2937566 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -1,12 +1,12 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o -iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o +iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o coex_legacy.o iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-y += tof.o fw-dbg.o -iwlmvm-$(CONFIG_PM_SLEEP) += d3.o +iwlmvm-$(CONFIG_PM) += d3.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index c9ca029c69f4..2e098f8e0f83 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex_legacy.c index 61c07b05fcaa..015045733444 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex_legacy.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 5c21231e195d..b00c03fcd447 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -106,6 +106,7 @@ #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 +#define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 9e51843764ca..6ac40727541e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -104,9 +104,13 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, struct inet6_ifaddr *ifa; int idx = 0; + memset(mvmvif->tentative_addrs, 0, sizeof(mvmvif->tentative_addrs)); + read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { mvmvif->target_ipv6_addrs[idx] = ifa->addr; + if (ifa->flags & IFA_F_TENTATIVE) + __set_bit(idx, mvmvif->tentative_addrs); idx++; if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX) break; @@ -775,6 +779,9 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) */ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + /* the fw is reset, so all the keys are cleared */ + memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); + mvm->ptk_ivlen = 0; mvm->ptk_icvlen = 0; mvm->ptk_ivlen = 0; @@ -797,6 +804,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; + wowlan_config_cmd->flags = ENABLE_L3_FILTERING | + ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); @@ -846,15 +855,38 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, return 0; } +static void +iwl_mvm_iter_d0i3_ap_keys(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data), + void *data) +{ + struct ieee80211_sta *ap_sta; + + rcu_read_lock(); + + ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id]); + if (IS_ERR_OR_NULL(ap_sta)) + goto out; + + ieee80211_iter_keys_rcu(mvm->hw, vif, iter, data); +out: + rcu_read_unlock(); +} + int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool configure_keys, + bool d0i3, u32 cmd_flags) { struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; struct wowlan_key_data key_data = { - .configure_keys = configure_keys, + .configure_keys = !d0i3, .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, @@ -867,15 +899,28 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, return -ENOMEM; /* - * Note that currently we don't propagate cmd_flags - * to the iterator. In case of key_data.configure_keys, - * all the configured commands are SYNC, and - * iwl_mvm_wowlan_program_keys() will take care of - * locking/unlocking mvm->mutex. + * if we have to configure keys, call ieee80211_iter_keys(), + * as we need non-atomic context in order to take the + * required locks. + * for the d0i3 we can't use ieee80211_iter_keys(), as + * taking (almost) any mutex might result in deadlock. */ - ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_wowlan_program_keys, - &key_data); + if (!d0i3) { + /* + * Note that currently we don't propagate cmd_flags + * to the iterator. In case of key_data.configure_keys, + * all the configured commands are SYNC, and + * iwl_mvm_wowlan_program_keys() will take care of + * locking/unlocking mvm->mutex. + */ + ieee80211_iter_keys(mvm->hw, vif, + iwl_mvm_wowlan_program_keys, + &key_data); + } else { + iwl_mvm_iter_d0i3_ap_keys(mvm, vif, + iwl_mvm_wowlan_program_keys, + &key_data); + } if (key_data.error) { ret = -EIO; @@ -900,7 +945,8 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, goto out; } - if (mvmvif->rekey_data.valid) { + /* configure rekey data only if offloaded rekey is supported (d3) */ + if (mvmvif->rekey_data.valid && !d0i3) { memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, NL80211_KCK_LEN); @@ -917,6 +963,7 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, if (ret) goto out; } + ret = 0; out: kfree(key_data.rsc_tsc); return ret; @@ -946,8 +993,11 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, * that isn't really a problem though. */ mutex_unlock(&mvm->mutex); - iwl_mvm_wowlan_config_key_params(mvm, vif, true, CMD_ASYNC); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif, false, + CMD_ASYNC); mutex_lock(&mvm->mutex); + if (ret) + return ret; } ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, @@ -960,7 +1010,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (ret) return ret; - ret = iwl_mvm_send_proto_offload(mvm, vif, false, 0); + ret = iwl_mvm_send_proto_offload(mvm, vif, false, true, 0); if (ret) return ret; @@ -1179,19 +1229,20 @@ remove_notif: int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_trans *trans = mvm->trans; int ret; /* make sure the d0i3 exit work is not pending */ flush_work(&mvm->d0i3_exit_work); - ret = iwl_trans_suspend(mvm->trans); + ret = iwl_trans_suspend(trans); if (ret) return ret; - mvm->trans->wowlan_d0i3 = wowlan->any; - if (mvm->trans->wowlan_d0i3) { - /* 'any' trigger means d0i3 usage */ - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + if (wowlan->any) { + trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3; + + if (iwl_mvm_enter_d0i3_on_suspend(mvm)) { ret = iwl_mvm_enter_d0i3_sync(mvm); if (ret) @@ -1202,11 +1253,13 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); - iwl_trans_d3_suspend(mvm->trans, false); + iwl_trans_d3_suspend(trans, false); return 0; } + trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + return __iwl_mvm_suspend(hw, wowlan, false); } @@ -1711,6 +1764,29 @@ out_unlock: return false; } +void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_wowlan_status *status) +{ + struct iwl_mvm_d3_gtk_iter_data gtkdata = { + .status = status, + }; + + /* + * rekey handling requires taking locks that can't be taken now. + * however, d0i3 doesn't offload rekey, so we're fine. + */ + if (WARN_ON_ONCE(status->num_of_gtk_rekeys)) + return; + + /* find last GTK that we used initially, if any */ + gtkdata.find_phase = true; + iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata); + + gtkdata.find_phase = false; + iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata); +} + struct iwl_mvm_nd_query_results { u32 matched_profiles; struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; @@ -1969,8 +2045,9 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) { bool exit_now; enum iwl_d3_status d3_status; + struct iwl_trans *trans = mvm->trans; - iwl_trans_d3_resume(mvm->trans, &d3_status, false); + iwl_trans_d3_resume(trans, &d3_status, false); /* * make sure to clear D0I3_DEFER_WAKEUP before @@ -1987,9 +2064,9 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) _iwl_mvm_exit_d0i3(mvm); } - iwl_trans_resume(mvm->trans); + iwl_trans_resume(trans); - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + if (iwl_mvm_enter_d0i3_on_suspend(mvm)) { int ret = iwl_mvm_exit_d0i3(mvm->hw->priv); if (ret) @@ -2005,12 +2082,16 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) int iwl_mvm_resume(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; - /* 'any' trigger means d0i3 was used */ - if (hw->wiphy->wowlan_config->any) - return iwl_mvm_resume_d0i3(mvm); + if (mvm->trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) + ret = iwl_mvm_resume_d0i3(mvm); else - return iwl_mvm_resume_d3(mvm); + ret = iwl_mvm_resume_d3(mvm); + + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; + + return ret; } void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) @@ -2034,6 +2115,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) ieee80211_stop_queues(mvm->hw); synchronize_net(); + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + /* start pseudo D3 */ rtnl_lock(); err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); @@ -2088,9 +2171,13 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) int remaining_time = 10; mvm->d3_test_active = false; + rtnl_lock(); __iwl_mvm_resume(mvm, true); rtnl_unlock(); + + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; + iwl_abort_notification_waits(&mvm->notif_wait); ieee80211_restart_hw(mvm->hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 7904b41a04c6..9e0d46368cdd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 7e2a8149411c..90500e2d107b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -1029,7 +1029,8 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (ret) return ret; - iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, NULL); + iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf, + (count - 1), NULL); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); @@ -1316,6 +1317,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); + PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1450,7 +1452,7 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h index d398a6102805..2a33b694ba10 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 228684cfdb7e..62b9a0a96700 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -94,10 +95,14 @@ struct iwl_d3_manager_config { * enum iwl_d3_proto_offloads - enabled protocol offloads * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled + * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid + * @IWL_D3_PROTO_IPV6_VALID: IPv6 data is valid */ enum iwl_proto_offloads { IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), IWL_D3_PROTO_OFFLOAD_NS = BIT(1), + IWL_D3_PROTO_IPV4_VALID = BIT(2), + IWL_D3_PROTO_IPV6_VALID = BIT(3), }; #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 @@ -241,6 +246,13 @@ enum iwl_wowlan_wakeup_filters { IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ +enum iwl_wowlan_flags { + IS_11W_ASSOC = BIT(0), + ENABLE_L3_FILTERING = BIT(1), + ENABLE_NBNS_FILTERING = BIT(2), + ENABLE_DHCP_FILTERING = BIT(3), +}; + struct iwl_wowlan_config_cmd { __le32 wakeup_filter; __le16 non_qos_seq; @@ -248,8 +260,9 @@ struct iwl_wowlan_config_cmd { u8 wowlan_ba_teardown_tids; u8 is_11n_connection; u8 offloading_tid; - u8 reserved[3]; -} __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ + u8 flags; + u8 reserved[2]; +} __packed; /* WOWLAN_CONFIG_API_S_VER_4 */ /* * WOWLAN_TSC_RSC_PARAMS diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 9a8a37f7fd19..fb6d341d6f3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -79,6 +79,11 @@ #define IWL_RX_INFO_ENERGY_ANT_B_POS 8 #define IWL_RX_INFO_ENERGY_ANT_C_POS 16 +enum iwl_mac_context_info { + MAC_CONTEXT_INFO_NONE, + MAC_CONTEXT_INFO_GSCAN, +}; + /** * struct iwl_rx_phy_info - phy info * (REPLY_RX_PHY_CMD = 0xc0) @@ -97,6 +102,8 @@ * @frame_time: frame's time on the air, based on byte count and frame rate * calculation * @mac_active_msk: what MACs were active when the frame was received + * @mac_context_info: additional info on the context in which the frame was + * received as defined in &enum iwl_mac_context_info * * Before each Rx, the device sends this data. It contains PHY information * about the reception of the packet. @@ -114,7 +121,8 @@ struct iwl_rx_phy_info { __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT]; __le32 rate_n_flags; __le32 byte_count; - __le16 mac_active_msk; + u8 mac_active_msk; + u8 mac_context_info; __le16 frame_time; } __packed; @@ -279,11 +287,17 @@ enum iwl_rx_mpdu_status { IWL_RX_MPDU_STATUS_KEY_ERROR = BIT(4), IWL_RX_MPDU_STATUS_ICV_OK = BIT(5), IWL_RX_MPDU_STATUS_MIC_OK = BIT(6), + /* TODO - verify this is the correct value */ + IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), IWL_RX_MPDU_STATUS_SEC_MASK = 0x7 << 8, IWL_RX_MPDU_STATUS_SEC_NONE = 0x0 << 8, IWL_RX_MPDU_STATUS_SEC_WEP = 0x1 << 8, IWL_RX_MPDU_STATUS_SEC_CCM = 0x2 << 8, IWL_RX_MPDU_STATUS_SEC_TKIP = 0x3 << 8, + /* TODO - define IWL_RX_MPDU_STATUS_SEC_EXT_ENC - this is a stub */ + IWL_RX_MPDU_STATUS_SEC_EXT_ENC = 0x4 << 8, + /* TODO - define IWL_RX_MPDU_STATUS_SEC_GCM - this is a stub */ + IWL_RX_MPDU_STATUS_SEC_GCM = 0x5 << 8, IWL_RX_MPDU_STATUS_DECRYPTED = BIT(11), IWL_RX_MPDU_STATUS_WEP_MATCH = BIT(12), IWL_RX_MPDU_STATUS_EXT_IV_MATCH = BIT(13), @@ -302,6 +316,8 @@ enum iwl_rx_mpdu_sta_id_flags { IWL_RX_MPDU_SIF_FILTER_STATUS_MASK = 0xc0, }; +#define IWL_RX_REORDER_DATA_INVALID_BAID 0x7f + enum iwl_rx_mpdu_reorder_data { IWL_RX_MPDU_REORDER_NSSN_MASK = 0x00000fff, IWL_RX_MPDU_REORDER_SN_MASK = 0x00fff000, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index 3a657e4b60ac..f01dab0d0dac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -285,6 +285,8 @@ struct iwl_scan_channel_opt { * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report * and DS parameter set IEs into probe requests. + * @IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL: use extended dwell time on channels + * 1, 6 and 11. * @IWL_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches */ enum iwl_mvm_lmac_scan_flags { @@ -295,6 +297,7 @@ enum iwl_mvm_lmac_scan_flags { IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4), IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5), IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED = BIT(6), + IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL = BIT(7), IWL_MVM_LMAC_SCAN_FLAG_MATCH = BIT(9), }; @@ -322,6 +325,7 @@ enum iwl_scan_priority_ext { * @active-dwell: dwell time for active channels * @passive-dwell: dwell time for passive channels * @fragmented-dwell: dwell time for fragmented passive scan + * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases) * @reserved2: for alignment and future use * @rx_chain_selct: PHY_RX_CHAIN_* flags * @scan_flags: &enum iwl_mvm_lmac_scan_flags @@ -346,7 +350,8 @@ struct iwl_scan_req_lmac { u8 active_dwell; u8 passive_dwell; u8 fragmented_dwell; - __le16 reserved2; + u8 extended_dwell; + u8 reserved2; __le16 rx_chain_select; __le32 scan_flags; __le32 max_out_time; @@ -490,7 +495,7 @@ enum iwl_channel_flags { * @dwell_active: default dwell time for active scan * @dwell_passive: default dwell time for passive scan * @dwell_fragmented: default dwell time for fragmented scan - * @reserved: for future use and alignment + * @dwell_extended: default dwell time for channels 1, 6 and 11 * @mac_addr: default mac address to be used in probes * @bcast_sta_id: the index of the station in the fw * @channel_flags: default channel flags - enum iwl_channel_flags @@ -507,7 +512,7 @@ struct iwl_scan_config { u8 dwell_active; u8 dwell_passive; u8 dwell_fragmented; - u8 reserved; + u8 dwell_extended; u8 mac_addr[ETH_ALEN]; u8 bcast_sta_id; u8 channel_flags; @@ -543,7 +548,8 @@ enum iwl_umac_scan_general_flags { IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = BIT(6), IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = BIT(7), IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8), - IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9) + IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9), + IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = BIT(10), }; /** @@ -597,7 +603,7 @@ struct iwl_scan_req_umac_tail { * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @general_flags: &enum iwl_umac_scan_general_flags - * @reserved1: for future use and alignment + * @extended_dwell: dwell time for channels 1, 6 and 11 * @active_dwell: dwell time for active scan * @passive_dwell: dwell time for passive scan * @fragmented_dwell: dwell time for fragmented passive scan @@ -606,7 +612,7 @@ struct iwl_scan_req_umac_tail { * @scan_priority: scan internal prioritization &enum iwl_scan_priority * @channel_flags: &enum iwl_scan_channel_flags * @n_channels: num of channels in scan request - * @reserved2: for future use and alignment + * @reserved: for future use and alignment * @data: &struct iwl_scan_channel_cfg_umac and * &struct iwl_scan_req_umac_tail */ @@ -616,7 +622,7 @@ struct iwl_scan_req_umac { __le32 ooc_priority; /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ __le32 general_flags; - u8 reserved1; + u8 extended_dwell; u8 active_dwell; u8 passive_dwell; u8 fragmented_dwell; @@ -626,7 +632,7 @@ struct iwl_scan_req_umac { /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ u8 channel_flags; u8 n_channels; - __le16 reserved2; + __le16 reserved; u8 data[]; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 9436798977a0..995898c5d017 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -270,6 +270,9 @@ enum { REPLY_MAX = 0xff, }; +/* Please keep this enum *SORTED* by hex value. + * Needed for binary search, otherwise a warning will be triggered. + */ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, @@ -277,6 +280,8 @@ enum iwl_phy_ops_subcmd_ids { /* command groups */ enum { + LEGACY_GROUP = 0x0, + LONG_GROUP = 0x1, PHY_OPS_GROUP = 0x4, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 9fcabc5ce904..f406c76b4302 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -122,7 +122,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, unsigned long flags; int i, j; - if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) + if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) return; /* Pull RXF data from all RXFs */ @@ -349,6 +349,7 @@ static const struct { { .start = 0x00a04560, .end = 0x00a0457c }, { .start = 0x00a04590, .end = 0x00a04598 }, { .start = 0x00a045c0, .end = 0x00a045f4 }, + { .start = 0x00a44000, .end = 0x00a7bf80 }, }; static u32 iwl_dump_prph(struct iwl_trans *trans, @@ -358,7 +359,7 @@ static u32 iwl_dump_prph(struct iwl_trans *trans, unsigned long flags; u32 prph_len = 0, i; - if (!iwl_trans_grab_nic_access(trans, false, &flags)) + if (!iwl_trans_grab_nic_access(trans, &flags)) return 0; for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { @@ -383,7 +384,7 @@ static u32 iwl_dump_prph(struct iwl_trans *trans, *val++ = cpu_to_le32(iwl_read_prph_no_grab(trans, reg)); - *data = iwl_fw_error_next_data(*data); + *data = iwl_fw_error_next_data(*data); } iwl_trans_release_nic_access(trans, &flags); @@ -400,7 +401,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_trigger_desc *dump_trig; struct iwl_mvm_dump_ptrs *fw_error_dump; u32 sram_len, sram_ofs; - u32 file_len, fifo_data_len = 0; + u32 file_len, fifo_data_len = 0, prph_len = 0; u32 smem_len = mvm->cfg->smem_len; u32 sram2_len = mvm->cfg->dccm2_len; bool monitor_dump_only = false; @@ -460,12 +461,24 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } + + /* Make room for PRPH registers */ + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4; + + prph_len += sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } } file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 + sram_len + sizeof(*dump_mem) + fifo_data_len + + prph_len + sizeof(*dump_info); /* Make room for the SMEM, if it exists */ @@ -489,17 +502,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(*dump_info); } - /* Make room for PRPH registers */ - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - - iwl_prph_dump_addr[i].start + 4; - - file_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; - } - /* * In 8000 HW family B-step include the ICCM (which resides separately) */ @@ -625,7 +627,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } dump_data = iwl_fw_error_next_data(dump_data); - iwl_dump_prph(mvm->trans, &dump_data); + if (prph_len) + iwl_dump_prph(mvm->trans, &dump_data); dump_trans_data: fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 05c933313f97..e6e80882d86d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index ee511aae727d..5e3a7582885b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -855,11 +855,17 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, u32 action) { struct iwl_mac_ctx_cmd cmd = {}; + u32 tfd_queue_msk = 0; + int ret, i; WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); + for (i = 0; i < IEEE80211_NUM_ACS; i++) + if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) + tfd_queue_msk |= BIT(vif->hw_queue[i]); + cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | MAC_FILTER_IN_CONTROL_AND_MGMT | MAC_FILTER_IN_BEACON | @@ -867,6 +873,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, MAC_FILTER_IN_CRC32); ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS); + /* Allocate sniffer station */ + ret = iwl_mvm_allocate_int_sta(mvm, &mvm->snif_sta, tfd_queue_msk, + vif->type); + if (ret) + return ret; + return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); } @@ -1289,8 +1301,10 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->uploaded = false; - if (vif->type == NL80211_IFTYPE_MONITOR) + if (vif->type == NL80211_IFTYPE_MONITOR) { __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags); + iwl_mvm_dealloc_snif_sta(mvm); + } return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a90f1ee4e571..296b9c5cd1be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -439,6 +439,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); + if (mvm->trans->max_skb_frags) + hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; + hw->queues = mvm->first_agg_queue; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | @@ -664,6 +667,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (!iwl_mvm_is_csum_supported(mvm)) hw->netdev_features &= ~NETIF_F_RXCSUM; + if (IWL_MVM_SW_TX_CSUM_OFFLOAD) + hw->netdev_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6; + ret = ieee80211_register_hw(mvm->hw); if (ret) iwl_mvm_leds_exit(mvm); @@ -964,6 +971,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->calibrating = false; /* just in case one was running */ + iwl_mvm_cleanup_roc_te(mvm); ieee80211_remain_on_channel_expired(mvm->hw); /* @@ -976,6 +984,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; iwl_mvm_reset_phy_ctxts(mvm); + memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained)); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); @@ -993,6 +1002,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->vif_count = 0; mvm->rx_ba_sessions = 0; mvm->fw_dbg_conf = FW_DBG_INVALID; + mvm->scan_type = IWL_SCAN_TYPE_NOT_SET; /* keep statistics ticking */ iwl_mvm_accu_radio_stats(mvm); @@ -1004,10 +1014,18 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - /* Clean up some internal and mac80211 state on restart */ - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* Clean up some internal and mac80211 state on restart */ iwl_mvm_restart_cleanup(mvm); - + } else { + /* Hold the reference to prevent runtime suspend while + * the start procedure runs. It's a bit confusing + * that the UCODE_DOWN reference is taken, but it just + * means "UCODE is not UP yet". ( TODO: rename this + * reference). + */ + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + } ret = iwl_mvm_up(mvm); if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { @@ -1074,15 +1092,13 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) { - if (!iwl_mvm_is_d0i3_supported(mvm)) - return; - - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) - if (!wait_event_timeout(mvm->d0i3_exit_waitq, - !test_bit(IWL_MVM_STATUS_IN_D0I3, - &mvm->status), - HZ)) - WARN_ONCE(1, "D0i3 exit on resume timed out\n"); + if (iwl_mvm_is_d0i3_supported(mvm) && + iwl_mvm_enter_d0i3_on_suspend(mvm)) + WARN_ONCE(!wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, + &mvm->status), + HZ), + "D0i3 exit on resume timed out\n"); } static void @@ -1110,14 +1126,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) */ memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats)); - /* - * Disallow low power states when the FW is down by taking - * the UCODE_DOWN ref. in case of ongoing hw restart the - * ref is already taken, so don't take it again. - */ - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - /* async_handlers_wk is now blocked */ /* @@ -1729,8 +1737,8 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, return true; } -static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + +static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm) { struct iwl_bcast_filter_cmd cmd; @@ -1744,8 +1752,7 @@ static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, sizeof(cmd), &cmd); } #else -static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm) { return 0; } @@ -1860,7 +1867,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } iwl_mvm_recalc_multicast(mvm); - iwl_mvm_configure_bcast_filter(mvm, vif); + iwl_mvm_configure_bcast_filter(mvm); /* reset rssi values */ mvmvif->bf_data.ave_beacon_signal = 0; @@ -1868,6 +1875,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_bt_coex_vif_change(mvm); iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, IEEE80211_SMPS_AUTOMATIC); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_UMAC_SCAN)) + iwl_mvm_config_scan(mvm); } else if (changes & BSS_CHANGED_BEACON_INFO) { /* * We received a beacon _after_ association so @@ -1908,7 +1918,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ARP_FILTER) { IWL_DEBUG_MAC80211(mvm, "arp filter changed\n"); - iwl_mvm_configure_bcast_filter(mvm, vif); + iwl_mvm_configure_bcast_filter(mvm); } } @@ -2238,7 +2248,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); /* @@ -2254,11 +2263,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], ERR_PTR(-ENOENT)); - if (mvm_sta->vif->type == NL80211_IFTYPE_AP) { - mvmvif->ap_assoc_sta_count--; - iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); - } - mutex_unlock(&mvm->mutex); } @@ -2370,6 +2374,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { + if (vif->type == NL80211_IFTYPE_AP) { + mvmvif->ap_assoc_sta_count++; + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + } ret = iwl_mvm_update_sta(mvm, vif, sta); if (ret == 0) iwl_mvm_rs_rate_init(mvm, sta, @@ -2396,6 +2404,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = 0; } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) { + if (vif->type == NL80211_IFTYPE_AP) { + mvmvif->ap_assoc_sta_count--; + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + } ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_NONE) { @@ -3116,6 +3128,11 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) goto out_remove_binding; + + ret = iwl_mvm_add_snif_sta(mvm, vif); + if (ret) + goto out_remove_binding; + } /* Handle binding during CSA */ @@ -3189,6 +3206,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; mvmvif->ps_disabled = false; + iwl_mvm_rm_snif_sta(mvm, vif); break; case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7dc3af6e06f7..287c16250570 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -294,6 +294,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_PROTECT_CSA, IWL_MVM_REF_FW_DBG_COLLECT, + IWL_MVM_REF_INIT_UCODE, /* update debugfs.c when changing this */ @@ -404,7 +405,7 @@ struct iwl_mvm_vif { */ struct iwl_mvm_phy_ctxt *phy_ctxt; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM /* WoWLAN GTK rekey data */ struct { u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; @@ -421,6 +422,7 @@ struct iwl_mvm_vif { #if IS_ENABLED(CONFIG_IPV6) /* IPv6 addresses for WoWLAN */ struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; + unsigned long tentative_addrs[BITS_TO_LONGS(IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)]; int num_target_ipv6_addrs; #endif @@ -475,6 +477,14 @@ enum iwl_scan_status { IWL_MVM_SCAN_MASK = 0xff, }; +enum iwl_mvm_scan_type { + IWL_SCAN_TYPE_NOT_SET, + IWL_SCAN_TYPE_UNASSOC, + IWL_SCAN_TYPE_WILD, + IWL_SCAN_TYPE_MILD, + IWL_SCAN_TYPE_FRAGMENTED, +}; + /** * struct iwl_nvm_section - describes an NVM section in memory. * @@ -643,7 +653,7 @@ struct iwl_mvm { unsigned int scan_status; void *scan_cmd; struct iwl_mcast_filter_cmd *mcast_filter_cmd; - bool scan_fragmented; + enum iwl_mvm_scan_type scan_type; /* max number of simultaneous scans the FW supports */ unsigned int max_scans; @@ -667,6 +677,7 @@ struct iwl_mvm { /* Internal station */ struct iwl_mvm_int_sta aux_sta; + struct iwl_mvm_int_sta snif_sta; bool last_ebs_successful; @@ -727,7 +738,7 @@ struct iwl_mvm { struct ieee80211_vif *p2p_device_vif; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM struct wiphy_wowlan_support wowlan; int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; @@ -924,6 +935,19 @@ static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_DQA_SUPPORT); } +static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) +{ + /* For now we only use this mode to differentiate between + * slave transports, which handle D0i3 entry in suspend by + * themselves in conjunction with runtime PM D0i3. So, this + * function is used to check whether we need to do anything + * when entering suspend or if the transport layer has already + * done it. + */ + return (mvm->trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) && + (mvm->trans->runtime_pm_mode != IWL_PLAT_PM_MODE_D0I3); +} + static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) { bool nvm_lar = mvm->nvm_data->lar_enabled; @@ -1111,6 +1135,11 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue); +void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, @@ -1249,10 +1278,6 @@ static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm) /* D3 (WoWLAN, NetDetect) */ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int iwl_mvm_resume(struct ieee80211_hw *hw); -int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool configure_keys, - u32 cmd_flags); void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled); void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1263,10 +1288,31 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); extern const struct file_operations iwl_dbgfs_d3_test_ops; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM +int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool host_awake, + u32 cmd_flags); +void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_wowlan_status *status); void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif); #else +static inline int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool host_awake, + u32 cmd_flags) +{ + return 0; +} + +static inline void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_wowlan_status *status) +{ +} + static inline void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -1277,6 +1323,7 @@ void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool disable_offloading, + bool offload_ns, u32 cmd_flags); /* D0i3 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index a9fcb15e9d1a..d8dcb67b7ff9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index f83e2bc6d0d5..6338d9cf7070 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,6 +66,7 @@ *****************************************************************************/ #include #include +#include #include "mvm.h" void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, @@ -86,6 +89,7 @@ void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool disable_offloading, + bool offload_ns, u32 cmd_flags) { union { @@ -106,6 +110,13 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, #if IS_ENABLED(CONFIG_IPV6) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; + /* + * Skip tentative address when ns offload is enabled to avoid + * violating RFC4862. + * Keep tentative address when ns offload is disabled so the NS packets + * will not be filtered out and will wake up the host. + */ + bool skip_tentative = offload_ns; if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { @@ -113,6 +124,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_targ_addr *addrs; int n_nsc, n_addrs; int c; + int num_skipped = 0; if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { nsc = cmd.v3s.ns_config; @@ -126,9 +138,6 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; } - if (mvmvif->num_target_ipv6_addrs) - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - /* * For each address we have (and that will fit) fill a target * address struct and combine for NS offload structs with the @@ -140,6 +149,12 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct in6_addr solicited_addr; int j; + if (skip_tentative && + test_bit(i, mvmvif->tentative_addrs)) { + num_skipped++; + continue; + } + addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], &solicited_addr); for (j = 0; j < c; j++) @@ -154,41 +169,64 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); } + if (mvmvif->num_target_ipv6_addrs - num_skipped) + enabled |= IWL_D3_PROTO_IPV6_VALID; + if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) - cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); + cmd.v3s.num_valid_ipv6_addrs = + cpu_to_le32(i - num_skipped); else - cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); + cmd.v3l.num_valid_ipv6_addrs = + cpu_to_le32(i - num_skipped); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); - } + bool found = false; BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != sizeof(mvmvif->target_ipv6_addrs[0])); for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) { + if (skip_tentative && + test_bit(i, mvmvif->tentative_addrs)) + continue; + memcpy(cmd.v2.target_ipv6_addr[i], &mvmvif->target_ipv6_addrs[i], sizeof(cmd.v2.target_ipv6_addr[i])); - } else { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); - } + found = true; + } + if (found) { + enabled |= IWL_D3_PROTO_IPV6_VALID; + memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); + } + } else { + bool found = false; BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != sizeof(mvmvif->target_ipv6_addrs[0])); for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) + IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) { + if (skip_tentative && + test_bit(i, mvmvif->tentative_addrs)) + continue; + memcpy(cmd.v1.target_ipv6_addr[i], &mvmvif->target_ipv6_addrs[i], sizeof(cmd.v1.target_ipv6_addr[i])); - } -#endif + found = true; + } + + if (found) { + enabled |= IWL_D3_PROTO_IPV6_VALID; + memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); + } + } + + if (offload_ns && (enabled & IWL_D3_PROTO_IPV6_VALID)) + enabled |= IWL_D3_PROTO_OFFLOAD_NS; +#endif if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { common = &cmd.v3s.common; size = sizeof(cmd.v3s); @@ -204,7 +242,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, } if (vif->bss_conf.arp_addr_cnt) { - enabled |= IWL_D3_PROTO_OFFLOAD_ARP; + enabled |= IWL_D3_PROTO_OFFLOAD_ARP | IWL_D3_PROTO_IPV4_VALID; common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3b0d597f5033..89ea70deeb84 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -83,6 +83,8 @@ #include "fw-api-scan.h" #include "time-event.h" #include "fw-dbg.h" +#include "fw-api.h" +#include "fw-api-scan.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -269,104 +271,127 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { }; #undef RX_HANDLER #undef RX_HANDLER_GRP -#define CMD(x) [x] = #x -static const char *const iwl_mvm_cmd_strings[REPLY_MAX + 1] = { - CMD(MVM_ALIVE), - CMD(REPLY_ERROR), - CMD(ECHO_CMD), - CMD(INIT_COMPLETE_NOTIF), - CMD(PHY_CONTEXT_CMD), - CMD(MGMT_MCAST_KEY), - CMD(TX_CMD), - CMD(TXPATH_FLUSH), - CMD(SHARED_MEM_CFG), - CMD(MAC_CONTEXT_CMD), - CMD(TIME_EVENT_CMD), - CMD(TIME_EVENT_NOTIFICATION), - CMD(BINDING_CONTEXT_CMD), - CMD(TIME_QUOTA_CMD), - CMD(NON_QOS_TX_COUNTER_CMD), - CMD(DC2DC_CONFIG_CMD), - CMD(NVM_ACCESS_CMD), - CMD(PHY_CONFIGURATION_CMD), - CMD(CALIB_RES_NOTIF_PHY_DB), - CMD(SET_CALIB_DEFAULT_CMD), - CMD(FW_PAGING_BLOCK_CMD), - CMD(ADD_STA_KEY), - CMD(ADD_STA), - CMD(FW_GET_ITEM_CMD), - CMD(REMOVE_STA), - CMD(LQ_CMD), - CMD(SCAN_OFFLOAD_CONFIG_CMD), - CMD(MATCH_FOUND_NOTIFICATION), - CMD(SCAN_OFFLOAD_REQUEST_CMD), - CMD(SCAN_OFFLOAD_ABORT_CMD), - CMD(HOT_SPOT_CMD), - CMD(SCAN_OFFLOAD_COMPLETE), - CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), - CMD(SCAN_ITERATION_COMPLETE), - CMD(POWER_TABLE_CMD), - CMD(WEP_KEY), - CMD(REPLY_RX_PHY_CMD), - CMD(REPLY_RX_MPDU_CMD), - CMD(FRAME_RELEASE), - CMD(BEACON_NOTIFICATION), - CMD(BEACON_TEMPLATE_CMD), - CMD(STATISTICS_CMD), - CMD(STATISTICS_NOTIFICATION), - CMD(EOSP_NOTIFICATION), - CMD(REDUCE_TX_POWER_CMD), - CMD(TX_ANT_CONFIGURATION_CMD), - CMD(D3_CONFIG_CMD), - CMD(D0I3_END_CMD), - CMD(PROT_OFFLOAD_CONFIG_CMD), - CMD(OFFLOADS_QUERY_CMD), - CMD(REMOTE_WAKE_CONFIG_CMD), - CMD(WOWLAN_PATTERNS), - CMD(WOWLAN_CONFIGURATION), - CMD(WOWLAN_TSC_RSC_PARAM), - CMD(WOWLAN_TKIP_PARAM), - CMD(WOWLAN_KEK_KCK_MATERIAL), - CMD(WOWLAN_GET_STATUSES), - CMD(WOWLAN_TX_POWER_PER_DB), - CMD(SCAN_OFFLOAD_PROFILES_QUERY_CMD), - CMD(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), - CMD(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), - CMD(CARD_STATE_NOTIFICATION), - CMD(MISSED_BEACONS_NOTIFICATION), - CMD(BT_COEX_PRIO_TABLE), - CMD(BT_COEX_PROT_ENV), - CMD(BT_PROFILE_NOTIFICATION), - CMD(BT_CONFIG), - CMD(MCAST_FILTER_CMD), - CMD(BCAST_FILTER_CMD), - CMD(REPLY_SF_CFG_CMD), - CMD(REPLY_BEACON_FILTERING_CMD), - CMD(CMD_DTS_MEASUREMENT_TRIGGER), - CMD(DTS_MEASUREMENT_NOTIFICATION), - CMD(REPLY_THERMAL_MNG_BACKOFF), - CMD(MAC_PM_POWER_TABLE), - CMD(LTR_CONFIG), - CMD(BT_COEX_CI), - CMD(BT_COEX_UPDATE_SW_BOOST), - CMD(BT_COEX_UPDATE_CORUN_LUT), - CMD(BT_COEX_UPDATE_REDUCED_TXP), - CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), - CMD(ANTENNA_COUPLING_NOTIFICATION), - CMD(SCD_QUEUE_CFG), - CMD(SCAN_CFG_CMD), - CMD(SCAN_REQ_UMAC), - CMD(SCAN_ABORT_UMAC), - CMD(SCAN_COMPLETE_UMAC), - CMD(TDLS_CHANNEL_SWITCH_CMD), - CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), - CMD(TDLS_CONFIG_CMD), - CMD(MCC_UPDATE_CMD), - CMD(SCAN_ITERATION_COMPLETE_UMAC), - CMD(LDBG_CONFIG_CMD), +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { + HCMD_NAME(MVM_ALIVE), + HCMD_NAME(REPLY_ERROR), + HCMD_NAME(ECHO_CMD), + HCMD_NAME(INIT_COMPLETE_NOTIF), + HCMD_NAME(PHY_CONTEXT_CMD), + HCMD_NAME(DBG_CFG), + HCMD_NAME(ANTENNA_COUPLING_NOTIFICATION), + HCMD_NAME(SCAN_CFG_CMD), + HCMD_NAME(SCAN_REQ_UMAC), + HCMD_NAME(SCAN_ABORT_UMAC), + HCMD_NAME(SCAN_COMPLETE_UMAC), + HCMD_NAME(TOF_CMD), + HCMD_NAME(TOF_NOTIFICATION), + HCMD_NAME(ADD_STA_KEY), + HCMD_NAME(ADD_STA), + HCMD_NAME(REMOVE_STA), + HCMD_NAME(FW_GET_ITEM_CMD), + HCMD_NAME(TX_CMD), + HCMD_NAME(SCD_QUEUE_CFG), + HCMD_NAME(TXPATH_FLUSH), + HCMD_NAME(MGMT_MCAST_KEY), + HCMD_NAME(WEP_KEY), + HCMD_NAME(SHARED_MEM_CFG), + HCMD_NAME(TDLS_CHANNEL_SWITCH_CMD), + HCMD_NAME(MAC_CONTEXT_CMD), + HCMD_NAME(TIME_EVENT_CMD), + HCMD_NAME(TIME_EVENT_NOTIFICATION), + HCMD_NAME(BINDING_CONTEXT_CMD), + HCMD_NAME(TIME_QUOTA_CMD), + HCMD_NAME(NON_QOS_TX_COUNTER_CMD), + HCMD_NAME(LQ_CMD), + HCMD_NAME(FW_PAGING_BLOCK_CMD), + HCMD_NAME(SCAN_OFFLOAD_REQUEST_CMD), + HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD), + HCMD_NAME(HOT_SPOT_CMD), + HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), + HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), + HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), + HCMD_NAME(BT_COEX_UPDATE_SW_BOOST), + HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT), + HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP), + HCMD_NAME(BT_COEX_CI), + HCMD_NAME(PHY_CONFIGURATION_CMD), + HCMD_NAME(CALIB_RES_NOTIF_PHY_DB), + HCMD_NAME(SCAN_OFFLOAD_COMPLETE), + HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), + HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD), + HCMD_NAME(POWER_TABLE_CMD), + HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), + HCMD_NAME(REPLY_THERMAL_MNG_BACKOFF), + HCMD_NAME(DC2DC_CONFIG_CMD), + HCMD_NAME(NVM_ACCESS_CMD), + HCMD_NAME(SET_CALIB_DEFAULT_CMD), + HCMD_NAME(BEACON_NOTIFICATION), + HCMD_NAME(BEACON_TEMPLATE_CMD), + HCMD_NAME(TX_ANT_CONFIGURATION_CMD), + HCMD_NAME(BT_CONFIG), + HCMD_NAME(STATISTICS_CMD), + HCMD_NAME(STATISTICS_NOTIFICATION), + HCMD_NAME(EOSP_NOTIFICATION), + HCMD_NAME(REDUCE_TX_POWER_CMD), + HCMD_NAME(CARD_STATE_CMD), + HCMD_NAME(CARD_STATE_NOTIFICATION), + HCMD_NAME(MISSED_BEACONS_NOTIFICATION), + HCMD_NAME(TDLS_CONFIG_CMD), + HCMD_NAME(MAC_PM_POWER_TABLE), + HCMD_NAME(TDLS_CHANNEL_SWITCH_NOTIFICATION), + HCMD_NAME(MFUART_LOAD_NOTIFICATION), + HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC), + HCMD_NAME(REPLY_RX_PHY_CMD), + HCMD_NAME(REPLY_RX_MPDU_CMD), + HCMD_NAME(BA_NOTIF), + HCMD_NAME(MCC_UPDATE_CMD), + HCMD_NAME(MCC_CHUB_UPDATE_CMD), + HCMD_NAME(MARKER_CMD), + HCMD_NAME(BT_COEX_PRIO_TABLE), + HCMD_NAME(BT_COEX_PROT_ENV), + HCMD_NAME(BT_PROFILE_NOTIFICATION), + HCMD_NAME(BCAST_FILTER_CMD), + HCMD_NAME(MCAST_FILTER_CMD), + HCMD_NAME(REPLY_SF_CFG_CMD), + HCMD_NAME(REPLY_BEACON_FILTERING_CMD), + HCMD_NAME(D3_CONFIG_CMD), + HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), + HCMD_NAME(OFFLOADS_QUERY_CMD), + HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), + HCMD_NAME(MATCH_FOUND_NOTIFICATION), + HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER), + HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), + HCMD_NAME(WOWLAN_PATTERNS), + HCMD_NAME(WOWLAN_CONFIGURATION), + HCMD_NAME(WOWLAN_TSC_RSC_PARAM), + HCMD_NAME(WOWLAN_TKIP_PARAM), + HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL), + HCMD_NAME(WOWLAN_GET_STATUSES), + HCMD_NAME(WOWLAN_TX_POWER_PER_DB), + HCMD_NAME(SCAN_ITERATION_COMPLETE), + HCMD_NAME(D0I3_END_CMD), + HCMD_NAME(LTR_CONFIG), + HCMD_NAME(REPLY_DEBUG_CMD), }; -#undef CMD + +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { + HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), + HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), +}; + +static const struct iwl_hcmd_arr iwl_mvm_groups[] = { + [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), + [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), + [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), +}; + /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); @@ -508,13 +533,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; - trans_cfg.command_names = iwl_mvm_cmd_strings; + trans_cfg.command_groups = iwl_mvm_groups; + trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; + trans_cfg.sw_csum_tx = IWL_MVM_SW_TX_CSUM_OFFLOAD; /* Set a short watchdog for the command queue */ trans_cfg.cmd_q_wdg_timeout = @@ -577,9 +604,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, goto out_free; mutex_lock(&mvm->mutex); + iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); if (!err || !iwlmvm_mod_params.init_dbg) iwl_trans_stop_device(trans); + iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); /* returns 0 if successful, 1 if success but in rfkill */ if (err < 0 && !iwlmvm_mod_params.init_dbg) { @@ -607,8 +636,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); - /* rpm starts with a taken ref. only set the appropriate bit here. */ - mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; + /* rpm starts with a taken reference, we can release it now */ + iwl_trans_unref(mvm->trans); iwl_mvm_tof_init(mvm); @@ -793,6 +822,8 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode, if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); + else if (pkt->hdr.cmd == FRAME_RELEASE) + iwl_mvm_rx_frame_release(mvm, rxb, 0); else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) iwl_mvm_rx_rx_phy_cmd(mvm, rxb); else @@ -807,9 +838,9 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) - iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); + iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0); else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) - iwl_mvm_rx_rx_phy_cmd(mvm, rxb); + iwl_mvm_rx_phy_cmd_mq(mvm, rxb); else iwl_mvm_rx_common(mvm, rxb, pkt); } @@ -839,6 +870,18 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) } } +static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, + const struct iwl_device_cmd *cmd) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + /* + * For now, we only set the CMD_WANT_ASYNC_CALLBACK for ADD_STA + * commands that need to block the Tx queues. + */ + iwl_trans_block_txq_ptrs(mvm->trans, false); +} + static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -1033,6 +1076,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) struct iwl_d0i3_iter_data { struct iwl_mvm *mvm; + struct ieee80211_vif *connected_vif; u8 ap_sta_id; u8 vif_count; u8 offloading_tid; @@ -1113,7 +1157,8 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, data->disable_offloading = true; iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags); - iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, flags); + iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, + false, flags); /* * on init/association, mvm already configures POWER_TABLE_CMD @@ -1123,6 +1168,12 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, */ data->ap_sta_id = mvmvif->ap_sta_id; data->vif_count++; + + /* + * no new commands can be sent at this stage, so it's safe + * to save the vif pointer during d0i3 entrance. + */ + data->connected_vif = vif; } static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, @@ -1144,7 +1195,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; cmd->offloading_tid = iter_data->offloading_tid; - + cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | + ENABLE_DHCP_FILTERING; /* * The d0i3 uCode takes care of the nonqos counters, * so configure only the qos seq ones. @@ -1175,6 +1227,9 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); + if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR)) + return -EINVAL; + set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); /* @@ -1213,6 +1268,10 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) /* configure wowlan configuration only if needed */ if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) { + iwl_mvm_wowlan_config_key_params(mvm, + d0i3_iter_data.connected_vif, + true, flags); + iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data); @@ -1242,25 +1301,30 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); } -struct iwl_mvm_wakeup_reason_iter_data { +struct iwl_mvm_d0i3_exit_work_iter_data { struct iwl_mvm *mvm; + struct iwl_wowlan_status *status; u32 wakeup_reasons; }; -static void iwl_mvm_d0i3_wakeup_reason_iter(void *_data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_d0i3_exit_work_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) { - struct iwl_mvm_wakeup_reason_iter_data *data = _data; + struct iwl_mvm_d0i3_exit_work_iter_data *data = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u32 reasons = data->wakeup_reasons; - if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && - data->mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) { - if (data->wakeup_reasons & - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH) - iwl_mvm_connection_loss(data->mvm, vif, "D0i3"); - else - ieee80211_beacon_loss(vif); - } + /* consider only the relevant station interface */ + if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc || + data->mvm->d0i3_ap_sta_id != mvmvif->ap_sta_id) + return; + + if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH) + iwl_mvm_connection_loss(data->mvm, vif, "D0i3"); + else if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON) + ieee80211_beacon_loss(vif); + else + iwl_mvm_d0i3_update_keys(data->mvm, vif, data->status); } void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) @@ -1326,9 +1390,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) .id = WOWLAN_GET_STATUSES, .flags = CMD_HIGH_PRIO | CMD_WANT_SKB, }; + struct iwl_mvm_d0i3_exit_work_iter_data iter_data = { + .mvm = mvm, + }; + struct iwl_wowlan_status *status; int ret; - u32 handled_reasons, wakeup_reasons = 0; + u32 wakeup_reasons = 0; __le16 *qos_seq = NULL; mutex_lock(&mvm->mutex); @@ -1345,18 +1413,12 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); - handled_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; - if (wakeup_reasons & handled_reasons) { - struct iwl_mvm_wakeup_reason_iter_data data = { - .mvm = mvm, - .wakeup_reasons = wakeup_reasons, - }; - - ieee80211_iterate_active_interfaces( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d0i3_wakeup_reason_iter, &data); - } + iter_data.wakeup_reasons = wakeup_reasons; + iter_data.status = status; + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_d0i3_exit_work_iter, + &iter_data); out: iwl_mvm_d0i3_enable_tx(mvm, qos_seq); @@ -1382,6 +1444,9 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm) IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); + if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR)) + return -EINVAL; + mutex_lock(&mvm->d0i3_suspend_mutex); if (test_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags)) { IWL_DEBUG_RPM(mvm, "Deferring d0i3 exit until resume\n"); @@ -1414,6 +1479,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) #define IWL_MVM_COMMON_OPS \ /* these could be differentiated */ \ + .async_cb = iwl_mvm_async_cb, \ .queue_full = iwl_mvm_stop_sw_queue, \ .queue_not_full = iwl_mvm_wake_sw_queue, \ .hw_rf_kill = iwl_mvm_set_hw_rfkill_state, \ @@ -1438,8 +1504,12 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode, unsigned int queue) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + struct iwl_rx_packet *pkt = rxb_addr(rxb); - iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); + if (unlikely(pkt->hdr.cmd == FRAME_RELEASE)) + iwl_mvm_rx_frame_release(mvm, rxb, queue); + else + iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue); } static const struct iwl_op_mode_ops iwl_mvm_ops_mq = { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index e68a475e3071..6e6a56f2153d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index bed9696ee410..87a9f244e151 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c index 509a66d05245..0b762b4f8fad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 54789bd3b352..7bb6fd0e4391 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -20,7 +20,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -552,9 +552,10 @@ static char *rs_pretty_rate(const struct rs_rate *rate) }; const char *rate_str; - if (is_type_legacy(rate->type)) + if (is_type_legacy(rate->type) && (rate->index <= IWL_RATE_54M_INDEX)) rate_str = legacy_rates[rate->index]; - else if (is_type_ht(rate->type) || is_type_vht(rate->type)) + else if ((is_type_ht(rate->type) || is_type_vht(rate->type)) && + (rate->index <= IWL_RATE_MCS_9_INDEX)) rate_str = ht_vht_rates[rate->index]; else rate_str = "BAD_RATE"; @@ -2550,6 +2551,8 @@ static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { { S8_MIN, IWL_RATE_MCS_0_INDEX }, }; +#define IWL_RS_LOW_RSSI_THRESHOLD (-76) /* dBm */ + /* Init the optimal rate based on STA caps * This combined with rssi is used to report the last tx rate * to userspace when we haven't transmitted enough frames. @@ -2635,11 +2638,13 @@ static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm, * of last Rx */ static void rs_get_initial_rate(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, enum ieee80211_band band, struct rs_rate *rate) { int i, nentries; + unsigned long active_rate; s8 best_rssi = S8_MIN; u8 best_ant = ANT_NONE; u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); @@ -2680,19 +2685,55 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } - if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { - for (i = 0; i < nentries; i++) { - int rate_idx = initial_rates[i].rate_idx; - if ((best_rssi >= initial_rates[i].rssi) && - (BIT(rate_idx) & lq_sta->active_legacy_rate)) { - rate->index = rate_idx; - break; - } + if (!IWL_MVM_RS_RSSI_BASED_INIT_RATE) + goto out; + + /* Start from a higher rate if the corresponding debug capability + * is enabled. The rate is chosen according to AP capabilities. + * In case of VHT/HT when the rssi is low fallback to the case of + * legacy rates. + */ + if (sta->vht_cap.vht_supported && + best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { + if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { + initial_rates = rs_optimal_rates_vht_40_80mhz; + nentries = ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); + if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) + rate->bw = RATE_MCS_CHAN_WIDTH_80; + else + rate->bw = RATE_MCS_CHAN_WIDTH_40; + } else if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { + initial_rates = rs_optimal_rates_vht_20mhz; + nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); + rate->bw = RATE_MCS_CHAN_WIDTH_20; + } else { + IWL_ERR(mvm, "Invalid BW %d\n", sta->bandwidth); + goto out; + } + active_rate = lq_sta->active_siso_rate; + rate->type = LQ_VHT_SISO; + } else if (sta->ht_cap.ht_supported && + best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { + initial_rates = rs_optimal_rates_ht; + nentries = ARRAY_SIZE(rs_optimal_rates_ht); + active_rate = lq_sta->active_siso_rate; + rate->type = LQ_HT_SISO; + } else { + active_rate = lq_sta->active_legacy_rate; + } + + for (i = 0; i < nentries; i++) { + int rate_idx = initial_rates[i].rate_idx; + + if ((best_rssi >= initial_rates[i].rssi) && + (BIT(rate_idx) & active_rate)) { + rate->index = rate_idx; + break; } } - IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index, - rs_pretty_ant(rate->ant)); +out: + rs_dump_rate(mvm, rate, "INITIAL"); } /* Save info about RSSI of last Rx */ @@ -2752,14 +2793,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; - rs_get_initial_rate(mvm, lq_sta, band, rate); + rs_get_initial_rate(mvm, sta, lq_sta, band, rate); rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); - if (rate->ant == ANT_A) - tbl->column = RS_COLUMN_LEGACY_ANT_A; - else - tbl->column = RS_COLUMN_LEGACY_ANT_B; + tbl->column = rs_get_column_from_rate(rate); rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_lq_cmd(mvm, sta, lq_sta, rate); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 81314ad9ebe0..bdb6f2d8d854 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -20,7 +20,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index a0e957a4018d..145ec68ce6f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c new file mode 100644 index 000000000000..e2a872deb668 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -0,0 +1,378 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include +#include +#include "iwl-trans.h" +#include "mvm.h" +#include "fw-api.h" +#include "fw-dbg.h" + +void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ + mvm->ampdu_ref++; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { + spin_lock(&mvm->drv_stats_lock); + mvm->drv_rx_stats.ampdu_count++; + spin_unlock(&mvm->drv_stats_lock); + } +#endif +} + +static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, + struct napi_struct *napi, + struct sk_buff *skb, + struct ieee80211_hdr *hdr, u16 len, + u32 ampdu_status, u8 crypt_len, + struct iwl_rx_cmd_buffer *rxb) +{ + unsigned int hdrlen, fraglen; + + /* If frame is small enough to fit in skb->head, pull it completely. + * If not, only pull ieee80211_hdr (including crypto if present, and + * an additional 8 bytes for SNAP/ethertype, see below) so that + * splice() or TCP coalesce are more efficient. + * + * Since, in addition, ieee80211_data_to_8023() always pull in at + * least 8 bytes (possibly more for mesh) we can do the same here + * to save the cost of doing it later. That still doesn't pull in + * the actual IP header since the typical case has a SNAP header. + * If the latter changes (there are efforts in the standards group + * to do so) we should revisit this and ieee80211_data_to_8023(). + */ + hdrlen = (len <= skb_tailroom(skb)) ? len : + sizeof(*hdr) + crypt_len + 8; + + memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + fraglen = len - hdrlen; + + if (fraglen) { + int offset = (void *)hdr + hdrlen - + rxb_addr(rxb) + rxb_offset(rxb); + + skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, + fraglen, rxb->truesize); + } + + ieee80211_rx_napi(mvm->hw, skb, napi); +} + +static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_rx_status *rx_status) +{ + int energy_a, energy_b, energy_c, max_energy; + + energy_a = desc->energy_a; + energy_a = energy_a ? -energy_a : S8_MIN; + energy_b = desc->energy_b; + energy_b = energy_b ? -energy_b : S8_MIN; + energy_c = desc->energy_c; + energy_c = energy_c ? -energy_c : S8_MIN; + max_energy = max(energy_a, energy_b); + max_energy = max(max_energy, energy_c); + + IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n", + energy_a, energy_b, energy_c, max_energy); + + rx_status->signal = max_energy; + rx_status->chains = 0; /* TODO: phy info */ + rx_status->chain_signal[0] = energy_a; + rx_status->chain_signal[1] = energy_b; + rx_status->chain_signal[2] = energy_c; +} + +static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *stats, + struct iwl_rx_mpdu_desc *desc, int queue, + u8 *crypt_len) +{ + u16 status = le16_to_cpu(desc->status); + + if (!ieee80211_has_protected(hdr->frame_control) || + (status & IWL_RX_MPDU_STATUS_SEC_MASK) == + IWL_RX_MPDU_STATUS_SEC_NONE) + return 0; + + /* TODO: handle packets encrypted with unknown alg */ + + switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { + case IWL_RX_MPDU_STATUS_SEC_CCM: + case IWL_RX_MPDU_STATUS_SEC_GCM: + /* alg is CCM: check MIC only */ + if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) + return -1; + + stats->flag |= RX_FLAG_DECRYPTED; + *crypt_len = IEEE80211_CCMP_HDR_LEN; + return 0; + case IWL_RX_MPDU_STATUS_SEC_TKIP: + /* Don't drop the frame and decrypt it in SW */ + if (!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) + return 0; + + *crypt_len = IEEE80211_TKIP_IV_LEN; + /* fall through if TTAK OK */ + case IWL_RX_MPDU_STATUS_SEC_WEP: + if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) + return -1; + + stats->flag |= RX_FLAG_DECRYPTED; + if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == + IWL_RX_MPDU_STATUS_SEC_WEP) + *crypt_len = IEEE80211_WEP_IV_LEN; + return 0; + case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: + if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) + return -1; + stats->flag |= RX_FLAG_DECRYPTED; + return 0; + default: + IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); + } + + return 0; +} + +static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, + struct sk_buff *skb, + struct iwl_rx_mpdu_desc *desc) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + + if (mvmvif->features & NETIF_F_RXCSUM && + desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_IP_HDR_CSUM_OK) && + desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_TCP_UDP_CSUM_OK)) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + +void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue) +{ + struct ieee80211_rx_status *rx_status; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; + struct ieee80211_hdr *hdr = (void *)(desc + 1); + u32 len = le16_to_cpu(desc->mpdu_len); + u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); + struct ieee80211_sta *sta = NULL; + struct sk_buff *skb; + u32 ampdu_status; + u8 crypt_len = 0; + + /* Dont use dev_alloc_skb(), we'll have enough headroom once + * ieee80211_hdr pulled. + */ + skb = alloc_skb(128, GFP_ATOMIC); + if (!skb) { + IWL_ERR(mvm, "alloc_skb failed\n"); + return; + } + + rx_status = IEEE80211_SKB_RXCB(skb); + + if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, queue, &crypt_len)) { + kfree_skb(skb); + return; + } + + /* + * Keep packets with CRC errors (and with overrun) for monitor mode + * (otherwise the firmware discards them) but mark them as bad. + */ + if (!(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_CRC_OK)) || + !(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_OVERRUN_OK))) { + IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", + le16_to_cpu(desc->status)); + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + } + + rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); + rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); + rx_status->band = desc->channel > 14 ? IEEE80211_BAND_5GHZ : + IEEE80211_BAND_2GHZ; + rx_status->freq = ieee80211_channel_to_frequency(desc->channel, + rx_status->band); + iwl_mvm_get_signal_strength(mvm, desc, rx_status); + + rcu_read_lock(); + + if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) { + u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; + + if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) { + sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); + if (IS_ERR(sta)) + sta = NULL; + } + } else if (!is_multicast_ether_addr(hdr->addr2)) { + /* + * This is fine since we prevent two stations with the same + * address from being added. + */ + sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); + } + + if (sta) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + /* + * We have tx blocked stations (with CS bit). If we heard + * frames from a blocked station on a new channel we can + * TX to it again. + */ + if (unlikely(mvm->csa_tx_block_bcn_timeout)) + iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); + + rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); + + if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && + ieee80211_is_beacon(hdr->frame_control)) { + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; + bool trig_check; + s32 rssi; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, + FW_DBG_TRIGGER_RSSI); + rssi_trig = (void *)trig->data; + rssi = le32_to_cpu(rssi_trig->rssi); + + trig_check = + iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, + trig); + if (trig_check && rx_status->signal < rssi) + iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); + } + + /* TODO: multi queue TCM */ + + if (ieee80211_is_data(hdr->frame_control)) + iwl_mvm_rx_csum(sta, skb, desc); + } + + rcu_read_unlock(); + + /* + * TODO: PHY info. + * Verify we don't have the information in the MPDU descriptor and + * that it is not needed. + * Make sure for monitor mode that we are on default queue, update + * ampdu_ref and the rest of phy info then + */ + + /* Set up the HT phy flags */ + switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { + case RATE_MCS_CHAN_WIDTH_20: + break; + case RATE_MCS_CHAN_WIDTH_40: + rx_status->flag |= RX_FLAG_40MHZ; + break; + case RATE_MCS_CHAN_WIDTH_80: + rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; + break; + case RATE_MCS_CHAN_WIDTH_160: + rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; + break; + } + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status->flag |= RX_FLAG_SHORT_GI; + if (rate_n_flags & RATE_HT_MCS_GF_MSK) + rx_status->flag |= RX_FLAG_HT_GF; + if (rate_n_flags & RATE_MCS_LDPC_MSK) + rx_status->flag |= RX_FLAG_LDPC; + if (rate_n_flags & RATE_MCS_HT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> + RATE_MCS_STBC_POS; + rx_status->flag |= RX_FLAG_HT; + rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; + rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; + } else if (rate_n_flags & RATE_MCS_VHT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> + RATE_MCS_STBC_POS; + rx_status->vht_nss = + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> + RATE_VHT_MCS_NSS_POS) + 1; + rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; + rx_status->flag |= RX_FLAG_VHT; + rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_BF_MSK) + rx_status->vht_flag |= RX_VHT_FLAG_BF; + } else { + rx_status->rate_idx = + iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, + rx_status->band); + } + + /* TODO: PHY info - update ampdu queue statistics (for debugfs) */ + /* TODO: PHY info - gscan */ + + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status, + crypt_len, rxb); +} + +void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, int queue) +{ + /* TODO */ +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 7cbfb085f60b..bee3201c7116 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -72,13 +72,6 @@ #define IWL_DENSE_EBS_SCAN_RATIO 5 #define IWL_SPARSE_EBS_SCAN_RATIO 1 -enum iwl_mvm_scan_type { - IWL_SCAN_TYPE_UNASSOC, - IWL_SCAN_TYPE_WILD, - IWL_SCAN_TYPE_MILD, - IWL_SCAN_TYPE_FRAGMENTED, -}; - enum iwl_mvm_traffic_load { IWL_MVM_TRAFFIC_LOW, IWL_MVM_TRAFFIC_MEDIUM, @@ -89,6 +82,7 @@ struct iwl_mvm_scan_timing_params { u32 dwell_active; u32 dwell_passive; u32 dwell_fragmented; + u32 dwell_extended; u32 suspend_time; u32 max_out_time; }; @@ -98,6 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { .dwell_active = 10, .dwell_passive = 110, .dwell_fragmented = 44, + .dwell_extended = 100, .suspend_time = 0, .max_out_time = 0, }, @@ -105,6 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { .dwell_active = 10, .dwell_passive = 110, .dwell_fragmented = 44, + .dwell_extended = 100, .suspend_time = 30, .max_out_time = 120, }, @@ -112,6 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { .dwell_active = 10, .dwell_passive = 110, .dwell_fragmented = 44, + .dwell_extended = 100, .suspend_time = 120, .max_out_time = 120, }, @@ -119,6 +116,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { .dwell_active = 10, .dwell_passive = 110, .dwell_fragmented = 44, + .dwell_extended = 44, .suspend_time = 95, .max_out_time = 44, }, @@ -206,9 +204,7 @@ static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) } static enum -iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mvm_scan_params *params) +iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) { int global_cnt = 0; enum iwl_mvm_traffic_load load; @@ -224,8 +220,7 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, load = iwl_mvm_get_traffic_load(mvm); low_latency = iwl_mvm_low_latency(mvm); - if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && - vif->type != NL80211_IFTYPE_P2P_DEVICE && + if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && !p2p_device && fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) return IWL_SCAN_TYPE_FRAGMENTED; @@ -726,6 +721,7 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm, cmd->active_dwell = scan_timing[params->type].dwell_active; cmd->passive_dwell = scan_timing[params->type].dwell_passive; cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented; + cmd->extended_dwell = scan_timing[params->type].dwell_extended; cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time); cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time); cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); @@ -759,8 +755,15 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, vif->type != NL80211_IFTYPE_P2P_DEVICE); } +static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params) +{ + return params->n_scan_plans == 1 && + params->scan_plans[0].iterations == 1; +} + static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, - struct iwl_mvm_scan_params *params) + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif) { int flags = 0; @@ -786,6 +789,10 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; #endif + if (iwl_mvm_is_regular_scan(params) && + vif->type != NL80211_IFTYPE_P2P_DEVICE) + flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL; + return flags; } @@ -814,7 +821,8 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->delay = cpu_to_le32(params->delay); - cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params)); + cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params, + vif)); cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | @@ -917,18 +925,20 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) struct iwl_host_cmd cmd = { .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), }; + enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) return -ENOBUFS; + if (type == mvm->scan_type) + return 0; + cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels; scan_config = kzalloc(cmd_size, GFP_KERNEL); if (!scan_config) return -ENOMEM; - mvm->scan_fragmented = iwl_mvm_low_latency(mvm); - scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | SCAN_CONFIG_FLAG_SET_TX_CHAINS | @@ -938,17 +948,19 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) SCAN_CONFIG_FLAG_SET_MAC_ADDR | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| SCAN_CONFIG_N_CHANNELS(num_channels) | - (mvm->scan_fragmented ? + (type == IWL_SCAN_TYPE_FRAGMENTED ? SCAN_CONFIG_FLAG_SET_FRAGMENTED : SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED)); scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); - scan_config->out_of_channel_time = cpu_to_le32(170); - scan_config->suspend_time = cpu_to_le32(30); - scan_config->dwell_active = 20; - scan_config->dwell_passive = 110; - scan_config->dwell_fragmented = 20; + scan_config->out_of_channel_time = + cpu_to_le32(scan_timing[type].max_out_time); + scan_config->suspend_time = cpu_to_le32(scan_timing[type].suspend_time); + scan_config->dwell_active = scan_timing[type].dwell_active; + scan_config->dwell_passive = scan_timing[type].dwell_passive; + scan_config->dwell_fragmented = scan_timing[type].dwell_fragmented; + scan_config->dwell_extended = scan_timing[type].dwell_extended; memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); @@ -972,6 +984,8 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); ret = iwl_mvm_send_cmd(mvm, &cmd); + if (!ret) + mvm->scan_type = type; kfree(scan_config); return ret; @@ -988,16 +1002,11 @@ static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status) return -ENOENT; } -static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params) -{ - return params->n_scan_plans == 1 && - params->scan_plans[0].iterations == 1; -} - static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_umac *cmd, struct iwl_mvm_scan_params *params) { + cmd->extended_dwell = scan_timing[params->type].dwell_extended; cmd->active_dwell = scan_timing[params->type].dwell_active; cmd->passive_dwell = scan_timing[params->type].dwell_passive; cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented; @@ -1032,7 +1041,8 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, } static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, - struct iwl_mvm_scan_params *params) + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif) { int flags = 0; @@ -1060,6 +1070,11 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (mvm->scan_iter_notif_enabled) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; #endif + + if (iwl_mvm_is_regular_scan(params) && + vif->type != NL80211_IFTYPE_P2P_DEVICE) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; + return flags; } @@ -1090,7 +1105,8 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->scan_uid_status[uid] = type; cmd->uid = cpu_to_le32(uid); - cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params)); + cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params, + vif)); if (type == IWL_MVM_SCAN_SCHED) cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); @@ -1225,7 +1241,9 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, params.scan_plans = &scan_plan; params.n_scan_plans = 1; - params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); + params.type = + iwl_mvm_get_scan_type(mvm, + vif->type == NL80211_IFTYPE_P2P_DEVICE); iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); @@ -1307,7 +1325,9 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.n_scan_plans = req->n_scan_plans; params.scan_plans = req->scan_plans; - params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); + params.type = + iwl_mvm_get_scan_type(mvm, + vif->type == NL80211_IFTYPE_P2P_DEVICE); /* In theory, LMAC scans can handle a 32-bit delay, but since * waiting for over 18 hours to start the scan is a bit silly diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 2b976b110207..b556e33658d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -106,6 +106,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, .add_modify = update ? 1 : 0, .station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK | STA_FLG_MIMO_EN_MSK), + .tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg), }; int ret; u32 status; @@ -277,11 +278,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (sta_id == IWL_MVM_STATION_COUNT) return -ENOSPC; - if (vif->type == NL80211_IFTYPE_AP) { - mvmvif->ap_assoc_sta_count++; - iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); - } - spin_lock_init(&mvm_sta->lock); mvm_sta->sta_id = sta_id; @@ -580,9 +576,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta, - u32 qmask, enum nl80211_iftype iftype) +int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + u32 qmask, enum nl80211_iftype iftype) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); @@ -622,6 +618,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, color)); cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); + cmd.tid_disable_tx = cpu_to_le16(0xffff); if (addr) memcpy(cmd.addr, addr, ETH_ALEN); @@ -671,6 +668,33 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) return ret; } +int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); + return iwl_mvm_add_int_sta_common(mvm, &mvm->snif_sta, vif->addr, + mvmvif->id, 0); +} + +int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + int ret; + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); + if (ret) + IWL_WARN(mvm, "Failed sending remove station\n"); + + return ret; +} + +void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm) +{ + iwl_mvm_dealloc_int_sta(mvm, &mvm->snif_sta); +} + void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm) { lockdep_assert_held(&mvm->mutex); @@ -1196,22 +1220,17 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) if (max_offs < 0) return STA_KEY_IDX_INVALID; - __set_bit(max_offs, mvm->fw_key_table); - return max_offs; } -static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (sta) { - struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); - - return mvm_sta->sta_id; - } + if (sta) + return iwl_mvm_sta_from_mac80211(sta); /* * The device expects GTKs for station interfaces to be @@ -1230,12 +1249,12 @@ static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm, * be the AP ID, and no station was passed by mac80211. */ if (IS_ERR_OR_NULL(sta)) - return IWL_MVM_STATION_COUNT; + return NULL; - return sta_id; + return iwl_mvm_sta_from_mac80211(sta); } - return IWL_MVM_STATION_COUNT; + return NULL; } static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, @@ -1452,6 +1471,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, u8 key_offset) { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); + struct iwl_mvm_sta *mvm_sta; u8 sta_id; int ret; static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; @@ -1459,11 +1479,12 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); - if (sta_id == IWL_MVM_STATION_COUNT) { - IWL_ERR(mvm, "Failed to find station id\n"); + mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); + if (!mvm_sta) { + IWL_ERR(mvm, "Failed to find station\n"); return -EINVAL; } + sta_id = mvm_sta->sta_id; if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); @@ -1505,10 +1526,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, } ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast); - if (ret) { - __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); + if (ret) goto end; - } /* * For WEP, the same key is used for multicast and unicast. Upload it @@ -1521,11 +1540,13 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, !mcast); if (ret) { - __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); + goto end; } } + __set_bit(key_offset, mvm->fw_key_table); + end: IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", keyconf->cipher, keyconf->keylen, keyconf->keyidx, @@ -1539,13 +1560,14 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, struct ieee80211_key_conf *keyconf) { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); - u8 sta_id; + struct iwl_mvm_sta *mvm_sta; + u8 sta_id = IWL_MVM_STATION_COUNT; int ret, i; lockdep_assert_held(&mvm->mutex); - /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); + /* Get the station from the mvm local station table */ + mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); @@ -1566,11 +1588,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, } mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; - if (sta_id == IWL_MVM_STATION_COUNT) { + if (!mvm_sta) { IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); return 0; } + sta_id = mvm_sta->sta_id; + ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); if (ret) return ret; @@ -1590,24 +1614,13 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, u16 *phase1key) { struct iwl_mvm_sta *mvm_sta; - u8 sta_id; bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); rcu_read_lock(); - sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); - if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) + mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); + if (WARN_ON_ONCE(!mvm_sta)) goto unlock; - - if (!sta) { - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (WARN_ON(IS_ERR_OR_NULL(sta))) { - rcu_read_unlock(); - return; - } - } - - mvm_sta = iwl_mvm_sta_from_mac80211(sta); iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); @@ -1665,6 +1678,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, */ if (agg) { int remaining = cnt; + int sleep_tx_count; spin_lock_bh(&mvmsta->lock); for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) { @@ -1689,9 +1703,12 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, } remaining -= n_queued; } + sleep_tx_count = cnt - remaining; + if (reason == IEEE80211_FRAME_RELEASE_UAPSD) + mvmsta->sleep_tx_count = sleep_tx_count; spin_unlock_bh(&mvmsta->lock); - cmd.sleep_tx_count = cpu_to_le16(cnt - remaining); + cmd.sleep_tx_count = cpu_to_le16(sleep_tx_count); if (WARN_ON(cnt - remaining == 0)) { ieee80211_sta_eosp(sta); return; @@ -1709,7 +1726,12 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD); } - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); + /* block the Tx queues until the FW updated the sleep Tx count */ + iwl_trans_block_txq_ptrs(mvm->trans, true); + + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, + CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK, + sizeof(cmd), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 0631cc0a6d3c..badf17c7fcca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -303,6 +303,11 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) * @tt_tx_protection: is thermal throttling enable Tx protection? * @disable_tx: is tx to this STA disabled? * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) + * @sleep_tx_count: the number of frames that we told the firmware to let out + * even when that station is asleep. This is useful in case the queue + * gets empty before all the frames were sent, which can happen when + * we are sending frames from an AMPDU queue and there was a hole in + * the BA window. To be used for UAPSD only. * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -329,6 +334,7 @@ struct iwl_mvm_sta { bool disable_tx; u8 agg_tids; + u8 sleep_tx_count; }; static inline struct iwl_mvm_sta * @@ -401,7 +407,13 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + u32 qmask, enum nl80211_iftype iftype); void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm); void iwl_mvm_sta_drained_wk(struct work_struct *wk); void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index fe2fa5650443..18711c5de35a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 87a04c32cb92..924dd6a41626 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -792,11 +792,9 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } -void iwl_mvm_stop_roc(struct iwl_mvm *mvm) +static struct iwl_mvm_time_event_data *iwl_mvm_get_roc_te(struct iwl_mvm *mvm) { - struct iwl_mvm_vif *mvmvif = NULL; struct iwl_mvm_time_event_data *te_data; - bool is_p2p = false; lockdep_assert_held(&mvm->mutex); @@ -810,11 +808,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) * request */ list_for_each_entry(te_data, &mvm->time_event_list, list) { - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { - mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - is_p2p = true; - goto remove_te; - } + if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) + goto out; } /* There can only be at most one AUX ROC time event, we just use the @@ -823,18 +818,35 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) te_data = list_first_entry_or_null(&mvm->aux_roc_te_list, struct iwl_mvm_time_event_data, list); - if (te_data) - mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - -remove_te: +out: spin_unlock_bh(&mvm->time_event_lock); + return te_data; +} - if (!mvmvif) { +void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) +{ + struct iwl_mvm_time_event_data *te_data; + u32 uid; + + te_data = iwl_mvm_get_roc_te(mvm); + if (te_data) + __iwl_mvm_remove_time_event(mvm, te_data, &uid); +} + +void iwl_mvm_stop_roc(struct iwl_mvm *mvm) +{ + struct iwl_mvm_vif *mvmvif; + struct iwl_mvm_time_event_data *te_data; + + te_data = iwl_mvm_get_roc_te(mvm); + if (!te_data) { IWL_WARN(mvm, "No remain on channel event\n"); return; } - if (is_p2p) + mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); + + if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) iwl_mvm_remove_time_event(mvm, mvmvif, te_data); else iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 61d7cd791b6e..99d9a35ad5b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -215,6 +215,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data); +void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm); void iwl_mvm_roc_done_wk(struct work_struct *wk); /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index 4007f1d421dd..a1947d6f3a2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h index 9beebc33cb8d..8c3421c9991d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h @@ -25,7 +25,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index aaebb5d4462a..8bf48a7d0f4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -64,6 +64,7 @@ *****************************************************************************/ #include #include +#include #include "iwl-trans.h" #include "iwl-eeprom-parse.h" @@ -345,8 +346,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); memset(&info->status, 0, sizeof(info->status)); + memset(info->driver_data, 0, sizeof(info->driver_data)); - info->driver_data[0] = NULL; info->driver_data[1] = dev_cmd; return dev_cmd; @@ -425,11 +426,39 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) return 0; } +static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb_gso, + struct ieee80211_sta *sta, + struct sk_buff_head *mpdus_skb) +{ + struct sk_buff *tmp, *next; + char cb[sizeof(skb_gso->cb)]; + + memcpy(cb, skb_gso->cb, sizeof(cb)); + next = skb_gso_segment(skb_gso, 0); + if (IS_ERR(next)) + return -EINVAL; + else if (next) + consume_skb(skb_gso); + + while (next) { + tmp = next; + next = tmp->next; + memcpy(tmp->cb, cb, sizeof(tmp->cb)); + + tmp->prev = NULL; + tmp->next = NULL; + + __skb_queue_tail(mpdus_skb, tmp); + } + + return 0; +} + /* * Sets the fields in the Tx cmd that are crypto related */ -int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta) +static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_sta *sta) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -525,6 +554,51 @@ drop: return -1; } +int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_sta *sta) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct sk_buff_head mpdus_skbs; + unsigned int payload_len; + int ret; + + if (WARN_ON_ONCE(!mvmsta)) + return -1; + + if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) + return -1; + + if (!skb_is_gso(skb)) + return iwl_mvm_tx_mpdu(mvm, skb, sta); + + payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - + tcp_hdrlen(skb) + skb->data_len; + + if (payload_len <= skb_shinfo(skb)->gso_size) + return iwl_mvm_tx_mpdu(mvm, skb, sta); + + __skb_queue_head_init(&mpdus_skbs); + + ret = iwl_mvm_tx_tso(mvm, skb, sta, &mpdus_skbs); + if (ret) + return ret; + + if (WARN_ON(skb_queue_empty(&mpdus_skbs))) + return ret; + + while (!skb_queue_empty(&mpdus_skbs)) { + struct sk_buff *skb = __skb_dequeue(&mpdus_skbs); + + ret = iwl_mvm_tx_mpdu(mvm, skb, sta); + if (ret) { + __skb_queue_purge(&mpdus_skbs); + return ret; + } + } + + return 0; +} + static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 tid) { @@ -788,13 +862,43 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (tid != IWL_TID_NON_QOS) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + bool send_eosp_ndp = false; spin_lock_bh(&mvmsta->lock); tid_data->next_reclaimed = next_reclaimed; IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", next_reclaimed); iwl_mvm_check_ratid_empty(mvm, sta, tid); + + if (mvmsta->sleep_tx_count) { + mvmsta->sleep_tx_count--; + if (mvmsta->sleep_tx_count && + !iwl_mvm_tid_queued(tid_data)) { + /* + * The number of frames in the queue + * dropped to 0 even if we sent less + * frames than we thought we had on the + * Tx queue. + * This means we had holes in the BA + * window that we just filled, ask + * mac80211 to send EOSP since the + * firmware won't know how to do that. + * Send NDP and the firmware will send + * EOSP notification that will trigger + * a call to ieee80211_sta_eosp(). + */ + send_eosp_ndp = true; + } + } + spin_unlock_bh(&mvmsta->lock); + if (send_eosp_ndp) { + iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, + IEEE80211_FRAME_RELEASE_UAPSD, + 1, tid, false, false); + mvmsta->sleep_tx_count = 0; + ieee80211_send_eosp_nullfunc(sta, tid); + } } if (mvmsta->next_status_eosp) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index bbb7f6b27f5e..3a989f5c20db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -27,7 +27,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 9bdce443628b..af106513d38e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -471,19 +471,20 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x24FD, 0x0000, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0000, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x8010, iwl8265_2ac_cfg)}, /* 9000 Series */ {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl5165_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl5165_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl5165_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl5165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl5165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 44dc09d84d42..cc3888e2700d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -23,7 +23,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -278,6 +278,7 @@ struct iwl_txq { bool frozen; u8 active; bool ampdu; + bool block; unsigned long wd_timeout; }; @@ -288,6 +289,11 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) sizeof(struct iwl_pcie_txq_scratch_buf) * idx; } +struct iwl_tso_hdr_page { + struct page *page; + u8 *pos; +}; + /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data @@ -306,6 +312,8 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue * @wide_cmd_header: true when ucode supports wide command header format + * @sw_csum_tx: if true, then the transport will compute the csum of the TXed + * frame. * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw @@ -323,6 +331,8 @@ struct iwl_trans_pcie { struct net_device napi_dev; struct napi_struct napi; + struct __percpu iwl_tso_hdr_page *tso_hdr_page; + /* INT ICT Table */ __le32 *ict_tbl; dma_addr_t ict_tbl_dma; @@ -360,10 +370,9 @@ struct iwl_trans_pcie { bool bc_table_dword; bool scd_set_active; bool wide_cmd_header; + bool sw_csum_tx; u32 rx_page_order; - const char *const *command_names; - /*protect hw register */ spinlock_t reg_lock; bool cmd_hold_nic_awake; @@ -526,14 +535,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) return index & (q->n_window - 1); } -static inline const char *get_cmd_string(struct iwl_trans_pcie *trans_pcie, - u8 cmd) -{ - if (!trans_pcie->command_names || !trans_pcie->command_names[cmd]) - return "UNKNOWN"; - return trans_pcie->command_names[cmd]; -} - static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) { return !(iwl_read32(trans, CSR_GP_CNTRL) & diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 9193f0c7f104..ccafbd8cf4b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -877,7 +877,10 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x, seq 0x%x)\n", rxcb._offset, - get_cmd_string(trans_pcie, pkt->hdr.cmd), + iwl_get_cmd_string(trans, + iwl_cmd_id(pkt->hdr.cmd, + pkt->hdr.group_id, + 0)), pkt->hdr.cmd, le16_to_cpu(pkt->hdr.sequence)); len = iwl_rx_packet_len(pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index efef4871478d..d44e7afad593 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -26,7 +26,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -1213,7 +1213,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (trans->wowlan_d0i3) { + if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) { /* Enable persistence mode to avoid reset */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PERSIST_MODE); @@ -1237,7 +1237,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - if (!trans->wowlan_d0i3) { + if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D3) { /* * reset TX queues -- some of their registers reset during S3 * so if we don't reset everything here the D3 image would try @@ -1286,7 +1286,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, false); - if (trans->wowlan_d0i3) { + if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) { iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } else { @@ -1440,9 +1440,12 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size); trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header; - trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; trans_pcie->scd_set_active = trans_cfg->scd_set_active; + trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx; + + trans->command_groups = trans_cfg->command_groups; + trans->command_groups_size = trans_cfg->command_groups_size; /* init ref_count to 1 (should be cleared when ucode is loaded) */ trans_pcie->ref_count = 1; @@ -1462,6 +1465,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, void iwl_trans_pcie_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; synchronize_irq(trans_pcie->pci_dev->irq); @@ -1481,6 +1485,15 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) iwl_pcie_free_fw_monitor(trans); + for_each_possible_cpu(i) { + struct iwl_tso_hdr_page *p = + per_cpu_ptr(trans_pcie->tso_hdr_page, i); + + if (p->page) + __free_page(p->page); + } + + free_percpu(trans_pcie->tso_hdr_page); iwl_trans_free(trans); } @@ -1492,8 +1505,8 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state) clear_bit(STATUS_TPOWER_PMI, &trans->status); } -static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, - unsigned long *flags) +static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, + unsigned long *flags) { int ret; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1534,14 +1547,11 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (unlikely(ret < 0)) { iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - if (!silent) { - u32 val = iwl_read32(trans, CSR_GP_CNTRL); - WARN_ONCE(1, - "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", - val); - spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); - return false; - } + WARN_ONCE(1, + "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", + iwl_read32(trans, CSR_GP_CNTRL)); + spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); + return false; } out: @@ -1589,7 +1599,7 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, int offs, ret = 0; u32 *vals = buf; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr); for (offs = 0; offs < dwords; offs++) vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); @@ -1607,7 +1617,7 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, int offs, ret = 0; const u32 *vals = buf; - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); for (offs = 0; offs < dwords; offs++) iwl_write32(trans, HBUS_TARG_MEM_WDAT, @@ -1673,6 +1683,33 @@ next_queue: } } +static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; + + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { + struct iwl_txq *txq = &trans_pcie->txq[i]; + + if (i == trans_pcie->cmd_queue) + continue; + + spin_lock_bh(&txq->lock); + + if (!block && !(WARN_ON_ONCE(!txq->block))) { + txq->block--; + if (!txq->block) { + iwl_write32(trans, HBUS_TARG_WRPTR, + txq->q.write_ptr | (i << 8)); + } + } else if (block) { + txq->block++; + } + + spin_unlock_bh(&txq->lock); + } +} + #define IWL_FLUSH_WAIT_MS 2000 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) @@ -2206,7 +2243,7 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, __le32 *val; int i; - if (!iwl_trans_grab_nic_access(trans, false, &flags)) + if (!iwl_trans_grab_nic_access(trans, &flags)) return 0; (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FH_REGS); @@ -2233,7 +2270,7 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans, unsigned long flags; u32 i; - if (!iwl_trans_grab_nic_access(trans, false, &flags)) + if (!iwl_trans_grab_nic_access(trans, &flags)) return 0; iwl_write_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1); @@ -2467,6 +2504,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, + .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, .write8 = iwl_trans_pcie_write8, .write32 = iwl_trans_pcie_write32, @@ -2511,6 +2549,11 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->ref_lock); mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); + trans_pcie->tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); + if (!trans_pcie->tso_hdr_page) { + ret = -ENOMEM; + goto out_no_pci; + } ret = pci_enable_device(pdev); if (ret) @@ -2612,7 +2655,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_pci_disable_msi; } - if (iwl_trans_grab_nic_access(trans, false, &flags)) { + if (iwl_trans_grab_nic_access(trans, &flags)) { u32 hw_step; hw_step = iwl_read_prph_no_grab(trans, WFPM_CTRL_REG); @@ -2647,7 +2690,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } trans_pcie->inta_mask = CSR_INI_SET_MASK; - trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND; return trans; @@ -2660,6 +2702,7 @@ out_pci_release_regions: out_pci_disable_device: pci_disable_device(pdev); out_no_pci: + free_percpu(trans_pcie->tso_hdr_page); iwl_trans_free(trans); return ERR_PTR(ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index a8c8a4a7420b..5262028b5505 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -23,13 +23,17 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ #include +#include #include #include +#include +#include +#include #include "iwl-debug.h" #include "iwl-csr.h" @@ -318,7 +322,9 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, * trying to tx (during RFKILL, we're not trying to tx). */ IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr); - iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); + if (!txq->block) + iwl_write32(trans, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); } void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans) @@ -576,6 +582,19 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, return 0; } +static void iwl_pcie_free_tso_page(struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]) { + struct page *page = + info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]; + + __free_page(page); + info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = NULL; + } +} + /* * iwl_pcie_txq_unmap - Unmap any remaining DMA mappings and free skb's */ @@ -589,6 +608,15 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) while (q->write_ptr != q->read_ptr) { IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, q->read_ptr); + + if (txq_id != trans_pcie->cmd_queue) { + struct sk_buff *skb = txq->entries[q->read_ptr].skb; + + if (WARN_ON_ONCE(!skb)) + continue; + + iwl_pcie_free_tso_page(skb); + } iwl_pcie_txq_free_tfd(trans, txq); q->read_ptr = iwl_queue_inc_wrap(q->read_ptr); } @@ -742,7 +770,7 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) spin_lock(&trans_pcie->irq_lock); - if (!iwl_trans_grab_nic_access(trans, false, &flags)) + if (!iwl_trans_grab_nic_access(trans, &flags)) goto out; /* Stop each Tx DMA channel */ @@ -1006,11 +1034,14 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, for (; q->read_ptr != tfd_num; q->read_ptr = iwl_queue_inc_wrap(q->read_ptr)) { + struct sk_buff *skb = txq->entries[txq->q.read_ptr].skb; - if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL)) + if (WARN_ON_ONCE(!skb)) continue; - __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb); + iwl_pcie_free_tso_page(skb); + + __skb_queue_tail(skbs, skb); txq->entries[txq->q.read_ptr].skb = NULL; @@ -1411,7 +1442,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, */ if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE, "Command %s (%#x) is too large (%d bytes)\n", - get_cmd_string(trans_pcie, cmd->id), cmd->id, copy_size)) { + iwl_get_cmd_string(trans, cmd->id), + cmd->id, copy_size)) { idx = -EINVAL; goto free_dup_buf; } @@ -1501,7 +1533,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, IWL_DEBUG_HC(trans, "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", - get_cmd_string(trans_pcie, out_cmd->hdr.cmd), + iwl_get_cmd_string(trans, cmd->id), group_id, out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); @@ -1591,16 +1623,14 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, /* * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim - * - * If an Rx buffer has an async callback associated with it the callback - * will be executed. The attached skb (if present) will only be freed - * if the callback returns 1 */ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); + u8 group_id = iwl_cmd_groupid(pkt->hdr.group_id); + u32 cmd_id; int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); int cmd_index; @@ -1626,6 +1656,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, cmd_index = get_cmd_index(&txq->q, index); cmd = txq->entries[cmd_index].cmd; meta = &txq->entries[cmd_index].meta; + cmd_id = iwl_cmd_id(cmd->hdr.cmd, group_id, 0); iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]); @@ -1638,17 +1669,20 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, meta->source->_rx_page_order = trans_pcie->rx_page_order; } + if (meta->flags & CMD_WANT_ASYNC_CALLBACK) + iwl_op_mode_async_cb(trans->op_mode, cmd); + iwl_pcie_cmdq_reclaim(trans, txq_id, index); if (!(meta->flags & CMD_ASYNC)) { if (!test_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status)) { IWL_WARN(trans, "HCMD_ACTIVE already clear for command %s\n", - get_cmd_string(trans_pcie, cmd->hdr.cmd)); + iwl_get_cmd_string(trans, cmd_id)); } clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", - get_cmd_string(trans_pcie, cmd->hdr.cmd)); + iwl_get_cmd_string(trans, cmd_id)); wake_up(&trans_pcie->wait_command_queue); } @@ -1662,7 +1696,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; /* An asynchronous command can not expect an SKB to be set. */ @@ -1673,7 +1706,7 @@ static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, if (ret < 0) { IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - get_cmd_string(trans_pcie, cmd->id), ret); + iwl_get_cmd_string(trans, cmd->id), ret); return ret; } return 0; @@ -1687,16 +1720,16 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, int ret; IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", - get_cmd_string(trans_pcie, cmd->id)); + iwl_get_cmd_string(trans, cmd->id)); if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status), "Command %s: a command is already active!\n", - get_cmd_string(trans_pcie, cmd->id))) + iwl_get_cmd_string(trans, cmd->id))) return -EIO; IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", - get_cmd_string(trans_pcie, cmd->id)); + iwl_get_cmd_string(trans, cmd->id)); cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd); if (cmd_idx < 0) { @@ -1704,7 +1737,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - get_cmd_string(trans_pcie, cmd->id), ret); + iwl_get_cmd_string(trans, cmd->id), ret); return ret; } @@ -1717,7 +1750,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, struct iwl_queue *q = &txq->q; IWL_ERR(trans, "Error sending %s: time out after %dms.\n", - get_cmd_string(trans_pcie, cmd->id), + iwl_get_cmd_string(trans, cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", @@ -1725,7 +1758,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", - get_cmd_string(trans_pcie, cmd->id)); + iwl_get_cmd_string(trans, cmd->id)); ret = -ETIMEDOUT; iwl_force_nmi(trans); @@ -1736,7 +1769,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, if (test_bit(STATUS_FW_ERROR, &trans->status)) { IWL_ERR(trans, "FW error in SYNC CMD %s\n", - get_cmd_string(trans_pcie, cmd->id)); + iwl_get_cmd_string(trans, cmd->id)); dump_stack(); ret = -EIO; goto cancel; @@ -1751,7 +1784,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) { IWL_ERR(trans, "Error: Response NULL in '%s'\n", - get_cmd_string(trans_pcie, cmd->id)); + iwl_get_cmd_string(trans, cmd->id)); ret = -EIO; goto cancel; } @@ -1794,6 +1827,305 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return iwl_pcie_send_hcmd_sync(trans, cmd); } +static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) +{ + struct iwl_queue *q = &txq->q; + u16 tb2_len; + int i; + + /* + * Set up TFD's third entry to point directly to remainder + * of skb's head, if any + */ + tb2_len = skb_headlen(skb) - hdr_len; + + if (tb2_len > 0) { + dma_addr_t tb2_phys = dma_map_single(trans->dev, + skb->data + hdr_len, + tb2_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { + iwl_pcie_tfd_unmap(trans, out_meta, + &txq->tfds[q->write_ptr]); + return -EINVAL; + } + iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); + } + + /* set up the remaining entries to point to the data */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t tb_phys; + int tb_idx; + + if (!skb_frag_size(frag)) + continue; + + tb_phys = skb_frag_dma_map(trans->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + iwl_pcie_tfd_unmap(trans, out_meta, + &txq->tfds[q->write_ptr]); + return -EINVAL; + } + tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, + skb_frag_size(frag), false); + + out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS); + } + + trace_iwlwifi_dev_tx(trans->dev, skb, + &txq->tfds[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, + skb->data + hdr_len, tb2_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, + hdr_len, skb->len - hdr_len); + return 0; +} + +#ifdef CONFIG_INET +static struct iwl_tso_hdr_page * +get_page_hdr(struct iwl_trans *trans, size_t len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->tso_hdr_page); + + if (!p->page) + goto alloc; + + /* enough room on this page */ + if (p->pos + len < (u8 *)page_address(p->page) + PAGE_SIZE) + return p; + + /* We don't have enough room on this page, get a new one. */ + __free_page(p->page); + +alloc: + p->page = alloc_page(GFP_ATOMIC); + if (!p->page) + return NULL; + p->pos = page_address(p->page); + return p; +} + +static void iwl_compute_pseudo_hdr_csum(void *iph, struct tcphdr *tcph, + bool ipv6, unsigned int len) +{ + if (ipv6) { + struct ipv6hdr *iphv6 = iph; + + tcph->check = ~csum_ipv6_magic(&iphv6->saddr, &iphv6->daddr, + len + tcph->doff * 4, + IPPROTO_TCP, 0); + } else { + struct iphdr *iphv4 = iph; + + ip_send_check(iphv4); + tcph->check = ~csum_tcpudp_magic(iphv4->saddr, iphv4->daddr, + len + tcph->doff * 4, + IPPROTO_TCP, 0); + } +} + +static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; + unsigned int mss = skb_shinfo(skb)->gso_size; + struct iwl_queue *q = &txq->q; + u16 length, iv_len, amsdu_pad; + u8 *start_hdr; + struct iwl_tso_hdr_page *hdr_page; + int ret; + struct tso_t tso; + + /* if the packet is protected, then it must be CCMP or GCMP */ + BUILD_BUG_ON(IEEE80211_CCMP_HDR_LEN != IEEE80211_GCMP_HDR_LEN); + iv_len = ieee80211_has_protected(hdr->frame_control) ? + IEEE80211_CCMP_HDR_LEN : 0; + + trace_iwlwifi_dev_tx(trans->dev, skb, + &txq->tfds[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, + NULL, 0); + + ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); + snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); + total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; + amsdu_pad = 0; + + /* total amount of header we may need for this A-MSDU */ + hdr_room = DIV_ROUND_UP(total_len, mss) * + (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; + + /* Our device supports 9 segments at most, it will fit in 1 page */ + hdr_page = get_page_hdr(trans, hdr_room); + if (!hdr_page) + return -ENOMEM; + + get_page(hdr_page->page); + start_hdr = hdr_page->pos; + info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = hdr_page->page; + memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); + hdr_page->pos += iv_len; + + /* + * Pull the ieee80211 header + IV to be able to use TSO core, + * we will restore it for the tx_status flow. + */ + skb_pull(skb, hdr_len + iv_len); + + tso_start(skb, &tso); + + while (total_len) { + /* this is the data left for this subframe */ + unsigned int data_left = + min_t(unsigned int, mss, total_len); + struct sk_buff *csum_skb = NULL; + unsigned int hdr_tb_len; + dma_addr_t hdr_tb_phys; + struct tcphdr *tcph; + u8 *iph; + + total_len -= data_left; + + memset(hdr_page->pos, 0, amsdu_pad); + hdr_page->pos += amsdu_pad; + amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + + data_left)) & 0x3; + ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); + hdr_page->pos += ETH_ALEN; + ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); + hdr_page->pos += ETH_ALEN; + + length = snap_ip_tcp_hdrlen + data_left; + *((__be16 *)hdr_page->pos) = cpu_to_be16(length); + hdr_page->pos += sizeof(length); + + /* + * This will copy the SNAP as well which will be considered + * as MAC header. + */ + tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); + iph = hdr_page->pos + 8; + tcph = (void *)(iph + ip_hdrlen); + + /* For testing on current hardware only */ + if (trans_pcie->sw_csum_tx) { + csum_skb = alloc_skb(data_left + tcp_hdrlen(skb), + GFP_ATOMIC); + if (!csum_skb) { + ret = -ENOMEM; + goto out_unmap; + } + + iwl_compute_pseudo_hdr_csum(iph, tcph, + skb->protocol == + htons(ETH_P_IPV6), + data_left); + + memcpy(skb_put(csum_skb, tcp_hdrlen(skb)), + tcph, tcp_hdrlen(skb)); + skb_set_transport_header(csum_skb, 0); + csum_skb->csum_start = + (unsigned char *)tcp_hdr(csum_skb) - + csum_skb->head; + } + + hdr_page->pos += snap_ip_tcp_hdrlen; + + hdr_tb_len = hdr_page->pos - start_hdr; + hdr_tb_phys = dma_map_single(trans->dev, start_hdr, + hdr_tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) { + dev_kfree_skb(csum_skb); + ret = -EINVAL; + goto out_unmap; + } + iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys, + hdr_tb_len, false); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, + hdr_tb_len); + + /* prepare the start_hdr for the next subframe */ + start_hdr = hdr_page->pos; + + /* put the payload */ + while (data_left) { + unsigned int size = min_t(unsigned int, tso.size, + data_left); + dma_addr_t tb_phys; + + if (trans_pcie->sw_csum_tx) + memcpy(skb_put(csum_skb, size), tso.data, size); + + tb_phys = dma_map_single(trans->dev, tso.data, + size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + dev_kfree_skb(csum_skb); + ret = -EINVAL; + goto out_unmap; + } + + iwl_pcie_txq_build_tfd(trans, txq, tb_phys, + size, false); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data, + size); + + data_left -= size; + tso_build_data(skb, &tso, size); + } + + /* For testing on early hardware only */ + if (trans_pcie->sw_csum_tx) { + __wsum csum; + + csum = skb_checksum(csum_skb, + skb_checksum_start_offset(csum_skb), + csum_skb->len - + skb_checksum_start_offset(csum_skb), + 0); + dev_kfree_skb(csum_skb); + dma_sync_single_for_cpu(trans->dev, hdr_tb_phys, + hdr_tb_len, DMA_TO_DEVICE); + tcph->check = csum_fold(csum); + dma_sync_single_for_device(trans->dev, hdr_tb_phys, + hdr_tb_len, DMA_TO_DEVICE); + } + } + + /* re -add the WiFi header and IV */ + skb_push(skb, hdr_len + iv_len); + + return 0; + +out_unmap: + iwl_pcie_tfd_unmap(trans, out_meta, &txq->tfds[q->write_ptr]); + return ret; +} +#else /* CONFIG_INET */ +static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) +{ + /* No A-MSDU without CONFIG_INET */ + WARN_ON(1); + + return -1; +} +#endif /* CONFIG_INET */ + int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { @@ -1805,12 +2137,11 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_queue *q; dma_addr_t tb0_phys, tb1_phys, scratch_phys; void *tb1_addr; - u16 len, tb1_len, tb2_len; + u16 len, tb1_len; bool wait_write_ptr; __le16 fc; u8 hdr_len; u16 wifi_seq; - int i; txq = &trans_pcie->txq[txq_id]; q = &txq->q; @@ -1819,6 +2150,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, "TX on unused queue %d\n", txq_id)) return -EINVAL; + if (unlikely(trans_pcie->sw_csum_tx && + skb->ip_summed == CHECKSUM_PARTIAL)) { + int offs = skb_checksum_start_offset(skb); + int csum_offs = offs + skb->csum_offset; + __wsum csum; + + if (skb_ensure_writable(skb, csum_offs + sizeof(__sum16))) + return -1; + + csum = skb_checksum(skb, offs, skb->len - offs, 0); + *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum); + } + if (skb_is_nonlinear(skb) && skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS && __skb_linearize(skb)) @@ -1893,57 +2237,20 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, goto out_err; iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false); - /* - * Set up TFD's third entry to point directly to remainder - * of skb's head, if any - */ - tb2_len = skb_headlen(skb) - hdr_len; - if (tb2_len > 0) { - dma_addr_t tb2_phys = dma_map_single(trans->dev, - skb->data + hdr_len, - tb2_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { - iwl_pcie_tfd_unmap(trans, out_meta, - &txq->tfds[q->write_ptr]); + if (ieee80211_is_data_qos(fc) && + (*ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_A_MSDU_PRESENT)) { + if (unlikely(iwl_fill_data_tbs_amsdu(trans, skb, txq, hdr_len, + out_meta, dev_cmd, + tb1_len))) goto out_err; - } - iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); - } - - /* set up the remaining entries to point to the data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - dma_addr_t tb_phys; - int tb_idx; - - if (!skb_frag_size(frag)) - continue; - - tb_phys = skb_frag_dma_map(trans->dev, frag, 0, - skb_frag_size(frag), DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { - iwl_pcie_tfd_unmap(trans, out_meta, - &txq->tfds[q->write_ptr]); - goto out_err; - } - tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, - skb_frag_size(frag), false); - - out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS); + } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, + out_meta, dev_cmd, tb1_len))) { + goto out_err; } /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); - trace_iwlwifi_dev_tx(trans->dev, skb, - &txq->tfds[txq->q.write_ptr], - sizeof(struct iwl_tfd), - &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, - skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, - hdr_len, skb->len - hdr_len); - wait_write_ptr = ieee80211_has_morefrags(fc); /* start timer if queue currently empty */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c index 50033aa7c7d5..74f63b7bf7b4 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_cs.c +++ b/drivers/net/wireless/intersil/hostap/hostap_cs.c @@ -473,7 +473,7 @@ static int prism2_config(struct pcmcia_device *link) struct net_device *dev; struct hostap_interface *iface; local_info_t *local; - int ret = 1; + int ret; struct hostap_cs_priv *hw_priv; unsigned long flags; @@ -502,8 +502,10 @@ static int prism2_config(struct pcmcia_device *link) /* Need to allocate net_device before requesting IRQ handler */ dev = prism2_init_local_data(&prism2_pccard_funcs, 0, &link->dev); - if (dev == NULL) + if (!dev) { + ret = -ENOMEM; goto failed; + } link->priv = dev; iface = netdev_priv(dev); diff --git a/drivers/net/wireless/intersil/prism54/isl_ioctl.c b/drivers/net/wireless/intersil/prism54/isl_ioctl.c index ecbb0546cf3e..48e8a978a832 100644 --- a/drivers/net/wireless/intersil/prism54/isl_ioctl.c +++ b/drivers/net/wireless/intersil/prism54/isl_ioctl.c @@ -2036,7 +2036,7 @@ format_event(islpci_private *priv, char *dest, const char *str, mlme->address, (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); - BUG_ON(n > IW_CUSTOM_MAX); + WARN_ON(n >= IW_CUSTOM_MAX); *length = n; } diff --git a/drivers/net/wireless/intersil/prism54/islpci_dev.c b/drivers/net/wireless/intersil/prism54/islpci_dev.c index 931cf440ff18..84a42012aeae 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_dev.c +++ b/drivers/net/wireless/intersil/prism54/islpci_dev.c @@ -707,7 +707,9 @@ islpci_alloc_memory(islpci_private *priv) pci_map_single(priv->pdev, (void *) skb->data, MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); - if (!priv->pci_map_rx_address[counter]) { + if (pci_dma_mapping_error(priv->pdev, + priv->pci_map_rx_address[counter])) { + priv->pci_map_rx_address[counter] = 0; /* error mapping the buffer to device accessible memory address */ printk(KERN_ERR "failed to map skb DMA'able\n"); diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index 674658f2e6ef..d83f6332019e 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -190,7 +190,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) pci_map_address = pci_map_single(priv->pdev, (void *) skb->data, skb->len, PCI_DMA_TODEVICE); - if (unlikely(pci_map_address == 0)) { + if (pci_dma_mapping_error(priv->pdev, pci_map_address)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); goto drop_free; @@ -448,7 +448,8 @@ islpci_eth_receive(islpci_private *priv) pci_map_single(priv->pdev, (void *) skb->data, MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); - if (unlikely(!priv->pci_map_rx_address[index])) { + if (pci_dma_mapping_error(priv->pdev, + priv->pci_map_rx_address[index])) { /* error mapping the buffer to device accessible memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.c b/drivers/net/wireless/intersil/prism54/islpci_mgt.c index 0de14dfa68cc..53d7a1705e8e 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.c +++ b/drivers/net/wireless/intersil/prism54/islpci_mgt.c @@ -130,7 +130,7 @@ islpci_mgmt_rx_fill(struct net_device *ndev) buf->pci_addr = pci_map_single(priv->pdev, buf->mem, MGMT_FRAME_SIZE, PCI_DMA_FROMDEVICE); - if (!buf->pci_addr) { + if (pci_dma_mapping_error(priv->pdev, buf->pci_addr)) { printk(KERN_WARNING "Failed to make memory DMA'able.\n"); return -ENOMEM; @@ -217,7 +217,7 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, err = -ENOMEM; buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, PCI_DMA_TODEVICE); - if (!buf.pci_addr) { + if (pci_dma_mapping_error(priv->pdev, buf.pci_addr)) { printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", ndev->name); goto error_free; diff --git a/drivers/net/wireless/intersil/prism54/oid_mgt.c b/drivers/net/wireless/intersil/prism54/oid_mgt.c index 3a8d2dbcfecd..6528ed5b9b1d 100644 --- a/drivers/net/wireless/intersil/prism54/oid_mgt.c +++ b/drivers/net/wireless/intersil/prism54/oid_mgt.c @@ -424,7 +424,7 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) void *cache, *_data = data; u32 oid; - BUG_ON(OID_NUM_LAST <= n); + BUG_ON(n >= OID_NUM_LAST); BUG_ON(extra > isl_oid[n].range); if (!priv->mib) @@ -485,7 +485,7 @@ mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len int dlen; u32 oid; - BUG_ON(OID_NUM_LAST <= n); + BUG_ON(n >= OID_NUM_LAST); dlen = isl_oid[n].size; oid = isl_oid[n].oid; @@ -524,7 +524,7 @@ mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, void *cache, *_res = NULL; u32 oid; - BUG_ON(OID_NUM_LAST <= n); + BUG_ON(n >= OID_NUM_LAST); BUG_ON(extra > isl_oid[n].range); res->ptr = NULL; @@ -626,7 +626,7 @@ mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) void mgt_set(islpci_private *priv, enum oid_num_t n, void *data) { - BUG_ON(OID_NUM_LAST <= n); + BUG_ON(n >= OID_NUM_LAST); BUG_ON(priv->mib[n] == NULL); memcpy(priv->mib[n], data, isl_oid[n].size); @@ -636,7 +636,7 @@ mgt_set(islpci_private *priv, enum oid_num_t n, void *data) void mgt_get(islpci_private *priv, enum oid_num_t n, void *res) { - BUG_ON(OID_NUM_LAST <= n); + BUG_ON(n >= OID_NUM_LAST); BUG_ON(priv->mib[n] == NULL); BUG_ON(res == NULL); diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index aa498e0d2204..1efef3b8273d 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -203,8 +203,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_aggr->priority = skb_src->priority; skb_aggr->tstamp = skb_src->tstamp; - skb_aggr->tstamp = ktime_get_real(); - do { /* Check if AMSDU can accommodate this MSDU */ if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN)) diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index b3970a8c9e48..09578c6cde59 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -48,7 +48,17 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, priv->wdev.iftype, 0, false); while (!skb_queue_empty(&list)) { + struct rx_packet_hdr *rx_hdr; + rx_skb = __skb_dequeue(&list); + rx_hdr = (struct rx_packet_hdr *)rx_skb->data; + if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && + ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) { + mwifiex_process_tdls_action_frame(priv, + (u8 *)rx_hdr, + skb->len); + } + ret = mwifiex_recv_packet(priv, rx_skb); if (ret == -1) mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 4073116e6e9f..e7adef72c05f 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -26,12 +26,10 @@ module_param(reg_alpha2, charp, 0); static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { { - .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | + .max = 3, .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_CLIENT), - }, - { - .max = 1, .types = BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_AP), }, }; @@ -827,18 +825,26 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, switch (type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + priv->bss_num = mwifiex_get_unused_bss_num(adapter, + MWIFIEX_BSS_TYPE_STA); priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: + priv->bss_num = mwifiex_get_unused_bss_num(adapter, + MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_P2P_GO: + priv->bss_num = mwifiex_get_unused_bss_num(adapter, + MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_UAP; priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_AP: + priv->bss_num = mwifiex_get_unused_bss_num(adapter, + MWIFIEX_BSS_TYPE_UAP); priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; break; @@ -1533,6 +1539,7 @@ static const u32 mwifiex_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_SMS4, WLAN_CIPHER_SUITE_AES_CMAC, }; @@ -1701,6 +1708,11 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 deauth_mac[ETH_ALEN]; unsigned long flags; + if (!priv->bss_started && priv->wdev.cac_started) { + mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__); + mwifiex_abort_cac(priv); + } + if (list_empty(&priv->sta_list) || !priv->bss_started) return 0; @@ -2608,7 +2620,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - priv = mwifiex_get_unused_priv(adapter); + priv = mwifiex_get_unused_priv_by_bss_type( + adapter, MWIFIEX_BSS_TYPE_STA); if (!priv) { mwifiex_dbg(adapter, ERROR, "could not get free private struct\n"); @@ -2627,7 +2640,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; priv->bss_priority = 0; priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_num = adapter->curr_iface_comb.sta_intf; break; case NL80211_IFTYPE_AP: @@ -2638,7 +2650,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - priv = mwifiex_get_unused_priv(adapter); + priv = mwifiex_get_unused_priv_by_bss_type( + adapter, MWIFIEX_BSS_TYPE_UAP); if (!priv) { mwifiex_dbg(adapter, ERROR, "could not get free private struct\n"); @@ -2653,7 +2666,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_priority = 0; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; priv->bss_started = 0; - priv->bss_num = adapter->curr_iface_comb.uap_intf; priv->bss_mode = type; break; @@ -2665,7 +2677,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - priv = mwifiex_get_unused_priv(adapter); + priv = mwifiex_get_unused_priv_by_bss_type( + adapter, MWIFIEX_BSS_TYPE_P2P); if (!priv) { mwifiex_dbg(adapter, ERROR, "could not get free private struct\n"); @@ -2689,7 +2702,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_priority = MWIFIEX_BSS_ROLE_STA; priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_started = 0; - priv->bss_num = adapter->curr_iface_comb.p2p_intf; if (mwifiex_cfg80211_init_p2p_client(priv)) { memset(&priv->wdev, 0, sizeof(priv->wdev)); @@ -2914,6 +2926,12 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, dont_care_byte = true; } + /* wildcard bytes record as the offset + * before the valid byte + */ + if (!valid_byte_cnt && !dont_care_byte) + pat->pkt_offset++; + if (valid_byte_cnt > max_byte_seq) return false; } @@ -3141,8 +3159,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, memset(&hs_cfg, 0, sizeof(hs_cfg)); hs_cfg.is_invoke_hostcmd = false; hs_cfg.conditions = HS_CFG_COND_MAC_EVENT; - hs_cfg.gpio = HS_CFG_GPIO_DEF; - hs_cfg.gap = HS_CFG_GAP_DEF; + hs_cfg.gpio = adapter->hs_cfg.gpio; + hs_cfg.gap = adapter->hs_cfg.gap; ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hs_cfg); if (ret) { @@ -3802,6 +3820,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->cipher_suites = mwifiex_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + if (adapter->region_code) + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | + REGULATORY_COUNTRY_IE_IGNORE; + ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | @@ -3862,11 +3884,15 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) "driver hint alpha2: %2.2s\n", reg_alpha2); regulatory_hint(wiphy, reg_alpha2); } else { - country_code = mwifiex_11d_code_2_region(adapter->region_code); - if (country_code) - mwifiex_dbg(adapter, WARN, - "ignoring F/W country code %2.2s\n", - country_code); + if (adapter->region_code == 0x00) { + mwifiex_dbg(adapter, WARN, "Ignore world regulatory domain\n"); + } else { + country_code = + mwifiex_11d_code_2_region(adapter->region_code); + if (country_code && + regulatory_hint(wiphy, country_code)) + mwifiex_dbg(priv->adapter, ERROR, "regulatory_hint() failed\n"); + } } mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, diff --git a/drivers/net/wireless/marvell/mwifiex/cfp.c b/drivers/net/wireless/marvell/mwifiex/cfp.c index 3ddb8ec676ed..09fae27140f7 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfp.c +++ b/drivers/net/wireless/marvell/mwifiex/cfp.c @@ -66,8 +66,8 @@ static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 }; -u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, - 0x32, 0x40, 0x41, 0xff }; +u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30, + 0x31, 0x32, 0x40, 0x41, 0x50 }; static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; @@ -168,7 +168,7 @@ struct region_code_mapping { static struct region_code_mapping region_code_mapping_t[] = { { 0x10, "US " }, /* US FCC */ { 0x20, "CA " }, /* IC Canada */ - { 0x30, "EU " }, /* ETSI */ + { 0x30, "FR " }, /* France */ { 0x31, "ES " }, /* Spain */ { 0x32, "FR " }, /* France */ { 0x40, "JP " }, /* Japan */ diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 45ae38e32621..cb25aa7e90db 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1637,9 +1637,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, if (adapter->region_code == region_code_index[i]) break; - /* If it's unidentified region code, use the default (USA) */ + /* If it's unidentified region code, use the default (world) */ if (i >= MWIFIEX_MAX_REGION_CODE) { - adapter->region_code = 0x10; + adapter->region_code = 0x00; mwifiex_dbg(adapter, WARN, "cmd: unknown region code, use default (USA)\n"); } diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index 9824d8dd2b44..5e5562909d9f 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -906,6 +906,34 @@ mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, return count; } +static ssize_t +mwifiex_reset_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = file->private_data; + struct mwifiex_adapter *adapter = priv->adapter; + char cmd; + bool result; + + if (copy_from_user(&cmd, ubuf, sizeof(cmd))) + return -EFAULT; + + if (strtobool(&cmd, &result)) + return -EINVAL; + + if (!result) + return -EINVAL; + + if (adapter->if_ops.card_reset) { + dev_info(adapter->dev, "Resetting per request\n"); + adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + mwifiex_cancel_all_pending_cmd(adapter); + adapter->if_ops.card_reset(adapter); + } + + return count; +} + #define MWIFIEX_DFS_ADD_FILE(name) do { \ if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ priv, &mwifiex_dfs_##name##_fops)) \ @@ -943,6 +971,7 @@ MWIFIEX_DFS_FILE_OPS(hscfg); MWIFIEX_DFS_FILE_OPS(histogram); MWIFIEX_DFS_FILE_OPS(debug_mask); MWIFIEX_DFS_FILE_OPS(timeshare_coex); +MWIFIEX_DFS_FILE_WRITE_OPS(reset); /* * This function creates the debug FS directory structure and the files. @@ -970,6 +999,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(histogram); MWIFIEX_DFS_ADD_FILE(debug_mask); MWIFIEX_DFS_ADD_FILE(timeshare_coex); + MWIFIEX_DFS_ADD_FILE(reset); } /* diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index 098e1f14dc9a..d9c15cd36f12 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -111,9 +111,9 @@ /* Rate index for OFDM 0 */ #define MWIFIEX_RATE_INDEX_OFDM0 4 -#define MWIFIEX_MAX_STA_NUM 1 -#define MWIFIEX_MAX_UAP_NUM 1 -#define MWIFIEX_MAX_P2P_NUM 1 +#define MWIFIEX_MAX_STA_NUM 3 +#define MWIFIEX_MAX_UAP_NUM 3 +#define MWIFIEX_MAX_P2P_NUM 3 #define MWIFIEX_A_BAND_START_FREQ 5000 diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 1e1e81a0a8d4..ced7af2be29a 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -537,7 +537,7 @@ enum P2P_MODES { #define EVENT_GET_BSS_TYPE(event_cause) \ (((event_cause) >> 24) & 0x00ff) -#define MWIFIEX_MAX_PATTERN_LEN 20 +#define MWIFIEX_MAX_PATTERN_LEN 40 #define MWIFIEX_MAX_OFFSET_LEN 100 #define STACK_NBYTES 100 #define TYPE_DNUM 1 @@ -1092,9 +1092,15 @@ struct host_cmd_ds_802_11_ad_hoc_start { u8 data_rate[HOSTCMD_SUPPORTED_RATES]; } __packed; -struct host_cmd_ds_802_11_ad_hoc_result { +struct host_cmd_ds_802_11_ad_hoc_start_result { u8 pad[3]; u8 bssid[ETH_ALEN]; + u8 pad2[2]; + u8 result; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_join_result { + u8 result; } __packed; struct adhoc_bss_desc { @@ -2124,7 +2130,8 @@ struct host_cmd_ds_command { struct host_cmd_ds_802_11_associate_rsp associate_rsp; struct host_cmd_ds_802_11_deauthenticate deauth; struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; - struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; + struct host_cmd_ds_802_11_ad_hoc_start_result start_result; + struct host_cmd_ds_802_11_ad_hoc_join_result join_result; struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; struct host_cmd_ds_802_11d_domain_info domain_info; struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index abf52d25b981..c488c3068abc 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -140,7 +140,7 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, - UAP_CUSTOM_IE_I, ie_list, false); + UAP_CUSTOM_IE_I, ie_list, true); return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index de74a7773fb6..6f7876ec31b7 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -95,7 +95,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | HostCmd_ACT_MAC_ETHERNETII_ENABLE; - priv->beacon_period = 100; /* beacon interval */ ; + priv->beacon_period = 100; /* beacon interval */ priv->attempted_bss_desc = NULL; memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 3cda1f956f0b..cc09a81dbf6a 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -1247,20 +1247,26 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; + struct host_cmd_ds_802_11_ad_hoc_start_result *start_result = + &resp->params.start_result; + struct host_cmd_ds_802_11_ad_hoc_join_result *join_result = + &resp->params.join_result; struct mwifiex_bssdescriptor *bss_desc; - u16 reason_code; + u16 cmd = le16_to_cpu(resp->command); + u8 result; - adhoc_result = &resp->params.adhoc_result; + if (cmd == HostCmd_CMD_802_11_AD_HOC_START) + result = start_result->result; + else + result = join_result->result; bss_desc = priv->attempted_bss_desc; /* Join result code 0 --> SUCCESS */ - reason_code = le16_to_cpu(resp->result); - if (reason_code) { + if (result) { mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n"); if (priv->media_connected) - mwifiex_reset_connect_state(priv, reason_code); + mwifiex_reset_connect_state(priv, result); memset(&priv->curr_bss_params.bss_descriptor, 0x00, sizeof(struct mwifiex_bssdescriptor)); @@ -1278,7 +1284,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, /* Update the created network descriptor with the new BSSID */ memcpy(bss_desc->mac_address, - adhoc_result->bssid, ETH_ALEN); + start_result->bssid, ETH_ALEN); priv->adhoc_state = ADHOC_STARTED; } else { diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 3959f1c97f4e..2f7f478ce04b 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -84,7 +84,7 @@ enum { #define MWIFIEX_KEY_BUFFER_SIZE 16 #define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 -#define MWIFIEX_MAX_REGION_CODE 7 +#define MWIFIEX_MAX_REGION_CODE 9 #define DEFAULT_BCN_AVG_FACTOR 8 #define DEFAULT_DATA_AVG_FACTOR 8 @@ -564,14 +564,14 @@ struct mwifiex_private { struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; u16 wep_key_curr_index; u8 wpa_ie[256]; - u8 wpa_ie_len; + u16 wpa_ie_len; u8 wpa_is_gtk_set; struct host_cmd_ds_802_11_key_material aes_key; struct host_cmd_ds_802_11_key_material_v2 aes_key_v2; u8 wapi_ie[256]; - u8 wapi_ie_len; + u16 wapi_ie_len; u8 *wps_ie; - u8 wps_ie_len; + u16 wps_ie_len; u8 wmm_required; u8 wmm_enabled; u8 wmm_qosinfo; @@ -1272,21 +1272,47 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter, return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); } +/* + * This function checks available bss_num when adding new interface or + * changing interface type. + */ +static inline u8 +mwifiex_get_unused_bss_num(struct mwifiex_adapter *adapter, u8 bss_type) +{ + u8 i, j; + int index[MWIFIEX_MAX_BSS_NUM]; + + memset(index, 0, sizeof(index)); + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]) { + if (adapter->priv[i]->bss_type == bss_type && + !(adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED)) { + index[adapter->priv[i]->bss_num] = 1; + } + } + for (j = 0; j < MWIFIEX_MAX_BSS_NUM; j++) + if (!index[j]) + return j; + return -1; +} + /* * This function returns the first available unused private structure pointer. */ static inline struct mwifiex_private * -mwifiex_get_unused_priv(struct mwifiex_adapter *adapter) +mwifiex_get_unused_priv_by_bss_type(struct mwifiex_adapter *adapter, + u8 bss_type) { - int i; + u8 i; - for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - if (adapter->priv[i]->bss_mode == - NL80211_IFTYPE_UNSPECIFIED) - break; + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED) { + adapter->priv[i]->bss_num = + mwifiex_get_unused_bss_num(adapter, bss_type); + break; } - } return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 21192b6f9c64..9703848ba9f8 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2599,6 +2599,30 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) kfree(card); } +static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) +{ + int ret; + struct pcie_service_card *card = adapter->card; + struct pci_dev *pdev = card->dev; + + if (pci_enable_msi(pdev) != 0) + pci_disable_msi(pdev); + else + card->msi_enable = 1; + + mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable); + + ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED, + "MRVL_PCIE", pdev); + if (ret) { + pr_err("request_irq failed: ret=%d\n", ret); + adapter->card = NULL; + return -1; + } + + return 0; +} + /* * This function registers the PCIE device. * @@ -2606,21 +2630,14 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { - int ret; struct pcie_service_card *card = adapter->card; struct pci_dev *pdev = card->dev; /* save adapter pointer in card */ card->adapter = adapter; - ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED, - "MRVL_PCIE", pdev); - if (ret) { - mwifiex_dbg(adapter, ERROR, - "request_irq failed: ret=%d\n", ret); - adapter->card = NULL; + if (mwifiex_pcie_request_irq(adapter)) return -1; - } adapter->dev = &pdev->dev; adapter->tx_buf_size = card->pcie.tx_buf_size; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 48e549c3b285..6fc28737b576 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -210,17 +210,17 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, .tx_rdptr = 0xC1A4, - .tx_wrptr = 0xC1A8, - .rx_rdptr = 0xC1A8, + .tx_wrptr = 0xC174, + .rx_rdptr = 0xC174, .rx_wrptr = 0xC1A4, .evt_rdptr = PCIE_SCRATCH_10_REG, .evt_wrptr = PCIE_SCRATCH_11_REG, .drv_rdy = PCIE_SCRATCH_12_REG, .tx_start_ptr = 16, .tx_mask = 0x0FFF0000, - .tx_wrap_mask = 0x01FF0000, + .tx_wrap_mask = 0x1FFF0000, .rx_mask = 0x00000FFF, - .rx_wrap_mask = 0x000001FF, + .rx_wrap_mask = 0x00001FFF, .tx_rollover_ind = BIT(28), .rx_rollover_ind = BIT(12), .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, @@ -326,6 +326,7 @@ struct pcie_service_card { dma_addr_t sleep_cookie_pbase; void __iomem *pci_mmap; void __iomem *pci_mmap1; + int msi_enable; }; static inline int @@ -342,6 +343,7 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) return 1; break; case PCIE_DEVICE_ID_MARVELL_88W8897: + case PCIE_DEVICE_ID_MARVELL_88W8997: if (((card->txbd_wrptr & reg->tx_mask) == (rdptr & reg->tx_mask)) && ((card->txbd_wrptr & reg->tx_rollover_ind) == diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index a6c8a4f7bfe9..6a4fc5d183cf 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -272,7 +272,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, priv->scan_block = false; if (bss) { - mwifiex_process_country_ie(priv, bss); + if (adapter->region_code == 0x00) + mwifiex_process_country_ie(priv, bss); /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), @@ -758,7 +759,7 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, return -1; } memcpy(priv->wpa_ie, ie_data_ptr, ie_len); - priv->wpa_ie_len = (u8) ie_len; + priv->wpa_ie_len = ie_len; mwifiex_dbg(priv->adapter, CMD, "cmd: Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len, priv->wpa_ie[0]); @@ -923,9 +924,8 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, if (encrypt_key->key_disable) { memset(&priv->wep_key[index], 0, sizeof(struct mwifiex_wep_key)); - if (wep_key->key_length) - goto done; - } + goto done; + } if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) enc_key = encrypt_key; @@ -1293,6 +1293,8 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, struct ieee_types_vendor_header *pvendor_ie; const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + u16 unparsed_len = ie_len; + int find_wpa_ie = 0; /* If the passed length is zero, reset the buffer */ if (!ie_len) { @@ -1304,40 +1306,69 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, return -1; } pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; - /* Test to see if it is a WPA IE, if not, then it is a gen IE */ - if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) && - (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) || - (pvendor_ie->element_id == WLAN_EID_RSN)) { - /* IE is a WPA/WPA2 IE so call set_wpa function */ - ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); - priv->wps.session_enable = false; + while (pvendor_ie) { + if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) { + /* Test to see if it is a WPA IE, if not, then it is a + * gen IE + */ + if (!memcmp(pvendor_ie->oui, wpa_oui, + sizeof(wpa_oui))) { + find_wpa_ie = 1; + break; + } - return ret; - } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { + /* Test to see if it is a WPS IE, if so, enable + * wps session flag + */ + if (!memcmp(pvendor_ie->oui, wps_oui, + sizeof(wps_oui))) { + priv->wps.session_enable = true; + mwifiex_dbg(priv->adapter, MSG, + "info: WPS Session Enabled.\n"); + ret = mwifiex_set_wps_ie(priv, + (u8 *)pvendor_ie, + unparsed_len); + } + } + + if (pvendor_ie->element_id == WLAN_EID_RSN) { + find_wpa_ie = 1; + break; + } + + if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { /* IE is a WAPI IE so call set_wapi function */ - ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); + ret = mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie, + unparsed_len); + return ret; + } + unparsed_len -= (pvendor_ie->len + + sizeof(struct ieee_types_header)); + + if (unparsed_len <= sizeof(struct ieee_types_header)) + pvendor_ie = NULL; + else + pvendor_ie = (struct ieee_types_vendor_header *) + (((u8 *)pvendor_ie) + pvendor_ie->len + + sizeof(struct ieee_types_header)); + } + + if (find_wpa_ie) { + /* IE is a WPA/WPA2 IE so call set_wpa function */ + ret = mwifiex_set_wpa_ie_helper(priv, (u8 *)pvendor_ie, + unparsed_len); + priv->wps.session_enable = false; return ret; } + /* * Verify that the passed length is not larger than the * available space remaining in the buffer */ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { - /* Test to see if it is a WPS IE, if so, enable - * wps session flag - */ - pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; - if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) && - (!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) { - priv->wps.session_enable = true; - mwifiex_dbg(priv->adapter, INFO, - "info: WPS Session Enabled.\n"); - ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len); - } - /* Append the passed data to the end of the genIeBuffer */ memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c index d4d4cb1ce95b..00fcbda09349 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c @@ -215,7 +215,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, if (rx_pkt_type == PKT_TYPE_MGMT) { ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) - mwifiex_dbg(adapter, ERROR, "Rx of mgmt packet failed"); + mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed"); dev_kfree_skb_any(skb); return ret; } diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 759a6ada5b0f..e791166d90c4 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -848,9 +848,9 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg, false)) { + UAP_BSS_PARAMS_I, bss_cfg, true)) { mwifiex_dbg(priv->adapter, ERROR, - "Failed to set the SSID\n"); + "Failed to set AP configuration\n"); return -1; } @@ -865,7 +865,7 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, } if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, NULL, false)) { + HostCmd_ACT_GEN_SET, 0, NULL, true)) { mwifiex_dbg(priv->adapter, ERROR, "Failed to start the BSS\n"); return -1; diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index 74d5d7238633..52f7981a8afc 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -310,8 +310,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, if (rx_pkt_type == PKT_TYPE_MGMT) { ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) - mwifiex_dbg(adapter, ERROR, - "Rx of mgmt packet failed"); + mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed"); dev_kfree_skb_any(skb); return ret; } diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index f46c9d7f6528..7f471bff435c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -801,7 +801,9 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) hw_queue); if (rx_remained_cnt == 0) return; - + buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[ + rtlpci->rx_ring[rxring_idx].idx]; + pdesc = (struct rtl_rx_desc *)skb->data; } else { /* rx descriptor */ pdesc = &rtlpci->rx_ring[rxring_idx].desc[ rtlpci->rx_ring[rxring_idx].idx]; @@ -824,13 +826,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) goto no_new; - if (rtlpriv->use_new_trx_flow) { - buffer_desc = - &rtlpci->rx_ring[rxring_idx].buffer_desc - [rtlpci->rx_ring[rxring_idx].idx]; - /*means rx wifi info*/ - pdesc = (struct rtl_rx_desc *)skb->data; - } memset(&rx_status , 0 , sizeof(rx_status)); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, (u8 *)pdesc, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 11344121c55e..47e32cb0ec1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -88,8 +88,6 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) u8 tid; rtl8188ee_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; rtlpriv->dm.disable_framebursting = 0; @@ -138,6 +136,11 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); if (!rtlpriv->psc.inactiveps) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index de6cb6c3a48c..4780bdc63b2b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -139,6 +139,8 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; if (!rtlpriv->psc.inactiveps) pr_info("rtl8192ce: Power Save off (module option)\n"); if (!rtlpriv->psc.fwctrl_lps) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index fd4a5353d216..7c6f7f0d18c6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -65,6 +65,8 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; /* for firmware buf */ rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index b19d0398215f..c6e09a19de1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -376,8 +376,8 @@ module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); -MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); -MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index e1fd27c888bf..31baca41ac2f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -187,6 +187,8 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; if (!rtlpriv->psc.inactiveps) pr_info("Power Save off (module option)\n"); if (!rtlpriv->psc.fwctrl_lps) @@ -425,8 +427,8 @@ module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); -MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); -MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 3859b3e3d158..ff49a8c0ff61 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -150,6 +150,11 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; @@ -267,6 +272,8 @@ static struct rtl_mod_params rtl8723e_mod_params = { .swctrl_lps = false, .fwctrl_lps = true, .debug = DBG_EMERG, + .msi_support = false, + .disable_watchdog = false, }; static struct rtl_hal_cfg rtl8723e_hal_cfg = { @@ -383,12 +390,14 @@ module_param_named(debug, rtl8723e_mod_params.debug, int, 0444); module_param_named(ips, rtl8723e_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl8723e_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723e_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8723e_mod_params.msi_support, bool, 0444); module_param_named(disable_watchdog, rtl8723e_mod_params.disable_watchdog, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index d091f1d5f91e..a78eaeda0008 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -93,7 +93,6 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtl8723be_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); rtlpriv->dm.dm_initialgain_enable = 1; @@ -151,6 +150,10 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; @@ -267,6 +270,9 @@ static struct rtl_mod_params rtl8723be_mod_params = { .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, + .msi_support = false, + .disable_watchdog = false, + .debug = DBG_EMERG, }; static struct rtl_hal_cfg rtl8723be_hal_cfg = { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 142bdff4ed60..4159f9b14db6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -95,8 +95,6 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); rtl8821ae_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear; rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); rtlpriv->dm.dm_initialgain_enable = 1; @@ -168,12 +166,15 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpci->msi_support = rtlpriv->cfg->mod_params->int_clear; + rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; rtlpriv->psc.reg_max_lps_awakeintvl = 5; - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 2721cf89fb16..aac1ed3f7bb4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -531,6 +531,8 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, ieee80211_rx(hw, skb); else dev_kfree_skb_any(skb); + } else { + dev_kfree_skb_any(skb); } } diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 8d110fd9eba1..e43b59d5b53b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1023,7 +1023,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) return -ENOMEM; } - selected_rates = kmalloc(2 * RSI_TBL_SZ, GFP_KERNEL); + selected_rates = kzalloc(2 * RSI_TBL_SZ, GFP_KERNEL); if (!selected_rates) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of mem\n", __func__); @@ -1032,7 +1032,6 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) } memset(skb->data, 0, sizeof(struct rsi_auto_rate)); - memset(selected_rates, 0, 2 * RSI_TBL_SZ); auto_rate = (struct rsi_auto_rate *)skb->data; @@ -1227,7 +1226,7 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event) mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); mgmt_frame->desc_word[1] = cpu_to_le16(BLOCK_HW_QUEUE); - if (block_event == true) { + if (block_event) { rsi_dbg(INFO_ZONE, "blocking the data qs\n"); mgmt_frame->desc_word[4] = cpu_to_le16(0xf); } else { diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 95a7fdb3cc1c..06321c799c90 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -873,12 +873,6 @@ int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) else val32 = 0; /* disabled */ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { - /* device is down, can _not_ set threshold */ - ret = -ENODEV; - goto out; - } - if (priv->rts_threshold == value) goto out; diff --git a/drivers/net/wireless/ti/wl12xx/conf.h b/drivers/net/wireless/ti/wl12xx/conf.h index 75e29897a0f5..a606ba9ef041 100644 --- a/drivers/net/wireless/ti/wl12xx/conf.h +++ b/drivers/net/wireless/ti/wl12xx/conf.h @@ -47,4 +47,237 @@ struct wl12xx_priv_conf { struct conf_memory_settings mem_wl127x; }; +enum wl12xx_sg_params { + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT master basic rate + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_BT_MASTER_MIN_BR = 0, + WL12XX_CONF_SG_ACL_BT_MASTER_MAX_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave basic rate + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_BR, + WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT master EDR + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_BT_MASTER_MIN_EDR, + WL12XX_CONF_SG_ACL_BT_MASTER_MAX_EDR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_EDR, + WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_EDR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave BR + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_BR, + WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_BR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave EDR + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_EDR, + WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_EDR, + + /* TODO: explain these values */ + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, + WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, + + WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, + WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, + WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_BR, + WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, + WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, + WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, + + /* + * Compensation percentage of probe requests when scan initiated + * during BT voice/ACL link. + * + * Range: 0 - 255 (%) + */ + WL12XX_CONF_SG_AUTO_SCAN_PROBE_REQ, + + /* + * Compensation percentage of probe requests when active scan initiated + * during BT voice + * + * Range: 0 - 255 (%) + */ + WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, + + /* + * Compensation percentage of WLAN active scan window if initiated + * during BT A2DP + * + * Range: 0 - 1000 (%) + */ + WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP BR + * + * Range: 0 - 1000 (%) + */ + WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_BR, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP EDR + * + * Range: 0 - 1000 (%) + */ + WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_EDR, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT voice + * + * Range: 0 - 1000 (%) + */ + WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_HV3, + + /* TODO: explain these values */ + WL12XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, + WL12XX_CONF_SG_BCN_HV3_COLL_THR_IN_PASSIVE_SCAN, + WL12XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN, + + /* + * Defines whether the SG will force WLAN host to enter/exit PSM + * + * Range: 1 - SG can force, 0 - host handles PSM + */ + WL12XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO, + + /* + * Defines antenna configuration (single/dual antenna) + * + * Range: 0 - single antenna, 1 - dual antenna + */ + WL12XX_CONF_SG_ANTENNA_CONFIGURATION, + + /* + * The threshold (percent) of max consecutive beacon misses before + * increasing priority of beacon reception. + * + * Range: 0 - 100 (%) + */ + WL12XX_CONF_SG_BEACON_MISS_PERCENT, + + /* + * Protection time of the DHCP procedure. + * + * Range: 0 - 100000 (ms) + */ + WL12XX_CONF_SG_DHCP_TIME, + + /* + * RX guard time before the beginning of a new BT voice frame during + * which no new WLAN trigger frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + WL12XX_CONF_SG_RXT, + + /* + * TX guard time before the beginning of a new BT voice frame during + * which no new WLAN frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + WL12XX_CONF_SG_TXT, + + /* + * Enable adaptive RXT/TXT algorithm. If disabled, the host values + * will be utilized. + * + * Range: 0 - disable, 1 - enable + */ + WL12XX_CONF_SG_ADAPTIVE_RXT_TXT, + + /* TODO: explain this value */ + WL12XX_CONF_SG_GENERAL_USAGE_BIT_MAP, + + /* + * Number of consecutive BT voice frames not interrupted by WLAN + * + * Range: 0 - 100 + */ + WL12XX_CONF_SG_HV3_MAX_SERVED, + + /* + * The used WLAN legacy service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_PS_POLL_TIMEOUT, + + /* + * The used WLAN UPSD service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + WL12XX_CONF_SG_UPSD_TIMEOUT, + + WL12XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD, + WL12XX_CONF_SG_STA_RX_WINDOW_AFTER_DTIM, + WL12XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME, + + /* AP params */ + WL12XX_CONF_AP_BEACON_MISS_TX, + WL12XX_CONF_AP_RX_WINDOW_AFTER_BEACON, + WL12XX_CONF_AP_BEACON_WINDOW_INTERVAL, + WL12XX_CONF_AP_CONNECTION_PROTECTION_TIME, + WL12XX_CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, + WL12XX_CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, + + /* CTS Diluting params */ + WL12XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, + WL12XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, + + WL12XX_CONF_SG_TEMP_PARAM_1, + WL12XX_CONF_SG_TEMP_PARAM_2, + WL12XX_CONF_SG_TEMP_PARAM_3, + WL12XX_CONF_SG_TEMP_PARAM_4, + WL12XX_CONF_SG_TEMP_PARAM_5, + WL12XX_CONF_SG_TEMP_PARAM_6, + WL12XX_CONF_SG_TEMP_PARAM_7, + WL12XX_CONF_SG_TEMP_PARAM_8, + WL12XX_CONF_SG_TEMP_PARAM_9, + WL12XX_CONF_SG_TEMP_PARAM_10, + + WL12XX_CONF_SG_PARAMS_MAX, + WL12XX_CONF_SG_PARAMS_ALL = 0xff +}; + #endif /* __WL12XX_CONF_H__ */ diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index af0fe2e17151..a0d6cccc56f3 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -39,6 +39,7 @@ #include "scan.h" #include "event.h" #include "debugfs.h" +#include "conf.h" static char *fref_param; static char *tcxo_param; @@ -46,69 +47,69 @@ static char *tcxo_param; static struct wlcore_conf wl12xx_conf = { .sg = { .params = { - [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, - [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, - [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, - [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, - [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, - [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, - [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, - [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, - [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, - [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, + [WL12XX_CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, + [WL12XX_CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, + [WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, + [WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, + [WL12XX_CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, + [WL12XX_CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, + [WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, + [WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, + [WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, + [WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, + [WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, + [WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, + [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, + [WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, + [WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, + [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, + [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, + [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, + [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, /* active scan params */ - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + [WL12XX_CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, /* passive scan params */ - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_BR] = 800, + [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_EDR] = 200, + [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_HV3] = 200, /* passive scan in dual antenna params */ - [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, - [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, - [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, + [WL12XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, + [WL12XX_CONF_SG_BCN_HV3_COLL_THR_IN_PASSIVE_SCAN] = 0, + [WL12XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN] = 0, /* general params */ - [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, - [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, - [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, + [WL12XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, + [WL12XX_CONF_SG_ANTENNA_CONFIGURATION] = 0, + [WL12XX_CONF_SG_BEACON_MISS_PERCENT] = 60, + [WL12XX_CONF_SG_DHCP_TIME] = 5000, + [WL12XX_CONF_SG_RXT] = 1200, + [WL12XX_CONF_SG_TXT] = 1000, + [WL12XX_CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [WL12XX_CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, + [WL12XX_CONF_SG_HV3_MAX_SERVED] = 6, + [WL12XX_CONF_SG_PS_POLL_TIMEOUT] = 10, + [WL12XX_CONF_SG_UPSD_TIMEOUT] = 10, + [WL12XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, + [WL12XX_CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, + [WL12XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, /* AP params */ - [CONF_AP_BEACON_MISS_TX] = 3, - [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, - [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, - [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, - [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, - [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, + [WL12XX_CONF_AP_BEACON_MISS_TX] = 3, + [WL12XX_CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, + [WL12XX_CONF_AP_BEACON_WINDOW_INTERVAL] = 2, + [WL12XX_CONF_AP_CONNECTION_PROTECTION_TIME] = 0, + [WL12XX_CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, + [WL12XX_CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, /* CTS Diluting params */ - [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, - [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, + [WL12XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, + [WL12XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, }, .state = CONF_SG_PROTECTIVE, }, @@ -1809,6 +1810,7 @@ static int wl12xx_setup(struct wl1271 *wl) BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS); BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS); + BUILD_BUG_ON(WL12XX_CONF_SG_PARAMS_MAX > WLCORE_CONF_SG_PARAMS_MAX); wl->rtable = wl12xx_rtable; wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index 71f1ec448ba5..7aa880f14ccb 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h @@ -139,4 +139,94 @@ struct wl18xx_priv_conf { struct conf_ap_sleep_settings ap_sleep; } __packed; +enum wl18xx_sg_params { + WL18XX_CONF_SG_PARAM_0 = 0, + + /* Configuration Parameters */ + WL18XX_CONF_SG_ANTENNA_CONFIGURATION, + WL18XX_CONF_SG_ZIGBEE_COEX, + WL18XX_CONF_SG_TIME_SYNC, + + WL18XX_CONF_SG_PARAM_4, + WL18XX_CONF_SG_PARAM_5, + WL18XX_CONF_SG_PARAM_6, + WL18XX_CONF_SG_PARAM_7, + WL18XX_CONF_SG_PARAM_8, + WL18XX_CONF_SG_PARAM_9, + WL18XX_CONF_SG_PARAM_10, + WL18XX_CONF_SG_PARAM_11, + WL18XX_CONF_SG_PARAM_12, + WL18XX_CONF_SG_PARAM_13, + WL18XX_CONF_SG_PARAM_14, + WL18XX_CONF_SG_PARAM_15, + WL18XX_CONF_SG_PARAM_16, + WL18XX_CONF_SG_PARAM_17, + WL18XX_CONF_SG_PARAM_18, + WL18XX_CONF_SG_PARAM_19, + WL18XX_CONF_SG_PARAM_20, + WL18XX_CONF_SG_PARAM_21, + WL18XX_CONF_SG_PARAM_22, + WL18XX_CONF_SG_PARAM_23, + WL18XX_CONF_SG_PARAM_24, + WL18XX_CONF_SG_PARAM_25, + + /* Active Scan Parameters */ + WL18XX_CONF_SG_AUTO_SCAN_PROBE_REQ, + WL18XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, + + WL18XX_CONF_SG_PARAM_28, + + /* Passive Scan Parameters */ + WL18XX_CONF_SG_PARAM_29, + WL18XX_CONF_SG_PARAM_30, + WL18XX_CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, + + /* Passive Scan in Dual Antenna Parameters */ + WL18XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, + WL18XX_CONF_SG_BEACON_HV3_COLL_TH_IN_PASSIVE_SCAN, + WL18XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN, + + /* General Parameters */ + WL18XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO, + WL18XX_CONF_SG_PARAM_36, + WL18XX_CONF_SG_BEACON_MISS_PERCENT, + WL18XX_CONF_SG_PARAM_38, + WL18XX_CONF_SG_RXT, + WL18XX_CONF_SG_UNUSED, + WL18XX_CONF_SG_ADAPTIVE_RXT_TXT, + WL18XX_CONF_SG_GENERAL_USAGE_BIT_MAP, + WL18XX_CONF_SG_HV3_MAX_SERVED, + WL18XX_CONF_SG_PARAM_44, + WL18XX_CONF_SG_PARAM_45, + WL18XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD, + WL18XX_CONF_SG_GEMINI_PARAM_47, + WL18XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME, + + /* AP Parameters */ + WL18XX_CONF_SG_AP_BEACON_MISS_TX, + WL18XX_CONF_SG_PARAM_50, + WL18XX_CONF_SG_AP_BEACON_WINDOW_INTERVAL, + WL18XX_CONF_SG_AP_CONNECTION_PROTECTION_TIME, + WL18XX_CONF_SG_PARAM_53, + WL18XX_CONF_SG_PARAM_54, + + /* CTS Diluting Parameters */ + WL18XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, + WL18XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, + + WL18XX_CONF_SG_TEMP_PARAM_1, + WL18XX_CONF_SG_TEMP_PARAM_2, + WL18XX_CONF_SG_TEMP_PARAM_3, + WL18XX_CONF_SG_TEMP_PARAM_4, + WL18XX_CONF_SG_TEMP_PARAM_5, + WL18XX_CONF_SG_TEMP_PARAM_6, + WL18XX_CONF_SG_TEMP_PARAM_7, + WL18XX_CONF_SG_TEMP_PARAM_8, + WL18XX_CONF_SG_TEMP_PARAM_9, + WL18XX_CONF_SG_TEMP_PARAM_10, + + WL18XX_CONF_SG_PARAMS_MAX, + WL18XX_CONF_SG_PARAMS_ALL = 0xff +}; + #endif /* __WL18XX_CONF_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index 09c7e098f460..719907a0a2c2 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -205,6 +205,8 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) mbox->sc_ssid, mbox->sc_pwd_len, mbox->sc_pwd); + if (vector & FW_LOGGER_INDICATION) + wlcore_event_fw_logger(wl); return 0; } diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index f3d4f13379cb..070de1274694 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -41,6 +41,7 @@ enum { SMART_CONFIG_SYNC_EVENT_ID = BIT(22), SMART_CONFIG_DECODE_EVENT_ID = BIT(23), TIME_SYNC_EVENT_ID = BIT(24), + FW_LOGGER_INDICATION = BIT(25), }; enum wl18xx_radar_types { diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 50cce42089a5..1bf26cc7374e 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -177,69 +177,80 @@ enum wl18xx_hw_rates { static struct wlcore_conf wl18xx_conf = { .sg = { .params = { - [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, - [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, - [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, - [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, - [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, - [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, - [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, - [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, - [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, - [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, - /* active scan params */ - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, - /* passive scan params */ - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, - /* passive scan in dual antenna params */ - [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, - [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, - [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, - /* general params */ - [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, - [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, - [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, - /* AP params */ - [CONF_AP_BEACON_MISS_TX] = 3, - [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, - [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, - [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, - [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, - [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, - /* CTS Diluting params */ - [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, - [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, + [WL18XX_CONF_SG_PARAM_0] = 0, + /* Configuartion Parameters */ + [WL18XX_CONF_SG_ANTENNA_CONFIGURATION] = 0, + [WL18XX_CONF_SG_ZIGBEE_COEX] = 0, + [WL18XX_CONF_SG_TIME_SYNC] = 0, + [WL18XX_CONF_SG_PARAM_4] = 0, + [WL18XX_CONF_SG_PARAM_5] = 0, + [WL18XX_CONF_SG_PARAM_6] = 0, + [WL18XX_CONF_SG_PARAM_7] = 0, + [WL18XX_CONF_SG_PARAM_8] = 0, + [WL18XX_CONF_SG_PARAM_9] = 0, + [WL18XX_CONF_SG_PARAM_10] = 0, + [WL18XX_CONF_SG_PARAM_11] = 0, + [WL18XX_CONF_SG_PARAM_12] = 0, + [WL18XX_CONF_SG_PARAM_13] = 0, + [WL18XX_CONF_SG_PARAM_14] = 0, + [WL18XX_CONF_SG_PARAM_15] = 0, + [WL18XX_CONF_SG_PARAM_16] = 0, + [WL18XX_CONF_SG_PARAM_17] = 0, + [WL18XX_CONF_SG_PARAM_18] = 0, + [WL18XX_CONF_SG_PARAM_19] = 0, + [WL18XX_CONF_SG_PARAM_20] = 0, + [WL18XX_CONF_SG_PARAM_21] = 0, + [WL18XX_CONF_SG_PARAM_22] = 0, + [WL18XX_CONF_SG_PARAM_23] = 0, + [WL18XX_CONF_SG_PARAM_24] = 0, + [WL18XX_CONF_SG_PARAM_25] = 0, + /* Active Scan Parameters */ + [WL18XX_CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [WL18XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [WL18XX_CONF_SG_PARAM_28] = 0, + /* Passive Scan Parameters */ + [WL18XX_CONF_SG_PARAM_29] = 0, + [WL18XX_CONF_SG_PARAM_30] = 0, + [WL18XX_CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + /* Passive Scan in Dual Antenna Parameters */ + [WL18XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, + [WL18XX_CONF_SG_BEACON_HV3_COLL_TH_IN_PASSIVE_SCAN] = 0, + [WL18XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN] = 0, + /* General Parameters */ + [WL18XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, + [WL18XX_CONF_SG_PARAM_36] = 0, + [WL18XX_CONF_SG_BEACON_MISS_PERCENT] = 60, + [WL18XX_CONF_SG_PARAM_38] = 0, + [WL18XX_CONF_SG_RXT] = 1200, + [WL18XX_CONF_SG_UNUSED] = 0, + [WL18XX_CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [WL18XX_CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, + [WL18XX_CONF_SG_HV3_MAX_SERVED] = 6, + [WL18XX_CONF_SG_PARAM_44] = 0, + [WL18XX_CONF_SG_PARAM_45] = 0, + [WL18XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, + [WL18XX_CONF_SG_GEMINI_PARAM_47] = 0, + [WL18XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 0, + /* AP Parameters */ + [WL18XX_CONF_SG_AP_BEACON_MISS_TX] = 3, + [WL18XX_CONF_SG_PARAM_50] = 0, + [WL18XX_CONF_SG_AP_BEACON_WINDOW_INTERVAL] = 2, + [WL18XX_CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 30, + [WL18XX_CONF_SG_PARAM_53] = 0, + [WL18XX_CONF_SG_PARAM_54] = 0, + /* CTS Diluting Parameters */ + [WL18XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, + [WL18XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_1] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_2] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_3] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_4] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_5] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_6] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_7] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_8] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_9] = 0, + [WL18XX_CONF_SG_TEMP_PARAM_10] = 0, }, .state = CONF_SG_PROTECTIVE, }, @@ -461,7 +472,7 @@ static struct wlcore_conf wl18xx_conf = { }, .fwlog = { .mode = WL12XX_FWLOG_CONTINUOUS, - .mem_blocks = 2, + .mem_blocks = 0, .severity = 0, .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, .output = WL12XX_FWLOG_OUTPUT_DBG_PINS, @@ -584,7 +595,7 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { .mem = { .start = 0x00A00000, .size = 0x00012000 }, .reg = { .start = 0x00807000, .size = 0x00005000 }, .mem2 = { .start = 0x00800000, .size = 0x0000B000 }, - .mem3 = { .start = 0x00000000, .size = 0x00000000 }, + .mem3 = { .start = 0x00401594, .size = 0x00001020 }, }, [PART_DOWN] = { .mem = { .start = 0x00000000, .size = 0x00014000 }, @@ -602,7 +613,7 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { .mem = { .start = 0x00800000, .size = 0x000050FC }, .reg = { .start = 0x00B00404, .size = 0x00001000 }, .mem2 = { .start = 0x00C00000, .size = 0x00000400 }, - .mem3 = { .start = 0x00000000, .size = 0x00000000 }, + .mem3 = { .start = 0x00401594, .size = 0x00001020 }, }, [PART_PHY_INIT] = { .mem = { .start = WL18XX_PHY_INIT_MEM_ADDR, @@ -1029,7 +1040,8 @@ static int wl18xx_boot(struct wl1271 *wl) DFS_CHANNELS_CONFIG_COMPLETE_EVENT | SMART_CONFIG_SYNC_EVENT_ID | SMART_CONFIG_DECODE_EVENT_ID | - TIME_SYNC_EVENT_ID; + TIME_SYNC_EVENT_ID | + FW_LOGGER_INDICATION; wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; @@ -1895,6 +1907,7 @@ static int wl18xx_setup(struct wl1271 *wl) BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS); BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS); + BUILD_BUG_ON(WL18XX_CONF_SG_PARAMS_MAX > WLCORE_CONF_SG_PARAMS_MAX); wl->rtable = wl18xx_rtable; wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS; diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index f28fa3b5029d..26cc23f32241 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -534,9 +534,9 @@ int wl12xx_acx_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_PARAMS_MAX; i++) + for (i = 0; i < WLCORE_CONF_SG_PARAMS_MAX; i++) param->params[i] = cpu_to_le32(c->params[i]); - param->param_idx = CONF_SG_PARAMS_ALL; + param->param_idx = WLCORE_CONF_SG_PARAMS_ALL; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index 954d57ec98f4..0d61fae88dcb 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h @@ -300,7 +300,7 @@ struct acx_bt_wlan_coex { struct acx_bt_wlan_coex_param { struct acx_header header; - __le32 params[CONF_SG_PARAMS_MAX]; + __le32 params[WLCORE_CONF_SG_PARAMS_MAX]; u8 param_idx; u8 padding[3]; } __packed; diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 8dc46c0a489a..e28e2f2303ce 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -626,7 +626,6 @@ struct wl12xx_cmd_remove_peer { */ enum wl12xx_fwlogger_log_mode { WL12XX_FWLOG_CONTINUOUS, - WL12XX_FWLOG_ON_DEMAND }; /* Include/exclude timestamps from the log messages */ diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 52a9d1b14020..44d898fe0afc 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -110,242 +110,11 @@ enum { CONF_SG_OPPORTUNISTIC }; -enum { - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT master basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_MASTER_MIN_BR = 0, - CONF_SG_ACL_BT_MASTER_MAX_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT slave basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_SLAVE_MIN_BR, - CONF_SG_ACL_BT_SLAVE_MAX_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_MASTER_MIN_EDR, - CONF_SG_ACL_BT_MASTER_MAX_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_SLAVE_MIN_EDR, - CONF_SG_ACL_BT_SLAVE_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna - * in WLAN PSM / BT master/slave BR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_WLAN_PS_MASTER_BR, - CONF_SG_ACL_WLAN_PS_SLAVE_BR, - - /* - * The maximum time WLAN can gain the antenna - * in WLAN PSM / BT master/slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_WLAN_PS_MASTER_EDR, - CONF_SG_ACL_WLAN_PS_SLAVE_EDR, - - /* TODO: explain these values */ - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, - - CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, - CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, - CONF_SG_ACL_PASSIVE_SCAN_BT_BR, - CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, - CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, - CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, - - /* - * Compensation percentage of probe requests when scan initiated - * during BT voice/ACL link. - * - * Range: 0 - 255 (%) - */ - CONF_SG_AUTO_SCAN_PROBE_REQ, - - /* - * Compensation percentage of probe requests when active scan initiated - * during BT voice - * - * Range: 0 - 255 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, - - /* - * Compensation percentage of WLAN active scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP BR - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP EDR - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT voice - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - - /* TODO: explain these values */ - CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, - CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, - CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, - - /* - * Defines whether the SG will force WLAN host to enter/exit PSM - * - * Range: 1 - SG can force, 0 - host handles PSM - */ - CONF_SG_STA_FORCE_PS_IN_BT_SCO, - - /* - * Defines antenna configuration (single/dual antenna) - * - * Range: 0 - single antenna, 1 - dual antenna - */ - CONF_SG_ANTENNA_CONFIGURATION, - - /* - * The threshold (percent) of max consecutive beacon misses before - * increasing priority of beacon reception. - * - * Range: 0 - 100 (%) - */ - CONF_SG_BEACON_MISS_PERCENT, - - /* - * Protection time of the DHCP procedure. - * - * Range: 0 - 100000 (ms) - */ - CONF_SG_DHCP_TIME, - - /* - * RX guard time before the beginning of a new BT voice frame during - * which no new WLAN trigger frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - CONF_SG_RXT, - - /* - * TX guard time before the beginning of a new BT voice frame during - * which no new WLAN frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - - CONF_SG_TXT, - - /* - * Enable adaptive RXT/TXT algorithm. If disabled, the host values - * will be utilized. - * - * Range: 0 - disable, 1 - enable - */ - CONF_SG_ADAPTIVE_RXT_TXT, - - /* TODO: explain this value */ - CONF_SG_GENERAL_USAGE_BIT_MAP, - - /* - * Number of consecutive BT voice frames not interrupted by WLAN - * - * Range: 0 - 100 - */ - CONF_SG_HV3_MAX_SERVED, - - /* - * The used WLAN legacy service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_PS_POLL_TIMEOUT, - - /* - * The used WLAN UPSD service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_UPSD_TIMEOUT, - - CONF_SG_CONSECUTIVE_CTS_THRESHOLD, - CONF_SG_STA_RX_WINDOW_AFTER_DTIM, - CONF_SG_STA_CONNECTION_PROTECTION_TIME, - - /* AP params */ - CONF_AP_BEACON_MISS_TX, - CONF_AP_RX_WINDOW_AFTER_BEACON, - CONF_AP_BEACON_WINDOW_INTERVAL, - CONF_AP_CONNECTION_PROTECTION_TIME, - CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, - CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, - - /* CTS Diluting params */ - CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, - CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, - - CONF_SG_TEMP_PARAM_1, - CONF_SG_TEMP_PARAM_2, - CONF_SG_TEMP_PARAM_3, - CONF_SG_TEMP_PARAM_4, - CONF_SG_TEMP_PARAM_5, - CONF_SG_TEMP_PARAM_6, - CONF_SG_TEMP_PARAM_7, - CONF_SG_TEMP_PARAM_8, - CONF_SG_TEMP_PARAM_9, - CONF_SG_TEMP_PARAM_10, - - CONF_SG_PARAMS_MAX, - CONF_SG_PARAMS_ALL = 0xff -}; +#define WLCORE_CONF_SG_PARAMS_MAX 67 +#define WLCORE_CONF_SG_PARAMS_ALL 0xff struct conf_sg_settings { - u32 params[CONF_SG_PARAMS_MAX]; + u32 params[WLCORE_CONF_SG_PARAMS_MAX]; u8 state; } __packed; diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index eb43f94a1597..8367f9edfb11 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -1234,6 +1234,65 @@ static const struct file_operations dev_mem_ops = { .llseek = dev_mem_seek, }; +static ssize_t fw_logger_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + + return wl1271_format_buffer(user_buf, count, + ppos, "%d\n", + wl->conf.fwlog.output); +} + +static ssize_t fw_logger_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + unsigned long value; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in fw_logger"); + return -EINVAL; + } + + if ((value > 2) || (value == 0)) { + wl1271_warning("fw_logger value must be 1-UART 2-SDIO"); + return -ERANGE; + } + + if (wl->conf.fwlog.output == 0) { + wl1271_warning("iligal opperation - fw logger disabled by default, please change mode via wlconf"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) { + count = ret; + goto out; + } + + wl->conf.fwlog.output = value; + + ret = wl12xx_cmd_config_fwlog(wl); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations fw_logger_ops = { + .open = simple_open, + .read = fw_logger_read, + .write = fw_logger_write, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -1260,6 +1319,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(irq_timeout, rootdir); DEBUGFS_ADD(fw_stats_raw, rootdir); DEBUGFS_ADD(sleep_auth, rootdir); + DEBUGFS_ADD(fw_logger, rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir); if (!streaming || IS_ERR(streaming)) diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index c42e78955e7b..c96405498bf4 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -28,6 +28,88 @@ #include "ps.h" #include "scan.h" #include "wl12xx_80211.h" +#include "hw_ops.h" + +#define WL18XX_LOGGER_SDIO_BUFF_MAX (0x1020) +#define WL18XX_DATA_RAM_BASE_ADDRESS (0x20000000) +#define WL18XX_LOGGER_SDIO_BUFF_ADDR (0x40159c) +#define WL18XX_LOGGER_BUFF_OFFSET (sizeof(struct fw_logger_information)) +#define WL18XX_LOGGER_READ_POINT_OFFSET (12) + +int wlcore_event_fw_logger(struct wl1271 *wl) +{ + u32 ret; + struct fw_logger_information fw_log; + u8 *buffer; + u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS; + u32 addr = WL18XX_LOGGER_SDIO_BUFF_ADDR; + u32 end_buff_addr = WL18XX_LOGGER_SDIO_BUFF_ADDR + + WL18XX_LOGGER_BUFF_OFFSET; + u32 available_len; + u32 actual_len; + u32 clear_addr; + size_t len; + u32 start_loc; + + buffer = kzalloc(WL18XX_LOGGER_SDIO_BUFF_MAX, GFP_KERNEL); + if (!buffer) { + wl1271_error("Fail to allocate fw logger memory"); + fw_log.actual_buff_size = cpu_to_le32(0); + goto out; + } + + ret = wlcore_read(wl, addr, buffer, WL18XX_LOGGER_SDIO_BUFF_MAX, + false); + if (ret < 0) { + wl1271_error("Fail to read logger buffer, error_id = %d", + ret); + fw_log.actual_buff_size = cpu_to_le32(0); + goto free_out; + } + + memcpy(&fw_log, buffer, sizeof(fw_log)); + + if (le32_to_cpu(fw_log.actual_buff_size) == 0) + goto free_out; + + actual_len = le32_to_cpu(fw_log.actual_buff_size); + start_loc = (le32_to_cpu(fw_log.buff_read_ptr) - + internal_fw_addrbase) - addr; + end_buff_addr += le32_to_cpu(fw_log.max_buff_size); + available_len = end_buff_addr - + (le32_to_cpu(fw_log.buff_read_ptr) - + internal_fw_addrbase); + actual_len = min(actual_len, available_len); + len = actual_len; + + wl12xx_copy_fwlog(wl, &buffer[start_loc], len); + clear_addr = addr + start_loc + le32_to_cpu(fw_log.actual_buff_size) + + internal_fw_addrbase; + + len = le32_to_cpu(fw_log.actual_buff_size) - len; + if (len) { + wl12xx_copy_fwlog(wl, + &buffer[WL18XX_LOGGER_BUFF_OFFSET], + len); + clear_addr = addr + WL18XX_LOGGER_BUFF_OFFSET + len + + internal_fw_addrbase; + } + + /* double check that clear address and write pointer are the same */ + if (clear_addr != le32_to_cpu(fw_log.buff_write_ptr)) { + wl1271_error("Calculate of clear addr Clear = %x, write = %x", + clear_addr, le32_to_cpu(fw_log.buff_write_ptr)); + } + + /* indicate FW about Clear buffer */ + ret = wlcore_write32(wl, addr + WL18XX_LOGGER_READ_POINT_OFFSET, + fw_log.buff_write_ptr); +free_out: + kfree(buffer); +out: + return le32_to_cpu(fw_log.actual_buff_size); +} +EXPORT_SYMBOL_GPL(wlcore_event_fw_logger); void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr) { diff --git a/drivers/net/wireless/ti/wlcore/event.h b/drivers/net/wireless/ti/wlcore/event.h index acc7a59d3828..75e8e98da2fe 100644 --- a/drivers/net/wireless/ti/wlcore/event.h +++ b/drivers/net/wireless/ti/wlcore/event.h @@ -64,6 +64,14 @@ enum { #define NUM_OF_RSSI_SNR_TRIGGERS 8 +struct fw_logger_information { + __le32 max_buff_size; + __le32 actual_buff_size; + __le32 num_trace_drop; + __le32 buff_read_ptr; + __le32 buff_write_ptr; +} __packed; + struct wl1271; int wl1271_event_unmask(struct wl1271 *wl); @@ -84,4 +92,5 @@ void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap); void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap); void wlcore_event_roc_complete(struct wl1271 *wl); void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr); +int wlcore_event_fw_logger(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c index 68e74eefd296..9ac118e727e9 100644 --- a/drivers/net/wireless/ti/wlcore/io.c +++ b/drivers/net/wireless/ti/wlcore/io.c @@ -175,12 +175,13 @@ int wlcore_set_partition(struct wl1271 *wl, if (ret < 0) goto out; - /* - * We don't need the size of the last partition, as it is - * automatically calculated based on the total memory size and - * the sizes of the previous partitions. - */ ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size); + if (ret < 0) + goto out; out: return ret; diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index 0305729d0986..6c257b54f415 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -36,8 +36,8 @@ #define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) #define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) #define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) -#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) - +#define HW_PART3_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) +#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 28) #define HW_ACCESS_REGISTER_SIZE 4 #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 @@ -207,19 +207,23 @@ static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg, static inline void wl1271_power_off(struct wl1271 *wl) { - int ret; + int ret = 0; if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags)) return; - ret = wl->if_ops->power(wl->dev, false); + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, false); if (!ret) clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static inline int wl1271_power_on(struct wl1271 *wl) { - int ret = wl->if_ops->power(wl->dev, true); + int ret = 0; + + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, true); if (ret == 0) set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ec7f6af3fab2..d1109c4f0f0d 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1,4 +1,3 @@ - /* * This file is part of wlcore * @@ -303,25 +302,11 @@ out: static void wlcore_adjust_conf(struct wl1271 *wl) { - /* Adjust settings according to optional module parameters */ - - /* Firmware Logger params */ - if (fwlog_mem_blocks != -1) { - if (fwlog_mem_blocks >= CONF_FWLOG_MIN_MEM_BLOCKS && - fwlog_mem_blocks <= CONF_FWLOG_MAX_MEM_BLOCKS) { - wl->conf.fwlog.mem_blocks = fwlog_mem_blocks; - } else { - wl1271_error( - "Illegal fwlog_mem_blocks=%d using default %d", - fwlog_mem_blocks, wl->conf.fwlog.mem_blocks); - } - } if (fwlog_param) { if (!strcmp(fwlog_param, "continuous")) { wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; - } else if (!strcmp(fwlog_param, "ondemand")) { - wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND; + wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_HOST; } else if (!strcmp(fwlog_param, "dbgpins")) { wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; @@ -825,91 +810,32 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) static void wl12xx_read_fwlog_panic(struct wl1271 *wl) { - struct wlcore_partition_set part, old_part; - u32 addr; - u32 offset; - u32 end_of_log; - u8 *block; - int ret; + u32 end_of_log = 0; - if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) || - (wl->conf.fwlog.mem_blocks == 0)) + if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) return; wl1271_info("Reading FW panic log"); - block = kmalloc(wl->fw_mem_block_size, GFP_KERNEL); - if (!block) - return; - /* * Make sure the chip is awake and the logger isn't active. * Do not send a stop fwlog command if the fw is hanged or if * dbgpins are used (due to some fw bug). */ if (wl1271_ps_elp_wakeup(wl)) - goto out; + return; if (!wl->watchdog_recovery && wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS) wl12xx_cmd_stop_fwlog(wl); - /* Read the first memory block address */ - ret = wlcore_fw_status(wl, wl->fw_status); - if (ret < 0) - goto out; - - addr = wl->fw_status->log_start_addr; - if (!addr) - goto out; - - if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) { - offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor); - end_of_log = wl->fwlog_end; - } else { - offset = sizeof(addr); - end_of_log = addr; - } - - old_part = wl->curr_part; - memset(&part, 0, sizeof(part)); - /* Traverse the memory blocks linked list */ do { - part.mem.start = wlcore_hw_convert_hwaddr(wl, addr); - part.mem.size = PAGE_SIZE; - - ret = wlcore_set_partition(wl, &part); - if (ret < 0) { - wl1271_error("%s: set_partition start=0x%X size=%d", - __func__, part.mem.start, part.mem.size); - goto out; + end_of_log = wlcore_event_fw_logger(wl); + if (end_of_log == 0) { + msleep(100); + end_of_log = wlcore_event_fw_logger(wl); } - - memset(block, 0, wl->fw_mem_block_size); - ret = wlcore_read_hwaddr(wl, addr, block, - wl->fw_mem_block_size, false); - - if (ret < 0) - goto out; - - /* - * Memory blocks are linked to one another. The first 4 bytes - * of each memory block hold the hardware address of the next - * one. The last memory block points to the first one in - * on demand mode and is equal to 0x2000000 in continuous mode. - */ - addr = le32_to_cpup((__le32 *)block); - - if (!wl12xx_copy_fwlog(wl, block + offset, - wl->fw_mem_block_size - offset)) - break; - } while (addr && (addr != end_of_log)); - - wake_up_interruptible(&wl->fwlog_waitq); - -out: - kfree(block); - wlcore_set_partition(wl, &old_part); + } while (end_of_log != 0); } static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -6291,7 +6217,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, wl->active_sta_count = 0; wl->active_link_count = 0; wl->fwlog_size = 0; - init_waitqueue_head(&wl->fwlog_waitq); /* The system link is always allocated */ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); @@ -6377,7 +6302,6 @@ int wlcore_free_hw(struct wl1271 *wl) /* Unblock any fwlog readers */ mutex_lock(&wl->mutex); wl->fwlog_size = -1; - wake_up_interruptible_all(&wl->fwlog_waitq); mutex_unlock(&wl->mutex); wlcore_sysfs_free(wl); @@ -6584,7 +6508,7 @@ MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(fwlog, - "FW logger options: continuous, ondemand, dbgpins or disable"); + "FW logger options: continuous, dbgpins or disable"); module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks"); diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 5b2927391d1c..34e7e938ede4 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -149,7 +149,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); - wake_up_interruptible(&wl->fwlog_waitq); return 0; } diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 236b41090827..44f059f7f34e 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -73,7 +73,10 @@ */ #define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) -#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) +/* Maximum number of SPI write chunks */ +#define WSPI_MAX_NUM_OF_CHUNKS \ + ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) + struct wl12xx_spi_glue { struct device *dev; @@ -268,9 +271,10 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); - struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; + /* SPI write buffers - 2 for each chunk */ + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; - u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ u32 *cmd; u32 chunk_len; int i; diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 24dd288d6809..a9218e5b0efc 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -119,32 +119,6 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, if (ret < 0) return -ERESTARTSYS; - /* Let only one thread read the log at a time, blocking others */ - while (wl->fwlog_size == 0) { - DEFINE_WAIT(wait); - - prepare_to_wait_exclusive(&wl->fwlog_waitq, - &wait, - TASK_INTERRUPTIBLE); - - if (wl->fwlog_size != 0) { - finish_wait(&wl->fwlog_waitq, &wait); - break; - } - - mutex_unlock(&wl->mutex); - - schedule(); - finish_wait(&wl->fwlog_waitq, &wait); - - if (signal_pending(current)) - return -ERESTARTSYS; - - ret = mutex_lock_interruptible(&wl->mutex); - if (ret < 0) - return -ERESTARTSYS; - } - /* Check if the fwlog is still valid */ if (wl->fwlog_size < 0) { mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 906be6aa4eb6..dda01b118c26 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -310,9 +310,6 @@ struct wl1271 { /* FW memory block size */ u32 fw_mem_block_size; - /* Sysfs FW log entry readers wait queue */ - wait_queue_head_t fwlog_waitq; - /* Hardware recovery work */ struct work_struct recovery_work; bool watchdog_recovery; diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 149214beeda9..0c675861623f 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -82,7 +82,7 @@ config SSB_SDIOHOST config SSB_HOST_SOC bool "Support for SSB bus on SoC" - depends on SSB + depends on SSB && BCM47XX_NVRAM help Host interface for a SSB directly mapped into memory. This is for some Broadcom SoCs from the BCM47xx and BCM53xx lines. diff --git a/drivers/ssb/host_soc.c b/drivers/ssb/host_soc.c index c809f255af34..d62992dc08b2 100644 --- a/drivers/ssb/host_soc.c +++ b/drivers/ssb/host_soc.c @@ -8,6 +8,7 @@ * Licensed under the GNU/GPL. See COPYING for details. */ +#include #include #include "ssb_private.h" @@ -171,3 +172,39 @@ const struct ssb_bus_ops ssb_host_soc_ops = { .block_write = ssb_host_soc_block_write, #endif }; + +int ssb_host_soc_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + char buf[20]; + int len, err; + + /* Fill boardinfo structure */ + memset(&iv->boardinfo, 0, sizeof(struct ssb_boardinfo)); + + len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf)); + if (len > 0) { + err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor); + if (err) + pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n", + buf); + } + if (!iv->boardinfo.vendor) + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; + + len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf)); + if (len > 0) { + err = kstrtou16(strim(buf), 0, &iv->boardinfo.type); + if (err) + pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n", + buf); + } + + memset(&iv->sprom, 0, sizeof(struct ssb_sprom)); + ssb_fill_sprom_with_fallback(bus, &iv->sprom); + + if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) + iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); + + return 0; +} diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 5d1e9a0fc389..cde5ff7529eb 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -762,15 +762,14 @@ EXPORT_SYMBOL(ssb_bus_sdiobus_register); #endif /* CONFIG_SSB_PCMCIAHOST */ #ifdef CONFIG_SSB_HOST_SOC -int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, - ssb_invariants_func_t get_invariants) +int ssb_bus_host_soc_register(struct ssb_bus *bus, unsigned long baseaddr) { int err; bus->bustype = SSB_BUSTYPE_SSB; bus->ops = &ssb_host_soc_ops; - err = ssb_bus_register(bus, get_invariants, baseaddr); + err = ssb_bus_register(bus, ssb_host_soc_get_invariants, baseaddr); if (!err) { ssb_info("Sonics Silicon Backplane found at address 0x%08lX\n", baseaddr); diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 15bfd5c7d2d7..c2f5d3969c8b 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -163,6 +163,9 @@ static inline int ssb_sdio_init(struct ssb_bus *bus) #ifdef CONFIG_SSB_HOST_SOC extern const struct ssb_bus_ops ssb_host_soc_ops; + +extern int ssb_host_soc_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); #endif /* scan.c */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index c3d1a525bacc..26a0b3c3ce5f 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -524,13 +524,9 @@ struct ssb_init_invariants { typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, struct ssb_init_invariants *iv); -/* Register a SSB system bus. get_invariants() is called after the - * basic system devices are initialized. - * The invariants are usually fetched from some NVRAM. - * Put the invariants into the struct pointed to by iv. */ -extern int ssb_bus_ssbbus_register(struct ssb_bus *bus, - unsigned long baseaddr, - ssb_invariants_func_t get_invariants); +/* Register SoC bus. */ +extern int ssb_bus_host_soc_register(struct ssb_bus *bus, + unsigned long baseaddr); #ifdef CONFIG_SSB_PCIHOST extern int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci);