From b27bc5a40f915671eda3ac255734a64153fc91f5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:40 +0300 Subject: ath10k: dump fw features during probing This should help when analysing problems from users and spot fw api blob problems easier. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 44 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 3 +++ drivers/net/wireless/ath/ath10k/debug.c | 9 +++++-- 3 files changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 59496a90ad5e..f5db43284b97 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -103,6 +103,50 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }; +static const char *const ath10k_core_fw_feature_str[] = { + [ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx", + [ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x", + [ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx", + [ATH10K_FW_FEATURE_NO_P2P] = "no-p2p", + [ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2", + [ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps", + [ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan", + [ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp", + [ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad", + [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init", +}; + +static unsigned int ath10k_core_get_fw_feature_str(char *buf, + size_t buf_len, + enum ath10k_fw_features feat) +{ + if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) || + WARN_ON(!ath10k_core_fw_feature_str[feat])) { + return scnprintf(buf, buf_len, "bit%d", feat); + } + + return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]); +} + +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t buf_len) +{ + unsigned int len = 0; + int i; + + for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { + if (test_bit(i, ar->fw_features)) { + if (len > 0) + len += scnprintf(buf + len, buf_len - len, ","); + + len += ath10k_core_get_fw_feature_str(buf + len, + buf_len - len, + i); + } + } +} + static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78094f23c9dd..e9f93045fbd8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -749,6 +749,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t max_len); int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8fa606a9c4dd..8a4edfd36e47 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,11 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", + char fw_features[128]; + + ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); + + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -138,7 +142,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_minor, ar->wmi.op_version, ath10k_cal_mode_str(ar->cal_mode), - ar->max_num_stations); + ar->max_num_stations, + fw_features); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), -- cgit v1.2.3-70-g09d2 From 67c81f5a06ed1474c4f16ad93f4502c760999515 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: ath10k: print htt op_version upon driver boot HTT version itself isn't sufficient to know what HTT version given firmware blob uses. Hence print the recently introduced HTT op version code. While at it make the info string a bit more consistent and clear. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8a4edfd36e47..edf6047997a7 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -128,7 +128,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -141,6 +141,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_major, ar->htt.target_version_minor, ar->wmi.op_version, + ar->htt.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations, fw_features); -- cgit v1.2.3-70-g09d2 From c702534a23d61deaa0565ef0495ab866c06c4325 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: ath10k: enable VHT for IBSS Enable VHT support for IBSS, while mac80211/cfg80211 and wpa_supplicant already support this. In my test env, qca988x 2x2 I get: (udp) ath10k-1 >>>> ath10k-2 (server) - speed: 419 Mbits/sec (tcp) ath10k-1 >>>> ath10k-2 (server) - speed: 404 Mbits/sec During tests I used wpa_supplicant (latest git version), which already support IBSS VHT, and choose highest available BW. Also tested with qca6174. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c48c744acbcc..c6255069e6e0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6902,6 +6902,8 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing -- cgit v1.2.3-70-g09d2 From aeae5b4cd9185b0dc72f6d6102cf45073bfbc974 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: ath10k: prevent debugfs mmio access crash kernel It was possible to force an out of bounds MMIO read/write via debugfs. E.g. on QCA988X this could be triggered with: echo 0x2080e0 | tee /sys/kernel/debug/ieee80211/*/ath10k/reg_addr cat /sys/kernel/debug/ieee80211/*/ath10k/reg_value BUG: unable to handle kernel paging request at ffffc90001e080e0 IP: [] ioread32+0x40/0x50 ... Call Trace: [] ? ath10k_pci_read32+0x4f/0x70 [ath10k_pci] [] ath10k_reg_value_read+0x90/0xf0 [ath10k_core] [] ? handle_mm_fault+0xa91/0x1050 [] __vfs_read+0x28/0xe0 [] ? security_file_permission+0x84/0xa0 [] ? rw_verify_area+0x53/0x100 [] vfs_read+0x8a/0x140 [] SyS_read+0x49/0xb0 [] ? trace_do_page_fault+0x3c/0xc0 [] system_call_fastpath+0x12/0x71 Reported-by: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/pci.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ea656e011a96..41765172297c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -479,6 +479,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; + if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(value), ar_pci->mem_len); + return; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", @@ -496,6 +502,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) u32 val; int ret; + if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(val), ar_pci->mem_len); + return 0; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", @@ -2679,6 +2691,7 @@ static int ath10k_pci_claim(struct ath10k *ar) pci_set_master(pdev); /* Arrange for access to Target SoC registers. */ + ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM); ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); if (!ar_pci->mem) { ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d7696ddc03c4..eea0a0170b00 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -162,6 +162,7 @@ struct ath10k_pci { struct device *dev; struct ath10k *ar; void __iomem *mem; + size_t mem_len; /* * Number of MSI interrupts granted, 0 --> using legacy PCI line -- cgit v1.2.3-70-g09d2 From 404d67ef2935c5e41d3d7a403c5fb1c278eff60e Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: ath10k: remove unused variable hdr in ath10k_htt_rx_h_undecap() Just found this during code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 89eb16b30fc4..7399e45a016e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1201,7 +1201,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, { struct htt_rx_desc *rxd; enum rx_msdu_decap_format decap; - struct ieee80211_hdr *hdr; /* First msdu's decapped header: * [802.11 header] <-- padded to 4 bytes long @@ -1215,7 +1214,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - hdr = (void *)rxd->rx_hdr_status; decap = MS(__le32_to_cpu(rxd->msdu_start.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); -- cgit v1.2.3-70-g09d2 From d4298a3a8c92a18d375e55feecc60e4eefeb45e3 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: ath10k: mac: remove unreachable negative return check wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is ==0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c6255069e6e0..e17eb75c508e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5566,7 +5566,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct ath10k *ar = hw->priv; bool skip; - int ret; + long time_left; /* mac80211 doesn't care if we really xmit queued frames or not * we'll collect those frames either way if we stop/delete vdevs */ @@ -5578,7 +5578,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (ar->state == ATH10K_STATE_WEDGED) goto skip; - ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ + time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; spin_lock_bh(&ar->htt.tx_lock); @@ -5592,9 +5592,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, (empty || skip); }), ATH10K_FLUSH_TIMEOUT_HZ); - if (ret <= 0 || skip) - ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", - skip, ar->state, ret); + if (time_left == 0 || skip) + ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", + skip, ar->state, time_left); skip: mutex_unlock(&ar->conf_mutex); -- cgit v1.2.3-70-g09d2 From 71c47df4aa54ee3bfb113a5ae468c8bfb3a6fb7b Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: ath10k: txrx: remove unreachable negative return check and fixup type wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is == 0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 826500bb2b1b..6cf289158840 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -147,9 +147,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, const u8 *addr, bool expect_mapped) { - int ret; + long time_left; - ret = wait_event_timeout(ar->peer_mapping_wq, ({ + time_left = wait_event_timeout(ar->peer_mapping_wq, ({ bool mapped; spin_lock_bh(&ar->data_lock); @@ -160,7 +160,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); }), 3*HZ); - if (ret <= 0) + if (time_left == 0) return -ETIMEDOUT; return 0; -- cgit v1.2.3-70-g09d2 From b503ed603ec9acc25dd31808fe87575bdaeab4e7 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 27 May 2015 22:20:46 +0300 Subject: iwlwifi: mvm: rs: report last tx rate based on RSSI and caps In scenarios where we haven't converged yet to a specific modulation and rate it could be better to report to userspace the last tx rate based on the STA capabilities and RSSI. This is important as sometimes userspace displays the last tx rate as the link speed. This avoids being presented with low legacy rates when rs just begins its search or after an idle period in which it resets itself. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 157 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rs.h | 10 +++ 2 files changed, 160 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index daff1d0a8e4a..19a79262e0a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2403,7 +2403,7 @@ struct rs_init_rate_info { u8 rate_idx; }; -static const struct rs_init_rate_info rs_init_rates_24ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_24ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -68, IWL_RATE_36M_INDEX }, @@ -2416,7 +2416,7 @@ static const struct rs_init_rate_info rs_init_rates_24ghz[] = { { S8_MIN, IWL_RATE_1M_INDEX }, }; -static const struct rs_init_rate_info rs_init_rates_5ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_5ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -72, IWL_RATE_36M_INDEX }, @@ -2427,6 +2427,124 @@ static const struct rs_init_rate_info rs_init_rates_5ghz[] = { { S8_MIN, IWL_RATE_6M_INDEX }, }; +static const struct rs_init_rate_info rs_optimal_rates_ht[] = { + { -60, IWL_RATE_MCS_7_INDEX }, + { -64, IWL_RATE_MCS_6_INDEX }, + { -68, IWL_RATE_MCS_5_INDEX }, + { -72, IWL_RATE_MCS_4_INDEX }, + { -80, IWL_RATE_MCS_3_INDEX }, + { -84, IWL_RATE_MCS_2_INDEX }, + { -85, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { + { -60, IWL_RATE_MCS_8_INDEX }, + { -64, IWL_RATE_MCS_7_INDEX }, + { -68, IWL_RATE_MCS_6_INDEX }, + { -72, IWL_RATE_MCS_5_INDEX }, + { -80, IWL_RATE_MCS_4_INDEX }, + { -84, IWL_RATE_MCS_3_INDEX }, + { -85, IWL_RATE_MCS_2_INDEX }, + { -87, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { + { -60, IWL_RATE_MCS_9_INDEX }, + { -64, IWL_RATE_MCS_8_INDEX }, + { -68, IWL_RATE_MCS_7_INDEX }, + { -72, IWL_RATE_MCS_6_INDEX }, + { -80, IWL_RATE_MCS_5_INDEX }, + { -84, IWL_RATE_MCS_4_INDEX }, + { -85, IWL_RATE_MCS_3_INDEX }, + { -87, IWL_RATE_MCS_2_INDEX }, + { -88, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX }, +}; + +/* 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. + */ +static void rs_init_optimal_rate(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + + if (lq_sta->max_mimo2_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; + else if (lq_sta->max_siso_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; + else if (lq_sta->band == IEEE80211_BAND_5GHZ) + rate->type = LQ_LEGACY_A; + else + rate->type = LQ_LEGACY_G; + + rate->bw = rs_bw_from_sta_bw(sta); + rate->sgi = rs_sgi_allow(mvm, sta, rate, NULL); + + /* ANT/LDPC/STBC aren't relevant for the rate reported to userspace */ + + if (is_mimo(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_mimo2_rate; + } else if (is_siso(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_siso_rate; + } else { + lq_sta->optimal_rate_mask = lq_sta->active_legacy_rate; + + if (lq_sta->band == IEEE80211_BAND_5GHZ) { + lq_sta->optimal_rates = rs_optimal_rates_5ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); + } else { + lq_sta->optimal_rates = rs_optimal_rates_24ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); + } + } + + if (is_vht(rate)) { + if (rate->bw == RATE_MCS_CHAN_WIDTH_20) { + lq_sta->optimal_rates = rs_optimal_rates_vht_20mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_20mhz); + } else { + lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); + } + } else if (is_ht(rate)) { + lq_sta->optimal_rates = rs_optimal_rates_ht; + lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_ht); + } +} + +/* Compute the optimal rate index based on RSSI */ +static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + int i; + + rate->index = find_first_bit(&lq_sta->optimal_rate_mask, + BITS_PER_LONG); + + for (i = 0; i < lq_sta->optimal_nentries; i++) { + int rate_idx = lq_sta->optimal_rates[i].rate_idx; + + if ((lq_sta->pers.last_rssi >= lq_sta->optimal_rates[i].rssi) && + (BIT(rate_idx) & lq_sta->optimal_rate_mask)) { + rate->index = rate_idx; + break; + } + } + + rs_dump_rate(mvm, rate, "OPTIMAL RATE"); + return rate; +} + /* Choose an initial legacy rate and antenna to use based on the RSSI * of last Rx */ @@ -2468,12 +2586,12 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, if (band == IEEE80211_BAND_5GHZ) { rate->type = LQ_LEGACY_A; - initial_rates = rs_init_rates_5ghz; - nentries = ARRAY_SIZE(rs_init_rates_5ghz); + initial_rates = rs_optimal_rates_5ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); } else { rate->type = LQ_LEGACY_G; - initial_rates = rs_init_rates_24ghz; - nentries = ARRAY_SIZE(rs_init_rates_24ghz); + initial_rates = rs_optimal_rates_24ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { @@ -2496,10 +2614,21 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct ieee80211_rx_status *rx_status) { + int i; + lq_sta->pers.chains = rx_status->chains; lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0]; lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1]; lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; + lq_sta->pers.last_rssi = S8_MIN; + + for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { + if (!(lq_sta->pers.chains & BIT(i))) + continue; + + if (lq_sta->pers.chain_signal[i] > lq_sta->pers.last_rssi) + lq_sta->pers.last_rssi = lq_sta->pers.chain_signal[i]; + } } /** @@ -2538,6 +2667,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate = &tbl->rate; rs_get_initial_rate(mvm, 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) @@ -2560,6 +2690,8 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; + struct rs_rate *optimal_rate; + u32 last_ucode_rate; if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) { /* if vif isn't initialized mvm doesn't know about @@ -2583,8 +2715,18 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags, info->band, &info->control.rates[0]); - info->control.rates[0].count = 1; + + /* Report the optimal rate based on rssi and STA caps if we haven't + * converged yet (too little traffic) or exploring other modulations + */ + if (lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN) { + optimal_rate = rs_get_optimal_rate(mvm, lq_sta); + last_ucode_rate = ucode_rate_from_rs_rate(mvm, + optimal_rate); + iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, info->band, + &txrc->reported_rate); + } } static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, @@ -2605,6 +2747,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, #endif lq_sta->pers.chains = 0; memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); + lq_sta->pers.last_rssi = S8_MIN; return &sta_priv->lq_sta; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 2a3da314305a..81314ad9ebe0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Mobile Communications 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 @@ -316,6 +317,14 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; + /* Optimal rate based on RSSI and STA caps. + * Used only to reflect link speed to userspace. + */ + struct rs_rate optimal_rate; + unsigned long optimal_rate_mask; + const struct rs_init_rate_info *optimal_rates; + int optimal_nentries; + u8 missed_rate_counter; struct iwl_lq_cmd lq; @@ -341,6 +350,7 @@ struct iwl_lq_sta { #endif u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; + s8 last_rssi; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; -- cgit v1.2.3-70-g09d2 From 1738d60b31d7792516426d62521ec65bff8281f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 May 2015 12:09:44 +0200 Subject: iwlwifi: mvm: handle RX MPDUs separately There's no need to forward RX MPDUs to notification wait tests, nor do we need to check them for firmware dump triggers, nor could they be asynchronous. It's thus more efficient to handle them separately, before going into the regular RX handlers. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffd..8f896cd1c9cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -221,7 +221,6 @@ struct iwl_rx_handlers { * called from a worker with mvm->mutex held. */ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { - RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false), RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), @@ -716,6 +715,9 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 i; + if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) + return iwl_mvm_rx_rx_mpdu(mvm, rxb, cmd); + iwl_mvm_rx_check_trigger(mvm, pkt); /* -- cgit v1.2.3-70-g09d2 From 6c7d32cfdc622ef4b9f157592fc167513507270d Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jun 2015 09:34:57 +0300 Subject: iwlwifi: deprecate -10.ucode for 3160 / 7260 / 7265 This firmware is not supported anymore - stop loading this firmware. Remove code handling older versions. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index cc35f796d406..fa35da4edda2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -76,7 +76,7 @@ #define IWL3165_UCODE_API_OK 13 /* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 10 +#define IWL7260_UCODE_API_MIN 12 #define IWL3165_UCODE_API_MIN 13 /* NVM versions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 72040cd0b979..0de575124fa2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -75,7 +75,7 @@ #define IWL8000_UCODE_API_OK 12 /* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN 10 +#define IWL8000_UCODE_API_MIN 12 /* NVM versions */ #define IWL8000_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index eb10c5ee4a14..a482ce692f5f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -676,8 +676,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) - iwl_mvm_get_shared_mem_conf(mvm); + iwl_mvm_get_shared_mem_conf(mvm); ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) -- cgit v1.2.3-70-g09d2 From 012c02c15ac63b0b26c7f058c744e85cb563a737 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 16 Jun 2015 22:37:40 +0300 Subject: iwlwifi: dvm: start HW before running FW The new locking in PCIe transport requires to start_hw before start_fw. This uncovered a bug in dvm which failed to do so. Fix that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 7acaa266b704..f603fb3122f7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -250,12 +250,24 @@ static int __iwl_up(struct iwl_priv *priv) } } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_run_init_ucode(priv); if (ret) { IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); goto error; } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); -- cgit v1.2.3-70-g09d2 From fa9f3281cbb1075545d4528c84059a3f4e117b44 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 11 Jun 2015 20:45:49 +0300 Subject: iwlwifi: pcie: lock start_hw / start_fw / stop_device This allows to ensure that we don't have races between them. A user reported that stop_device was called twice upon rfkill interrupt after suspend. When the interrupts are enabled, and right after when we directly check the rfkill state. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 4 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 3 + drivers/net/wireless/iwlwifi/pcie/rx.c | 2 + drivers/net/wireless/iwlwifi/pcie/trans.c | 82 ++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2ed1e4d2774d..dbd2a03a0f6d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -613,6 +613,7 @@ static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here @@ -643,7 +644,10 @@ static int iwl_pci_resume(struct device *device) } hw_rfkill = iwl_is_rfkill_set(trans); + + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); return 0; } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 31f72a61cc3f..4f0640767d30 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -301,6 +301,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access + * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor * @fw_mon_page: points to the first page of the buffer for the firmware monitor @@ -320,9 +321,11 @@ struct iwl_trans_pcie { dma_addr_t ict_tbl_dma; int ict_index; bool use_ict; + bool is_down; struct isr_statistics isr_stats; spinlock_t irq_lock; + struct mutex mutex; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a3fbaa0ef5e0..93062f2e8f56 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1251,7 +1251,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) isr_stats->rfkill++; + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); if (hw_rfkill) { set_bit(STATUS_RFKILL, &trans->status); if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 43ae658af6ec..23f2824e8d56 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -982,13 +982,25 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { - int ret; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; + int ret; + + mutex_lock(&trans_pcie->mutex); + + /* Someone called stop_device, don't try to start_fw */ + if (trans_pcie->is_down) { + IWL_WARN(trans, + "Can't start_fw since the HW hasn't been started\n"); + ret = EIO; + goto out; + } /* This may fail if AMT took ownership of the device */ if (iwl_pcie_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); - return -EIO; + ret = -EIO; + goto out; } iwl_enable_rfkill_int(trans); @@ -1000,15 +1012,17 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, else clear_bit(STATUS_RFKILL, &trans->status); iwl_trans_pcie_rf_kill(trans, hw_rfkill); - if (hw_rfkill && !run_in_rfkill) - return -ERFKILL; + if (hw_rfkill && !run_in_rfkill) { + ret = -ERFKILL; + goto out; + } iwl_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_pcie_nic_init(trans); if (ret) { IWL_ERR(trans, "Unable to init nic\n"); - return ret; + goto out; } /* make sure rfkill handshake bits are cleared */ @@ -1026,9 +1040,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* Load the given image to the HW */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) - return iwl_pcie_load_given_ucode_8000(trans, fw); + ret = iwl_pcie_load_given_ucode_8000(trans, fw); else - return iwl_pcie_load_given_ucode(trans, fw); + ret = iwl_pcie_load_given_ucode(trans, fw); + +out: + mutex_unlock(&trans_pcie->mutex); + return ret; } static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) @@ -1037,11 +1055,18 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill, was_hw_rfkill; + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->is_down) + return; + + trans_pcie->is_down = true; + was_hw_rfkill = iwl_is_rfkill_set(trans); /* tell the device to stop sending interrupts */ @@ -1131,10 +1156,24 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) iwl_pcie_prepare_card_hw(trans); } +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + mutex_lock(&trans_pcie->mutex); + _iwl_trans_pcie_stop_device(trans, low_power); + mutex_unlock(&trans_pcie->mutex); +} + void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) { + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->mutex); + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - iwl_trans_pcie_stop_device(trans, true); + _iwl_trans_pcie_stop_device(trans, true); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -1219,11 +1258,14 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; int err; + lockdep_assert_held(&trans_pcie->mutex); + err = iwl_pcie_prepare_card_hw(trans); if (err) { IWL_ERR(trans, "Error while preparing HW: %d\n", err); @@ -1240,20 +1282,38 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); + /* Set is_down to false here so that...*/ + trans_pcie->is_down = false; + hw_rfkill = iwl_is_rfkill_set(trans); if (hw_rfkill) set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); + /* ... rfkill can call stop_device and set it false if needed */ iwl_trans_pcie_rf_kill(trans, hw_rfkill); return 0; } +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + mutex_lock(&trans_pcie->mutex); + ret = _iwl_trans_pcie_start_hw(trans, low_power); + mutex_unlock(&trans_pcie->mutex); + + return ret; +} + static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + mutex_lock(&trans_pcie->mutex); + /* disable interrupts - don't enable HW RF kill interrupt */ spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); @@ -1266,6 +1326,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); + mutex_unlock(&trans_pcie->mutex); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -2472,6 +2533,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); spin_lock_init(&trans_pcie->ref_lock); + mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); err = pci_enable_device(pdev); -- cgit v1.2.3-70-g09d2 From 923a8c1d8069104726bde55c37cec66324ccc328 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 31 May 2015 21:44:22 +0300 Subject: iwlwifi: mvm: fix antenna selection when BT is active When BT is active, we want to avoid the shared antenna for management frame to make sure we don't disturb BT. There was a bug in that code because it chose the antenna BIT(ANT_A) where ANT_A is already a bitmap (0x1). This means that the antenna chosen in the end was ANT_B. While this is not optimal on devices with 2 antennas (it'd disturb BT), it is critical on single antenna devices like 3160 which couldn't connect at all when BT was active. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=97181 CC: [3.17+] Fixes: 34c8b24ff284 ("iwlwifi: mvm: BT Coex - avoid the shared antenna for management frames") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 7ba7a118ff5c..89116864d2a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -252,7 +252,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, if (info->band == IEEE80211_BAND_2GHZ && !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) - rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; + rate_flags = mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS; else rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; -- cgit v1.2.3-70-g09d2 From 11828dbce6f769ed631919aa378b645b1af6bda6 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Mon, 1 Jun 2015 15:15:11 +0300 Subject: iwlwifi: mvm: Avoid accessing Null pointer when setting igtk Sometimes when setting an igtk key the station maybe NULL. In the of case igtk the function will skip to the end, and try to print sta->addr, if sta is Null - we will access a Null pointer. Avoid accessing a Null pointer when setting a igtk key & the sta == NULL, and print a default MAC address instead. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d68dc697a4a0..26f076e82149 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1401,6 +1401,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); u8 sta_id; int ret; + static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; lockdep_assert_held(&mvm->mutex); @@ -1467,7 +1468,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, end: IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", keyconf->cipher, keyconf->keylen, keyconf->keyidx, - sta->addr, ret); + sta ? sta->addr : zero_addr, ret); return ret; } -- cgit v1.2.3-70-g09d2 From 2f2cfc4a9a5b7be65d61382b58cfb206f13966df Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:01 +0530 Subject: ath10k: Add a table to store hw specific values This is to prepare ath10k to support newer chip set. Values like CE_COUNT, MSI_ASSIGN_CE_MAX and RTC_STATE_V_ON can be different for different chips. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 +++++++++++++++--- 4 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f5db43284b97..b17541b74aaf 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1514,9 +1514,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, switch (hw_rev) { case ATH10K_HW_QCA988X: ar->regs = &qca988x_regs; + ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: ar->regs = &qca6174_regs; + ar->hw_values = &qca6174_values; break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e9f93045fbd8..993cd362fb0a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -560,6 +560,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_values *hw_values; struct ath10k_bmi bmi; struct ath10k_wmi wmi; struct ath10k_htc htc; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 5997f00afe3b..48bcd2cfad00 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -58,6 +58,20 @@ const struct ath10k_hw_regs qca6174_regs = { .scratch_3_address = 0x0028, }; +const struct ath10k_hw_values qca988x_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + +const struct ath10k_hw_values qca6174_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 85cca29375fe..b218388131ca 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -169,6 +169,16 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +struct ath10k_hw_values { + u32 rtc_state_val_on; + u8 ce_count; + u8 msi_assign_ce_max; + u8 num_target_ce_config_wlan; +}; + +extern const struct ath10k_hw_values qca988x_values; +extern const struct ath10k_hw_values qca6174_values; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); @@ -310,8 +320,10 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +#define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan + /* Number of Copy Engines supported */ -#define CE_COUNT 8 +#define CE_COUNT ar->hw_values->ce_count /* * Total number of PCIe MSI interrupts requested for all interrupt sources. @@ -335,10 +347,10 @@ enum ath10k_hw_rate_cck { /* MSIs for Copy Engines */ #define MSI_ASSIGN_CE_INITIAL 1 -#define MSI_ASSIGN_CE_MAX 7 +#define MSI_ASSIGN_CE_MAX ar->hw_values->msi_assign_ce_max /* as of IP3.7.1 */ -#define RTC_STATE_V_ON 3 +#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on #define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 -- cgit v1.2.3-70-g09d2 From a521ee983d312db76e6c275c32475cb20bdc7d39 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:02 +0530 Subject: ath10k: Add new reg_address/mask to hw register table Add more register address and mask which can be different for newer chip to hw_reg table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 6 ++++-- drivers/net/wireless/ath/ath10k/hw.c | 22 ++++++++++++++++++---- drivers/net/wireless/ath/ath10k/hw.h | 17 ++++++++++++----- 3 files changed, 34 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0eddb204d85b..93939de2be19 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -423,8 +423,10 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask)) -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + ar->regs->ce_wrap_intr_sum_host_msi_lsb +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + ar->regs->ce_wrap_intr_sum_host_msi_mask #define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \ (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 48bcd2cfad00..cb09867b5533 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -34,8 +34,15 @@ const struct ath10k_hw_regs qca988x_regs = { .ce7_base_address = 0x00059000, .soc_reset_control_si0_rst_mask = 0x00000001, .soc_reset_control_ce_rst_mask = 0x00040000, - .soc_chip_id_address = 0x00ec, - .scratch_3_address = 0x0030, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00000030, + .fw_indicator_address = 0x00009030, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_regs qca6174_regs = { @@ -54,8 +61,15 @@ const struct ath10k_hw_regs qca6174_regs = { .ce7_base_address = 0x00036000, .soc_reset_control_si0_rst_mask = 0x00000000, .soc_reset_control_ce_rst_mask = 0x00000001, - .soc_chip_id_address = 0x000f0, - .scratch_3_address = 0x0028, + .soc_chip_id_address = 0x000000f0, + .scratch_3_address = 0x00000028, + .fw_indicator_address = 0x00009028, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_values qca988x_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b218388131ca..5d04317cb3dc 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -164,6 +164,13 @@ struct ath10k_hw_regs { u32 soc_reset_control_ce_rst_mask; u32 soc_chip_id_address; u32 scratch_3_address; + u32 fw_indicator_address; + u32 pcie_local_base_address; + u32 ce_wrap_intr_sum_host_msi_lsb; + u32 ce_wrap_intr_sum_host_msi_mask; + u32 pcie_intr_fw_mask; + u32 pcie_intr_ce_mask_all; + u32 pcie_intr_clr_address; }; extern const struct ath10k_hw_regs qca988x_regs; @@ -386,7 +393,7 @@ enum ath10k_hw_rate_cck { #define CE7_BASE_ADDRESS ar->regs->ce7_base_address #define DBI_BASE_ADDRESS 0x00060000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 -#define PCIE_LOCAL_BASE_ADDRESS 0x00080000 +#define PCIE_LOCAL_BASE_ADDRESS ar->regs->pcie_local_base_address #define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 @@ -460,7 +467,7 @@ enum ath10k_hw_rate_cck { #define CORE_CTRL_ADDRESS 0x0000 #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c -#define PCIE_INTR_CLR_ADDRESS 0x0014 +#define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 @@ -468,13 +475,13 @@ enum ath10k_hw_rate_cck { #define CCNT_TO_MSEC(x) ((x) / 88000) /* Firmware indications to the Host via SCRATCH_3 register. */ -#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) +#define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address #define FW_IND_EVENT_PENDING 1 #define FW_IND_INITIALIZED 2 /* HOST_REG interrupt from firmware */ -#define PCIE_INTR_FIRMWARE_MASK 0x00000400 -#define PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask +#define PCIE_INTR_CE_MASK_ALL ar->regs->pcie_intr_ce_mask_all #define DRAM_BASE_ADDRESS 0x00400000 -- cgit v1.2.3-70-g09d2 From 8bd4702103dca2b06446f85c04222faa8eb553b5 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:03 +0530 Subject: ath10k: Add hw register/values for QCA99X0 chip This is to prepare the driver for QCA99X0 chip support. This commit adds hw_params, hw register table and hw_values table for QCA99X0 chip. Please note this is only a partial patch adding support for QCA99X0, so the device id is not yet added to pci device table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 18 ++++++++++++ drivers/net/wireless/ath/ath10k/hw.c | 44 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 ++++++++++++ drivers/net/wireless/ath/ath10k/pci.c | 5 ++++ drivers/net/wireless/ath/ath10k/targaddrs.h | 3 ++ 5 files changed, 88 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b17541b74aaf..f239e9690831 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -101,6 +101,20 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA99X0_HW_2_0_DEV_VERSION, + .name = "qca99x0 hw2.0", + .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .fw = { + .dir = QCA99X0_HW_2_0_FW_DIR, + .fw = QCA99X0_HW_2_0_FW_FILE, + .otp = QCA99X0_HW_2_0_OTP_FILE, + .board = QCA99X0_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, + }, }; static const char *const ath10k_core_fw_feature_str[] = { @@ -1520,6 +1534,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->regs = &qca6174_regs; ar->hw_values = &qca6174_values; break; + case ATH10K_HW_QCA99X0: + ar->regs = &qca99x0_regs; + ar->hw_values = &qca99x0_values; + break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index cb09867b5533..e5fe33d9ca43 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -72,6 +72,43 @@ const struct ath10k_hw_regs qca6174_regs = { .pcie_intr_clr_address = 0x00000014, }; +const struct ath10k_hw_regs qca99x0_regs = { + .rtc_state_cold_reset_mask = 0x00000400, + .rtc_soc_base_address = 0x00080000, + .rtc_wmac_base_address = 0x00000000, + .soc_core_base_address = 0x00082000, + .ce_wrapper_base_address = 0x0004d000, + .ce0_base_address = 0x0004a000, + .ce1_base_address = 0x0004a400, + .ce2_base_address = 0x0004a800, + .ce3_base_address = 0x0004ac00, + .ce4_base_address = 0x0004b000, + .ce5_base_address = 0x0004b400, + .ce6_base_address = 0x0004b800, + .ce7_base_address = 0x0004bc00, + /* Note: qca99x0 supports upto 12 Copy Engines. Other than address of + * CE0 and CE1 no other copy engine is directly referred in the code. + * It is not really neccessary to assign address for newly supported + * CEs in this address table. + * Copy Engine Address + * CE8 0x0004c000 + * CE9 0x0004c400 + * CE10 0x0004c800 + * CE11 0x0004cc00 + */ + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00040050, + .fw_indicator_address = 0x00040050, + .pcie_local_base_address = 0x00000000, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, + .pcie_intr_ce_mask_all = 0x000fff00, + .pcie_intr_clr_address = 0x00000010, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, @@ -86,6 +123,13 @@ const struct ath10k_hw_values qca6174_values = { .num_target_ce_config_wlan = 7, }; +const struct ath10k_hw_values qca99x0_values = { + .rtc_state_val_on = 5, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 10, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5d04317cb3dc..76caeab5c7d3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -72,6 +72,18 @@ enum qca6174_chip_id_rev { #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 +/* QCA99X0 1.0 definitions (unsupported) */ +#define QCA99X0_HW_1_0_CHIP_ID_REV 0x0 + +/* QCA99X0 2.0 definitions */ +#define QCA99X0_HW_2_0_DEV_VERSION 0x01000000 +#define QCA99X0_HW_2_0_CHIP_ID_REV 0x1 +#define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0" +#define QCA99X0_HW_2_0_FW_FILE "firmware.bin" +#define QCA99X0_HW_2_0_OTP_FILE "otp.bin" +#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" +#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" @@ -144,6 +156,7 @@ enum ath10k_fw_htt_op_version { enum ath10k_hw_rev { ATH10K_HW_QCA988X, ATH10K_HW_QCA6174, + ATH10K_HW_QCA99X0, }; struct ath10k_hw_regs { @@ -175,6 +188,7 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +extern const struct ath10k_hw_regs qca99x0_regs; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -185,12 +199,14 @@ struct ath10k_hw_values { extern const struct ath10k_hw_values qca988x_values; extern const struct ath10k_hw_values qca6174_values; +extern const struct ath10k_hw_values qca99x0_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) +#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) /* Known pecularities: * - current FW doesn't support raw rx mode (last tested v599) @@ -485,6 +501,8 @@ enum ath10k_hw_rate_cck { #define DRAM_BASE_ADDRESS 0x00400000 +#define PCIE_BAR_REG_ADDRESS 0x40030 + #define MISSING 0 #define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 41765172297c..0007e7077f9c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -59,6 +59,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define QCA988X_2_0_DEVICE_ID (0x003c) #define QCA6174_2_1_DEVICE_ID (0x003e) +#define QCA99X0_2_0_DEVICE_ID (0x0040) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ @@ -1699,6 +1700,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) switch (ar_pci->pdev->device) { case QCA988X_2_0_DEVICE_ID: + case QCA99X0_2_0_DEVICE_ID: return 1; case QCA6174_2_1_DEVICE_ID: switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { @@ -2758,6 +2760,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; break; + case QCA99X0_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA99X0; + break; default: WARN_ON(1); return -ENOTSUPP; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index a417aae52623..768bef629099 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -450,4 +450,7 @@ Fw Mode/SubMode Mask #define QCA6174_BOARD_DATA_SZ 8192 #define QCA6174_BOARD_EXT_DATA_SZ 0 +#define QCA99X0_BOARD_DATA_SZ 12288 +#define QCA99X0_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ -- cgit v1.2.3-70-g09d2 From 050af069de03489947023544bfed1977952b8215 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:04 +0530 Subject: ath10k: Copy Engine related changes for QCA99X0 QCA99X0 supports upto 12 Copy engines. Host and target CE configuration table is updated to support new copy engine pipes. This also fixes the assumption of diagnostic CE by making CE_7 as the one instead of CE_COUNT - 1. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/hw.h | 3 ++ drivers/net/wireless/ath/ath10k/pci.c | 69 ++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 93939de2be19..bb4b8f3e7c5c 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -21,7 +21,7 @@ #include "hif.h" /* Maximum number of Copy Engine's supported */ -#define CE_COUNT_MAX 8 +#define CE_COUNT_MAX 12 #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 /* Descriptor rings must be aligned to this boundary */ diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 76caeab5c7d3..581965947594 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -343,6 +343,9 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +/* Diagnostic Window */ +#define CE_DIAG_PIPE 7 + #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan /* Number of Copy Engines supported */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0007e7077f9c..c2aecfe76544 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -156,6 +156,38 @@ static const struct ce_attr host_ce_config_wlan[] = { .src_sz_max = DIAG_TRANSFER_LIMIT, .dest_nentries = 2, }, + + /* CE8: target->host pktlog */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target autonomous qcache memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE10: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE11: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, }; /* Target firmware's Copy Engine configuration. */ @@ -233,6 +265,38 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { }, /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 target->host packtlog */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* It not necessary to send target wlan configuration for CE10 & CE11 + * as these CEs are not actively used in target. + */ }; /* @@ -1771,7 +1835,8 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr, target_ce_config_wlan, - sizeof(target_ce_config_wlan)); + sizeof(struct ce_pipe_config) * + NUM_TARGET_CE_CONFIG_WLAN); if (ret != 0) { ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); @@ -1885,7 +1950,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar) } /* Last CE is Diagnostic Window */ - if (i == CE_COUNT - 1) { + if (i == CE_DIAG_PIPE) { ar_pci->ce_diag = pipe->ce_hdl; continue; } -- cgit v1.2.3-70-g09d2 From 418ca5992e2f91050e0673b3a3a78197f0122bf8 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:05 +0530 Subject: ath10k: Make target cpu address to CE address conversion chip specific Make the helper converting target virtual address space to CE address space a target type specific to support QCA99X0. Also make this as function instead of macro. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/pci.h | 12 ------------ 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c2aecfe76544..df7d74e75149 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -755,6 +755,26 @@ static void ath10k_pci_rx_replenish_retry(unsigned long ptr) ath10k_pci_rx_post(ar); } +static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) +{ + u32 val = 0; + + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS) & + 0x7fff) << 21; + break; + case ATH10K_HW_QCA99X0: + val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); + break; + } + + val |= 0x100000 | (addr & 0xfffff); + return val; +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -817,8 +837,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * convert it from Target CPU virtual address space * to CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, - address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, 0); @@ -976,7 +995,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * to * CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); remaining_bytes = orig_nbytes; ce_data = ce_data_base; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index eea0a0170b00..8d364fb8f743 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -237,18 +237,6 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define CDC_WAR_MAGIC_STR 0xceef0000 #define CDC_WAR_DATA_CE 4 -/* - * TODO: Should be a function call specific to each Target-type. - * This convoluted macro converts from Target CPU Virtual Address Space to CE - * Address Space. As part of this process, we conservatively fetch the current - * PCIE_BAR. MOST of the time, this should match the upper bits of PCI space - * for this device; but that's not guaranteed. - */ -#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \ - (((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \ - CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \ - 0x100000 | ((addr) & 0xfffff)) - /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -- cgit v1.2.3-70-g09d2 From 6e4202c3ed301dea62885a3ead6506534fcf8db3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:06 +0530 Subject: ath10k: Add chip reset sequence for QCA99X0 QCA99X0 supports only cold reset. Also, made ath10k_pci_irq_msi_fw_mask() and ath10k_pci_irq_msi_fw_unmask() non-99X0 specific till we get proper register configuration to mask/unmask irq/MSI. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 81 ++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index df7d74e75149..1b4634a6374d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -82,7 +82,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); -static int ath10k_pci_warm_reset(struct ath10k *ar); +static int ath10k_pci_safe_chip_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -91,6 +91,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -1427,20 +1428,42 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val &= ~CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val &= ~CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to mask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val |= CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val |= CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to unmask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_disable(struct ath10k *ar) @@ -1602,7 +1625,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * masked. To prevent the device from asserting the interrupt reset it * before proceeding with cleanup. */ - ath10k_pci_warm_reset(ar); + ath10k_pci_safe_chip_reset(ar); ath10k_pci_irq_disable(ar); ath10k_pci_irq_sync(ar); @@ -2114,6 +2137,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_safe_chip_reset(struct ath10k *ar) +{ + if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) { + return ath10k_pci_warm_reset(ar); + } else if (QCA_REV_99X0(ar)) { + ath10k_pci_irq_disable(ar); + return ath10k_pci_qca99x0_chip_reset(ar); + } else { + return -ENOTSUPP; + } +} + static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) { int i, ret; @@ -2220,12 +2255,38 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n"); + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n"); + + return 0; +} + static int ath10k_pci_chip_reset(struct ath10k *ar) { if (QCA_REV_988X(ar)) return ath10k_pci_qca988x_chip_reset(ar); else if (QCA_REV_6174(ar)) return ath10k_pci_qca6174_chip_reset(ar); + else if (QCA_REV_99X0(ar)) + return ath10k_pci_qca99x0_chip_reset(ar); else return -ENOTSUPP; } -- cgit v1.2.3-70-g09d2 From 2adf99ca33ca75c8a702797f77a1652e26f18a6e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:07 +0530 Subject: ath10k: Extend CE src desc flags for interrupt indication QCA99X0 uses two new copy engine src desc flags for interrupt indication. Bit_2 is to mark if host interrupt is disabled after processing the current desc and bit_3 is to mark if target interrupt is diabled after the processing of current descriptor. CE_DESC_FLAGS_META_DATA_MASK and CE_DESC_FLAGS_META_DATA_LSB are based on the target type. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 1 + drivers/net/wireless/ath/ath10k/ce.h | 9 +++++++-- drivers/net/wireless/ath/ath10k/hw.c | 6 ++++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e508c65b6ba8..cf28fbebaedc 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -452,6 +452,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, { struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; + struct ath10k *ar = ce_state->ar; unsigned int sw_index = dest_ring->sw_index; struct ce_desc *base = dest_ring->base_addr_owner_space; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index bb4b8f3e7c5c..5c903e15dd65 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -38,8 +38,13 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) -#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC -#define CE_DESC_FLAGS_META_DATA_LSB 2 + +/* Following desc flags are used in QCA99X0 */ +#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2) +#define CE_DESC_FLAGS_TGT_INT_DIS (1 << 3) + +#define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask +#define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb struct ce_desc { __le32 addr; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index e5fe33d9ca43..1414e1f3c7ac 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -114,6 +114,8 @@ const struct ath10k_hw_values qca988x_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca6174_values = { @@ -121,6 +123,8 @@ const struct ath10k_hw_values qca6174_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca99x0_values = { @@ -128,6 +132,8 @@ const struct ath10k_hw_values qca99x0_values = { .ce_count = 12, .msi_assign_ce_max = 12, .num_target_ce_config_wlan = 10, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, }; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 581965947594..35cd8caaf738 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -195,6 +195,8 @@ struct ath10k_hw_values { u8 ce_count; u8 msi_assign_ce_max; u8 num_target_ce_config_wlan; + u16 ce_desc_meta_data_mask; + u8 ce_desc_meta_data_lsb; }; extern const struct ath10k_hw_values qca988x_values; -- cgit v1.2.3-70-g09d2 From fd3d6ffbd035d24b2baff0b5b39751183c289b33 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:08 +0530 Subject: ath10k: Fix BMI communication timeout for QCA99X0 There is more than 1 sec delay in getting response from target through BMI in QCA99X0. Increase the BMI communication timeout to 2*HZ to fix BMI failures. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 31a990635490..df7c7616533b 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -178,7 +178,7 @@ struct bmi_target_info { }; /* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ) +#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ) #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 -- cgit v1.2.3-70-g09d2 From dcb02db1068b78bd1b4d2bf64317021c2531a7b0 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:09 +0530 Subject: ath10k: Add support for code swap Code swap is a mechanism to use host memory to store some fw binary code segment. Ath10k host driver allocates and loads the code swap binary into the host memory and configures the target with the host allocated memory information at the address taken from code swap binary. This patch adds code swap support for firmware binary. Code swap binary for firmware bin is available in ATH10K_FW_IE_FW_CODE_SWAP_IMAGE. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 3 +- drivers/net/wireless/ath/ath10k/core.c | 24 ++++ drivers/net/wireless/ath/ath10k/core.h | 7 ++ drivers/net/wireless/ath/ath10k/hw.h | 3 + drivers/net/wireless/ath/ath10k/swap.c | 208 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/swap.h | 72 +++++++++++ 6 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/swap.c create mode 100644 drivers/net/wireless/ath/ath10k/swap.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 9729e6941635..c04fb00e7930 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -11,7 +11,8 @@ ath10k_core-y += mac.o \ wmi-tlv.o \ bmi.o \ hw.o \ - p2p.o + p2p.o \ + swap.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f239e9690831..c5f5d160deb7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -470,6 +470,13 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) data = ar->firmware_data; data_len = ar->firmware_len; mode_name = "normal"; + ret = ath10k_swap_code_seg_configure(ar, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); + if (ret) { + ath10k_err(ar, "failed to configure fw code swap: %d\n", + ret); + return ret; + } break; case ATH10K_FIRMWARE_MODE_UTF: data = ar->testmode.utf->data; @@ -509,6 +516,8 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (!IS_ERR(ar->cal_file)) release_firmware(ar->cal_file); + ath10k_swap_code_seg_release(ar); + ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; @@ -522,6 +531,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) ar->firmware_len = 0; ar->cal_file = NULL; + } static int ath10k_fetch_cal_file(struct ath10k *ar) @@ -795,6 +805,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n", ar->htt.op_version); break; + case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE: + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "found fw code swap image ie (%zd B)\n", + ie_len); + ar->swap.firmware_codeswap_data = data; + ar->swap.firmware_codeswap_len = ie_len; + break; default: ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); @@ -1388,6 +1405,13 @@ static int ath10k_core_probe_fw(struct ath10k *ar) goto err_free_firmware_files; } + ret = ath10k_swap_code_seg_init(ar); + if (ret) { + ath10k_err(ar, "failed to initialize code swap segment: %d\n", + ret); + goto err_free_firmware_files; + } + mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 993cd362fb0a..b9145f539aa9 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -36,6 +36,7 @@ #include "spectral.h" #include "thermal.h" #include "wow.h" +#include "swap.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -603,6 +604,12 @@ struct ath10k { const struct firmware *cal_file; + struct { + const void *firmware_codeswap_data; + size_t firmware_codeswap_len; + struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; + } swap; + char spec_board_id[100]; bool spec_board_loaded; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 35cd8caaf738..3e277814ce93 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -124,6 +124,9 @@ enum ath10k_fw_ie_type { * FW API 5 and above. */ ATH10K_FW_IE_HTT_OP_VERSION = 6, + + /* Code swap image for firmware binary */ + ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7, }; enum ath10k_fw_wmi_op_version { diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c new file mode 100644 index 000000000000..3ca3fae408a7 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.c @@ -0,0 +1,208 @@ +/* + * 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. + */ + +/* This file has implementation for code swap logic. With code swap feature, + * target can run the fw binary with even smaller IRAM size by using host + * memory to store some of the code segments. + */ + +#include "core.h" +#include "bmi.h" +#include "debug.h" + +static int ath10k_swap_code_seg_fill(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info, + const void *data, size_t data_len) +{ + u8 *virt_addr = seg_info->virt_address[0]; + u8 swap_magic[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ] = {}; + const u8 *fw_data = data; + union ath10k_swap_code_seg_item *swap_item; + u32 length = 0; + u32 payload_len; + u32 total_payload_len = 0; + u32 size_left = data_len; + + /* Parse swap bin and copy the content to host allocated memory. + * The format is Address, length and value. The last 4-bytes is + * target write address. Currently address field is not used. + */ + seg_info->target_addr = -1; + while (size_left >= sizeof(*swap_item)) { + swap_item = (union ath10k_swap_code_seg_item *)fw_data; + payload_len = __le32_to_cpu(swap_item->tlv.length); + if ((payload_len > size_left) || + (payload_len == 0 && + size_left != sizeof(struct ath10k_swap_code_seg_tail))) { + ath10k_err(ar, "refusing to parse invalid tlv length %d\n", + payload_len); + return -EINVAL; + } + + if (payload_len == 0) { + if (memcmp(swap_item->tail.magic_signature, swap_magic, + ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ)) { + ath10k_err(ar, "refusing an invalid swap file\n"); + return -EINVAL; + } + seg_info->target_addr = + __le32_to_cpu(swap_item->tail.bmi_write_addr); + break; + } + + memcpy(virt_addr, swap_item->tlv.data, payload_len); + virt_addr += payload_len; + length = payload_len + sizeof(struct ath10k_swap_code_seg_tlv); + size_left -= length; + fw_data += length; + total_payload_len += payload_len; + } + + if (seg_info->target_addr == -1) { + ath10k_err(ar, "failed to parse invalid swap file\n"); + return -EINVAL; + } + seg_info->seg_hw_info.swap_size = __cpu_to_le32(total_payload_len); + + return 0; +} + +static void +ath10k_swap_code_seg_free(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info) +{ + u32 seg_size; + + if (!seg_info) + return; + + if (!seg_info->virt_address[0]) + return; + + seg_size = __le32_to_cpu(seg_info->seg_hw_info.size); + dma_free_coherent(ar->dev, seg_size, seg_info->virt_address[0], + seg_info->paddr[0]); +} + +static struct ath10k_swap_code_seg_info * +ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) +{ + struct ath10k_swap_code_seg_info *seg_info; + void *virt_addr; + dma_addr_t paddr; + + swap_bin_len = roundup(swap_bin_len, 2); + if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) { + ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n", + swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX); + return NULL; + } + + seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL); + if (!seg_info) + return NULL; + + virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr, + GFP_KERNEL); + if (!virt_addr) { + ath10k_err(ar, "failed to allocate dma coherent memory\n"); + return NULL; + } + + seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr); + seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.num_segs = + __cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED); + seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len)); + seg_info->virt_address[0] = virt_addr; + seg_info->paddr[0] = paddr; + + return seg_info; +} + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info = NULL; + + switch (type) { + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW: + if (!ar->swap.firmware_swap_code_seg_info) + return 0; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n"); + seg_info = ar->swap.firmware_swap_code_seg_info; + break; + default: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF: + ath10k_warn(ar, "ignoring unknown code swap binary type %d\n", + type); + return 0; + } + + ret = ath10k_bmi_write_memory(ar, seg_info->target_addr, + &seg_info->seg_hw_info, + sizeof(seg_info->seg_hw_info)); + if (ret) { + ath10k_err(ar, "failed to write Code swap segment information (%d)\n", + ret); + return ret; + } + + return 0; +} + +void ath10k_swap_code_seg_release(struct ath10k *ar) +{ + ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info); + ar->swap.firmware_codeswap_data = NULL; + ar->swap.firmware_codeswap_len = 0; + ar->swap.firmware_swap_code_seg_info = NULL; +} + +int ath10k_swap_code_seg_init(struct ath10k *ar) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info; + + if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data) + return 0; + + seg_info = ath10k_swap_code_seg_alloc(ar, + ar->swap.firmware_codeswap_len); + if (!seg_info) { + ath10k_err(ar, "failed to allocate fw code swap segment\n"); + return -ENOMEM; + } + + ret = ath10k_swap_code_seg_fill(ar, seg_info, + ar->swap.firmware_codeswap_data, + ar->swap.firmware_codeswap_len); + + if (ret) { + ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n", + ret); + ath10k_swap_code_seg_free(ar, seg_info); + return ret; + } + + ar->swap.firmware_swap_code_seg_info = seg_info; + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/swap.h b/drivers/net/wireless/ath/ath10k/swap.h new file mode 100644 index 000000000000..5c89952dd20f --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef _SWAP_H_ +#define _SWAP_H_ + +#define ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX (512 * 1024) +#define ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ 12 +#define ATH10K_SWAP_CODE_SEG_NUM_MAX 16 +/* Currently only one swap segment is supported */ +#define ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED 1 + +struct ath10k_swap_code_seg_tlv { + __le32 address; + __le32 length; + u8 data[0]; +} __packed; + +struct ath10k_swap_code_seg_tail { + u8 magic_signature[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ]; + __le32 bmi_write_addr; +} __packed; + +union ath10k_swap_code_seg_item { + struct ath10k_swap_code_seg_tlv tlv; + struct ath10k_swap_code_seg_tail tail; +} __packed; + +enum ath10k_swap_code_seg_bin_type { + ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF, +}; + +struct ath10k_swap_code_seg_hw_info { + /* Swap binary image size */ + __le32 swap_size; + __le32 num_segs; + + /* Swap data size */ + __le32 size; + __le32 size_log2; + __le32 bus_addr[ATH10K_SWAP_CODE_SEG_NUM_MAX]; + __le64 reserved[ATH10K_SWAP_CODE_SEG_NUM_MAX]; +} __packed; + +struct ath10k_swap_code_seg_info { + struct ath10k_swap_code_seg_hw_info seg_hw_info; + void *virt_address[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; + u32 target_addr; + dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; +}; + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type); +void ath10k_swap_code_seg_release(struct ath10k *ar); +int ath10k_swap_code_seg_init(struct ath10k *ar); + +#endif -- cgit v1.2.3-70-g09d2 From d772703e705961dc4bd280373e3679c8c4f95df7 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:10 +0530 Subject: ath10k: Add BMI param value to execute otp to hw_param BMI parameter value to execute downloaded otp binary is different for QCA99X0. Have a member in hw_params to hold hw specific BMI param. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 +++++++- drivers/net/wireless/ath/ath10k/core.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c5f5d160deb7..80f38b50296b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -49,6 +49,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .has_shifted_cc_wraparound = true, + .otp_exe_param = 0, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -63,6 +64,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, .fw = QCA6174_HW_2_1_FW_FILE, @@ -77,6 +79,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, .fw = QCA6174_HW_3_0_FW_FILE, @@ -91,6 +94,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { /* uses same binaries as hw3.0 */ .dir = QCA6174_HW_3_0_FW_DIR, @@ -106,6 +110,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .otp_exe_param = 0x00000700, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, @@ -413,6 +418,7 @@ out: static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; int ret; ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); @@ -438,7 +444,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, 0, &result); + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index b9145f539aa9..afd21d5b25ae 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -572,6 +572,7 @@ struct ath10k { const char *name; u32 patch_load_addr; int uart_pin; + u32 otp_exe_param; /* This is true if given HW chip has a quirky Cycle Counter * wraparound which resets to 0x7fffffff instead of 0. All -- cgit v1.2.3-70-g09d2 From 9bd213224654b8c13af8bffcf9bd07ee0baae5ef Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:09 +0530 Subject: ath10k: include new wmi op version for 10.4 fw qca99X0 chip uses firmware version 10.4. Define a new macro ATH10K_FW_WMI_OP_VERSION_10_4 for 10.4 firmware and include in switch cases where ATH10K_FW_WMI_OP_VERSION_* is used to avoid compilation error. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++ 4 files changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 80f38b50296b..5e8d8af5d0d0 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1115,6 +1115,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); @@ -1137,6 +1138,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 3e277814ce93..b0c89b48092d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -137,6 +137,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_10_2 = 3, ATH10K_FW_WMI_OP_VERSION_TLV = 4, ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, + ATH10K_FW_WMI_OP_VERSION_10_4 = 6, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e17eb75c508e..a8561d1f26e3 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6943,6 +6943,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_10x_if_comb); break; + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c046c244705..b32bb6825f3c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5415,6 +5415,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; ar->wmi.ops = &wmi_10_2_4_ops; -- cgit v1.2.3-70-g09d2 From 840357ccc365b650d2321a5690cb5374192619ca Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:10 +0530 Subject: ath10k: add 10.4 fw wmi service bitmap definition Include new enum to define wmi service bitmap definitions for 10.4 firmware and a function wmi_10_4_svc_map() to remap 10.4 firmware wmi service bitmap definitions to ath10k generic wmi services. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 5 ++ drivers/net/wireless/ath/ath10k/wmi.h | 146 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b32bb6825f3c..52493d14c9b0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5412,10 +5412,15 @@ static const struct wmi_ops wmi_10_2_4_ops = { /* .gen_adaptive_qcs not implemented */ }; +static const struct wmi_ops wmi_10_4_ops = { + .map_svc = wmi_10_4_svc_map, +}; + int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->wmi.ops = &wmi_10_4_ops; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cf44a3d080a3..b54d14b00819 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -150,6 +150,12 @@ enum wmi_service { WMI_SERVICE_SAP_AUTH_OFFLOAD, WMI_SERVICE_ATF, WMI_SERVICE_COEX_GPIO, + WMI_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_TT, + WMI_SERVICE_PEER_CACHING, + WMI_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_BSS_CHANNEL_INFO_64, /* keep last */ WMI_SERVICE_MAX, @@ -218,6 +224,51 @@ enum wmi_main_service { WMI_MAIN_SERVICE_TX_ENCAP, }; +enum wmi_10_4_service { + WMI_10_4_SERVICE_BEACON_OFFLOAD = 0, + WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_10_4_SERVICE_AP_UAPSD, + WMI_10_4_SERVICE_AP_DFS, + WMI_10_4_SERVICE_11AC, + WMI_10_4_SERVICE_BLOCKACK, + WMI_10_4_SERVICE_PHYERR, + WMI_10_4_SERVICE_BCN_FILTER, + WMI_10_4_SERVICE_RTT, + WMI_10_4_SERVICE_RATECTRL, + WMI_10_4_SERVICE_WOW, + WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_10_4_SERVICE_IRAM_TIDS, + WMI_10_4_SERVICE_BURST, + WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_10_4_SERVICE_SCAN_SCH, + WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_10_4_SERVICE_CHATTER, + WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_10_4_SERVICE_GPIO, + WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_10_4_SERVICE_TX_ENCAP, + WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_10_4_SERVICE_EARLY_RX, + WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_10_4_SERVICE_TT, + WMI_10_4_SERVICE_ATF, + WMI_10_4_SERVICE_PEER_CACHING, + WMI_10_4_SERVICE_COEX_GPIO, + WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, +}; + static inline char *wmi_service_name(int service_id) { #define SVCSTR(x) case x: return #x @@ -299,6 +350,12 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); SVCSTR(WMI_SERVICE_ATF); SVCSTR(WMI_SERVICE_COEX_GPIO); + SVCSTR(WMI_SERVICE_ENHANCED_PROXY_STA); + SVCSTR(WMI_SERVICE_TT); + SVCSTR(WMI_SERVICE_PEER_CACHING); + SVCSTR(WMI_SERVICE_AUX_SPECTRAL_INTF); + SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); + SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); default: return NULL; } @@ -437,6 +494,95 @@ static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TX_ENCAP, len); } +static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, + size_t len) +{ + SVCMAP(WMI_10_4_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_10_4_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_10_4_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_10_4_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_10_4_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_10_4_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_10_4_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL, + WMI_SERVICE_RATECTRL, len); + SVCMAP(WMI_10_4_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_10_4_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_10_4_SERVICE_BURST, + WMI_SERVICE_BURST, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GPIO, + WMI_SERVICE_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE, len); + SVCMAP(WMI_10_4_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP, len); + SVCMAP(WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); + SVCMAP(WMI_10_4_SERVICE_EARLY_RX, + WMI_SERVICE_EARLY_RX, len); + SVCMAP(WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_ENHANCED_PROXY_STA, len); + SVCMAP(WMI_10_4_SERVICE_TT, + WMI_SERVICE_TT, len); + SVCMAP(WMI_10_4_SERVICE_ATF, + WMI_SERVICE_ATF, len); + SVCMAP(WMI_10_4_SERVICE_PEER_CACHING, + WMI_SERVICE_PEER_CACHING, len); + SVCMAP(WMI_10_4_SERVICE_COEX_GPIO, + WMI_SERVICE_COEX_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_SPECTRAL_INTF, len); + SVCMAP(WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, len); + SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, + WMI_SERVICE_BSS_CHANNEL_INFO_64, len); +} + #undef SVCMAP /* 2 word representation of MAC addr */ -- cgit v1.2.3-70-g09d2 From 2d491e69962a94bbeb0449a060cca2d156f943e9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:11 +0530 Subject: ath10k: include 10.4 fw specific wmi cmd and event ids 10.4 firmware wmi cmd and event id values are not exactly aligned with previous firmware versions (main, 10.x, 10.2, etc). Add new enum to define wmi cmd & event definitions for 10.4 firmware and prepare wmi_10_4_cmd_map based on 10.4 firmware wmi cmd definitions. wmi_cmd_map is extended to accommodate new wmi commands which are exclusively available in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 184 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 252 ++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 52493d14c9b0..8dc937de98ab 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -395,6 +395,189 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, }; +/* 10.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_4_cmd_map = { + .init_cmdid = WMI_10_4_INIT_CMDID, + .start_scan_cmdid = WMI_10_4_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + .pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_dscp_tid_map_cmdid = WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_4_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_4_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_4_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_4_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_4_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_4_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_4_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_4_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_4_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_4_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_4_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_4_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_4_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_4_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_4_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_4_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_10_4_BCN_PRB_TMPL_CMDID, + .bcn_filter_rx_cmdid = WMI_10_4_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_4_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_10_4_PRB_TMPL_CMDID, + .addba_clear_resp_cmdid = WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_4_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_4_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_4_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_4_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_4_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_4_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_4_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_4_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_4_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_4_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_4_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_4_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_4_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_4_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + .ap_ps_peer_param_cmdid = WMI_10_4_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + .peer_rate_retry_sched_cmdid = WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_4_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_4_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_4_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_4_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_4_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_4_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_4_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_4_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_10_4_GTK_OFFLOAD_CMDID, + .csa_offload_enable_cmdid = WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + .csa_offload_chanswitch_cmdid = WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_4_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_4_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_4_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_4_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + .vdev_get_keepalive_cmdid = WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + .force_fw_hang_cmdid = WMI_10_4_FORCE_FW_HANG_CMDID, + .gpio_config_cmdid = WMI_10_4_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_4_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + .vdev_set_wmm_params_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_set_state_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_peer_update_cmdid = WMI_CMD_UNSUPPORTED, + .adaptive_qcs_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + .vdev_standby_response_cmdid = WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + .vdev_resume_response_cmdid = WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + .wlan_peer_caching_add_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + .wlan_peer_caching_evict_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + .wlan_peer_caching_restore_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + .wlan_peer_caching_print_all_peers_info_cmdid = + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + .peer_update_wds_entry_cmdid = WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + .peer_add_proxy_sta_entry_cmdid = + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + .rtt_keepalive_cmdid = WMI_10_4_RTT_KEEPALIVE_CMDID, + .oem_req_cmdid = WMI_10_4_OEM_REQ_CMDID, + .nan_cmdid = WMI_10_4_NAN_CMDID, + .vdev_ratemask_cmdid = WMI_10_4_VDEV_RATEMASK_CMDID, + .qboost_cfg_cmdid = WMI_10_4_QBOOST_CFG_CMDID, + .pdev_smart_ant_enable_cmdid = WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + .pdev_smart_ant_set_rx_antenna_cmdid = + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + .peer_smart_ant_set_tx_antenna_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + .peer_smart_ant_set_train_info_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + .peer_smart_ant_set_node_config_ops_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + .pdev_set_antenna_switch_table_cmdid = + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + .pdev_set_ctl_table_cmdid = WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + .pdev_set_mimogain_table_cmdid = WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + .pdev_ratepwr_table_cmdid = WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + .pdev_ratepwr_chainmsk_table_cmdid = + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + .pdev_fips_cmdid = WMI_10_4_PDEV_FIPS_CMDID, + .tt_set_conf_cmdid = WMI_10_4_TT_SET_CONF_CMDID, + .fwtest_cmdid = WMI_10_4_FWTEST_CMDID, + .vdev_atf_request_cmdid = WMI_10_4_VDEV_ATF_REQUEST_CMDID, + .peer_atf_request_cmdid = WMI_10_4_PEER_ATF_REQUEST_CMDID, + .pdev_get_ani_cck_config_cmdid = WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + .pdev_get_ani_ofdm_config_cmdid = + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + .pdev_reserve_ast_entry_cmdid = WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + .pdev_get_nfcal_power_cmdid = WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + .pdev_get_tpc_cmdid = WMI_10_4_PDEV_GET_TPC_CMDID, + .pdev_get_ast_info_cmdid = WMI_10_4_PDEV_GET_AST_INFO_CMDID, + .vdev_set_dscp_tid_map_cmdid = WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_get_info_cmdid = WMI_10_4_PDEV_GET_INFO_CMDID, + .vdev_get_info_cmdid = WMI_10_4_VDEV_GET_INFO_CMDID, + .vdev_filter_neighbor_rx_packets_cmdid = + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + .mu_cal_start_cmdid = WMI_10_4_MU_CAL_START_CMDID, + .set_cca_params_cmdid = WMI_10_4_SET_CCA_PARAMS_CMDID, + .pdev_bss_chan_info_request_cmdid = + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -5421,6 +5604,7 @@ int ath10k_wmi_attach(struct ath10k *ar) switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; + ar->wmi.cmd = &wmi_10_4_cmd_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b54d14b00819..c3a05a9a05ae 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -711,6 +711,48 @@ struct wmi_cmd_map { u32 tdls_set_state_cmdid; u32 tdls_peer_update_cmdid; u32 adaptive_qcs_cmdid; + u32 scan_update_request_cmdid; + u32 vdev_standby_response_cmdid; + u32 vdev_resume_response_cmdid; + u32 wlan_peer_caching_add_peer_cmdid; + u32 wlan_peer_caching_evict_peer_cmdid; + u32 wlan_peer_caching_restore_peer_cmdid; + u32 wlan_peer_caching_print_all_peers_info_cmdid; + u32 peer_update_wds_entry_cmdid; + u32 peer_add_proxy_sta_entry_cmdid; + u32 rtt_keepalive_cmdid; + u32 oem_req_cmdid; + u32 nan_cmdid; + u32 vdev_ratemask_cmdid; + u32 qboost_cfg_cmdid; + u32 pdev_smart_ant_enable_cmdid; + u32 pdev_smart_ant_set_rx_antenna_cmdid; + u32 peer_smart_ant_set_tx_antenna_cmdid; + u32 peer_smart_ant_set_train_info_cmdid; + u32 peer_smart_ant_set_node_config_ops_cmdid; + u32 pdev_set_antenna_switch_table_cmdid; + u32 pdev_set_ctl_table_cmdid; + u32 pdev_set_mimogain_table_cmdid; + u32 pdev_ratepwr_table_cmdid; + u32 pdev_ratepwr_chainmsk_table_cmdid; + u32 pdev_fips_cmdid; + u32 tt_set_conf_cmdid; + u32 fwtest_cmdid; + u32 vdev_atf_request_cmdid; + u32 peer_atf_request_cmdid; + u32 pdev_get_ani_cck_config_cmdid; + u32 pdev_get_ani_ofdm_config_cmdid; + u32 pdev_reserve_ast_entry_cmdid; + u32 pdev_get_nfcal_power_cmdid; + u32 pdev_get_tpc_cmdid; + u32 pdev_get_ast_info_cmdid; + u32 vdev_set_dscp_tid_map_cmdid; + u32 pdev_get_info_cmdid; + u32 vdev_get_info_cmdid; + u32 vdev_filter_neighbor_rx_packets_cmdid; + u32 mu_cal_start_cmdid; + u32 set_cca_params_cmdid; + u32 pdev_bss_chan_info_request_cmdid; }; /* @@ -1366,6 +1408,216 @@ enum wmi_10_2_event_id { WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, }; +enum wmi_10_4_cmd_id { + WMI_10_4_START_CMDID = 0x9000, + WMI_10_4_END_CMDID = 0x9FFF, + WMI_10_4_INIT_CMDID, + WMI_10_4_START_SCAN_CMDID = WMI_10_4_START_CMDID, + WMI_10_4_STOP_SCAN_CMDID, + WMI_10_4_SCAN_CHAN_LIST_CMDID, + WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + WMI_10_4_ECHO_CMDID, + WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + WMI_10_4_PDEV_SET_CHANNEL_CMDID, + WMI_10_4_PDEV_SET_PARAM_CMDID, + WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + WMI_10_4_VDEV_CREATE_CMDID, + WMI_10_4_VDEV_DELETE_CMDID, + WMI_10_4_VDEV_START_REQUEST_CMDID, + WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + WMI_10_4_VDEV_UP_CMDID, + WMI_10_4_VDEV_STOP_CMDID, + WMI_10_4_VDEV_DOWN_CMDID, + WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + WMI_10_4_VDEV_SET_PARAM_CMDID, + WMI_10_4_VDEV_INSTALL_KEY_CMDID, + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + WMI_10_4_PEER_CREATE_CMDID, + WMI_10_4_PEER_DELETE_CMDID, + WMI_10_4_PEER_FLUSH_TIDS_CMDID, + WMI_10_4_PEER_SET_PARAM_CMDID, + WMI_10_4_PEER_ASSOC_CMDID, + WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + WMI_10_4_PEER_MCAST_GROUP_CMDID, + WMI_10_4_BCN_TX_CMDID, + WMI_10_4_PDEV_SEND_BCN_CMDID, + WMI_10_4_BCN_PRB_TMPL_CMDID, + WMI_10_4_BCN_FILTER_RX_CMDID, + WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + WMI_10_4_MGMT_TX_CMDID, + WMI_10_4_PRB_TMPL_CMDID, + WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + WMI_10_4_ADDBA_SEND_CMDID, + WMI_10_4_ADDBA_STATUS_CMDID, + WMI_10_4_DELBA_SEND_CMDID, + WMI_10_4_ADDBA_SET_RESP_CMDID, + WMI_10_4_SEND_SINGLEAMSDU_CMDID, + WMI_10_4_STA_POWERSAVE_MODE_CMDID, + WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + WMI_10_4_STA_MIMO_PS_MODE_CMDID, + WMI_10_4_DBGLOG_CFG_CMDID, + WMI_10_4_PDEV_DFS_ENABLE_CMDID, + WMI_10_4_PDEV_DFS_DISABLE_CMDID, + WMI_10_4_PDEV_QVIT_CMDID, + WMI_10_4_ROAM_SCAN_MODE, + WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + WMI_10_4_ROAM_SCAN_PERIOD, + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_10_4_ROAM_AP_PROFILE, + WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_10_4_OFL_SCAN_PERIOD, + WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + WMI_10_4_P2P_GO_SET_BEACON_IE, + WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + WMI_10_4_AP_PS_PEER_PARAM_CMDID, + WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_10_4_PDEV_SUSPEND_CMDID, + WMI_10_4_PDEV_RESUME_CMDID, + WMI_10_4_ADD_BCN_FILTER_CMDID, + WMI_10_4_RMV_BCN_FILTER_CMDID, + WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_10_4_WOW_ENABLE_CMDID, + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_10_4_RTT_MEASREQ_CMDID, + WMI_10_4_RTT_TSF_CMDID, + WMI_10_4_RTT_KEEPALIVE_CMDID, + WMI_10_4_OEM_REQ_CMDID, + WMI_10_4_NAN_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_10_4_REQUEST_STATS_CMDID, + WMI_10_4_GPIO_CONFIG_CMDID, + WMI_10_4_GPIO_OUTPUT_CMDID, + WMI_10_4_VDEV_RATEMASK_CMDID, + WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + WMI_10_4_GTK_OFFLOAD_CMDID, + WMI_10_4_QBOOST_CFG_CMDID, + WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + WMI_10_4_FORCE_FW_HANG_CMDID, + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_4_PDEV_FIPS_CMDID, + WMI_10_4_TT_SET_CONF_CMDID, + WMI_10_4_FWTEST_CMDID, + WMI_10_4_VDEV_ATF_REQUEST_CMDID, + WMI_10_4_PEER_ATF_REQUEST_CMDID, + WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + WMI_10_4_PDEV_GET_TPC_CMDID, + WMI_10_4_PDEV_GET_AST_INFO_CMDID, + WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + WMI_10_4_PDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + WMI_10_4_MU_CAL_START_CMDID, + WMI_10_4_SET_CCA_PARAMS_CMDID, + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, + WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, +}; + +enum wmi_10_4_event_id { + WMI_10_4_SERVICE_READY_EVENTID = 0x8000, + WMI_10_4_READY_EVENTID, + WMI_10_4_DEBUG_MESG_EVENTID, + WMI_10_4_START_EVENTID = 0x9000, + WMI_10_4_END_EVENTID = 0x9FFF, + WMI_10_4_SCAN_EVENTID = WMI_10_4_START_EVENTID, + WMI_10_4_ECHO_EVENTID, + WMI_10_4_UPDATE_STATS_EVENTID, + WMI_10_4_INST_RSSI_STATS_EVENTID, + WMI_10_4_VDEV_START_RESP_EVENTID, + WMI_10_4_VDEV_STANDBY_REQ_EVENTID, + WMI_10_4_VDEV_RESUME_REQ_EVENTID, + WMI_10_4_VDEV_STOPPED_EVENTID, + WMI_10_4_PEER_STA_KICKOUT_EVENTID, + WMI_10_4_HOST_SWBA_EVENTID, + WMI_10_4_TBTTOFFSET_UPDATE_EVENTID, + WMI_10_4_MGMT_RX_EVENTID, + WMI_10_4_CHAN_INFO_EVENTID, + WMI_10_4_PHYERR_EVENTID, + WMI_10_4_ROAM_EVENTID, + WMI_10_4_PROFILE_MATCH, + WMI_10_4_DEBUG_PRINT_EVENTID, + WMI_10_4_PDEV_QVIT_EVENTID, + WMI_10_4_WLAN_PROFILE_DATA_EVENTID, + WMI_10_4_RTT_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_RTT_ERROR_REPORT_EVENTID, + WMI_10_4_RTT_KEEPALIVE_EVENTID, + WMI_10_4_OEM_CAPABILITY_EVENTID, + WMI_10_4_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_OEM_ERROR_REPORT_EVENTID, + WMI_10_4_NAN_EVENTID, + WMI_10_4_WOW_WAKEUP_HOST_EVENTID, + WMI_10_4_GTK_OFFLOAD_STATUS_EVENTID, + WMI_10_4_GTK_REKEY_FAIL_EVENTID, + WMI_10_4_DCS_INTERFERENCE_EVENTID, + WMI_10_4_PDEV_TPC_CONFIG_EVENTID, + WMI_10_4_CSA_HANDLING_EVENTID, + WMI_10_4_GPIO_INPUT_EVENTID, + WMI_10_4_PEER_RATECODE_LIST_EVENTID, + WMI_10_4_GENERIC_BUFFER_EVENTID, + WMI_10_4_MCAST_BUF_RELEASE_EVENTID, + WMI_10_4_MCAST_LIST_AGEOUT_EVENTID, + WMI_10_4_VDEV_GET_KEEPALIVE_EVENTID, + WMI_10_4_WDS_PEER_EVENTID, + WMI_10_4_PEER_STA_PS_STATECHG_EVENTID, + WMI_10_4_PDEV_FIPS_EVENTID, + WMI_10_4_TT_STATS_EVENTID, + WMI_10_4_PDEV_CHANNEL_HOPPING_EVENTID, + WMI_10_4_PDEV_ANI_CCK_LEVEL_EVENTID, + WMI_10_4_PDEV_ANI_OFDM_LEVEL_EVENTID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_EVENTID, + WMI_10_4_PDEV_TPC_EVENTID, + WMI_10_4_PDEV_GET_AST_INFO_EVENTID, + WMI_10_4_PDEV_TEMPERATURE_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, + WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID, + WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, +}; + enum wmi_phy_mode { MODE_11A = 0, /* 11a Mode */ MODE_11G = 1, /* 11b/g Mode */ -- cgit v1.2.3-70-g09d2 From 772b4aeee51a851132abf799de8c07cfbe95ac00 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:12 +0530 Subject: ath10k: set 10.4 fw exclusive wmi cmd as unsupported for other fw versions In fact, explicit assigned to ZERO for unsupported wmi commands are not really needed. Global static variable will have ZERO by default. However, just for better readability setting all wmi cmds in non 10.4 firmware wmi mapping table as unsupported for wmi cmd which are exclusively available only in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 32 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 158 ++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 8fdba3865c96..7e75dec5b4fb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3151,6 +3151,38 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID, .adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 8dc937de98ab..a58ddb74ac3b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -148,6 +148,48 @@ static struct wmi_cmd_map wmi_cmd_map = { .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -271,6 +313,48 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -393,6 +477,48 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.4 WMI cmd track */ @@ -1032,6 +1158,38 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, -- cgit v1.2.3-70-g09d2 From 93841a15cce206450cdb31fe9b3f6b00342afe2b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:13 +0530 Subject: ath10k: add 10.4 fw wmi vdev cmd ids Include 10.4 firmware wmi vdev cmd id and make up wmi vdev map table wmi_10_4_vdev_param_map and also update non 10.4 firmware vdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 16 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 124 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 85 ++++++++++++++++++++ 3 files changed, 225 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7e75dec5b4fb..b2a8e327a551 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3294,6 +3294,22 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_TLV_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static const struct wmi_ops wmi_tlv_ops = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a58ddb74ac3b..087dea85ef7c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -761,6 +761,22 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; /* 10.X WMI VDEV param map */ @@ -820,6 +836,22 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { @@ -878,6 +910,97 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { + .rts_threshold = WMI_10_4_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_10_4_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_10_4_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_10_4_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_10_4_VDEV_PARAM_WDS, + .atim_window = WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + .bmiss_final_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + .feature_wmm = WMI_10_4_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_10_4_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_10_4_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_10_4_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_10_4_VDEV_PARAM_SGI, + .ldpc = WMI_10_4_VDEV_PARAM_LDPC, + .tx_stbc = WMI_10_4_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_10_4_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_10_4_VDEV_PARAM_DEF_KEYID, + .nss = WMI_10_4_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + .enable_rtscts = WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_10_4_VDEV_PARAM_TXBF, + .packet_powersave = WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + .drop_unencry = WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + .tx_encap_type = WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + .cabq_maxdur = WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + .mfptest_set = WMI_10_4_VDEV_PARAM_MFPTEST_SET, + .rts_fixed_rate = WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + .vht_sgimask = WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + .vht80_ratemask = WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + .early_rx_adjust_enable = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + .early_rx_tgt_bmiss_num = WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + .early_rx_bmiss_sample_cycle = + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + .early_rx_slop_step = WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + .early_rx_init_slop = WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + .early_rx_adjust_pause = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + .proxy_sta = WMI_10_4_VDEV_PARAM_PROXY_STA, + .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, + .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, }; static struct wmi_pdev_param_map wmi_pdev_param_map = { @@ -5763,6 +5886,7 @@ int ath10k_wmi_attach(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; + ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c3a05a9a05ae..ecc7288ff119 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3904,6 +3904,22 @@ struct wmi_vdev_param_map { u32 drop_unencry; u32 tx_encap_type; u32 ap_detect_out_of_sync_sleeping_sta_time_secs; + u32 rc_num_retries; + u32 cabq_maxdur; + u32 mfptest_set; + u32 rts_fixed_rate; + u32 vht_sgimask; + u32 vht80_ratemask; + u32 early_rx_adjust_enable; + u32 early_rx_tgt_bmiss_num; + u32 early_rx_bmiss_sample_cycle; + u32 early_rx_slop_step; + u32 early_rx_init_slop; + u32 early_rx_adjust_pause; + u32 proxy_sta; + u32 meru_vc; + u32 rx_decap_type; + u32 bw_nss_ratemask; }; #define WMI_VDEV_PARAM_UNSUPPORTED 0 @@ -4162,6 +4178,75 @@ enum wmi_10x_vdev_param { WMI_10X_VDEV_PARAM_VHT80_RATEMASK, }; +enum wmi_10_4_vdev_param { + WMI_10_4_VDEV_PARAM_RTS_THRESHOLD = 0x1, + WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + WMI_10_4_VDEV_PARAM_SLOT_TIME, + WMI_10_4_VDEV_PARAM_PREAMBLE, + WMI_10_4_VDEV_PARAM_SWBA_TIME, + WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + WMI_10_4_VDEV_PARAM_WDS, + WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + WMI_10_4_VDEV_PARAM_FEATURE_WMM, + WMI_10_4_VDEV_PARAM_CHWIDTH, + WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + WMI_10_4_VDEV_PARAM_MGMT_RATE, + WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + WMI_10_4_VDEV_PARAM_FIXED_RATE, + WMI_10_4_VDEV_PARAM_SGI, + WMI_10_4_VDEV_PARAM_LDPC, + WMI_10_4_VDEV_PARAM_TX_STBC, + WMI_10_4_VDEV_PARAM_RX_STBC, + WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + WMI_10_4_VDEV_PARAM_DEF_KEYID, + WMI_10_4_VDEV_PARAM_NSS, + WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + WMI_10_4_VDEV_PARAM_TXBF, + WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + WMI_10_4_VDEV_PARAM_MFPTEST_SET, + WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + WMI_10_4_VDEV_PARAM_PROXY_STA, + WMI_10_4_VDEV_PARAM_MERU_VC, + WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, +}; + #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) -- cgit v1.2.3-70-g09d2 From d86561ff677b312424ba53389be80b507941973b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:14 +0530 Subject: ath10k: add 10.4 fw wmi pdev cmd ids Include 10.4 firmware wmi pdev cmd id and prepare wmi vdev map table wmi_10_4_pdev_param_map and update non 10.4 firmware pdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 42 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 228 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 136 ++++++++++++++++++ 3 files changed, 406 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b2a8e327a551..620b37b59784 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3236,6 +3236,48 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 087dea85ef7c..3f29886dc880 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1053,6 +1053,48 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -1106,6 +1148,48 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { @@ -1159,6 +1243,48 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; /* firmware 10.2 specific mappings */ @@ -1315,6 +1441,107 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; +static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { + .tx_chain_mask = WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_10_4_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + .pcielp_txbuf_watermark = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + .pcielp_txbuf_tmo_en = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_value = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + .pdev_stats_update_period = + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_10_4_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + .dcs = WMI_10_4_PDEV_PARAM_DCS, + .ani_enable = WMI_10_4_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_10_4_PDEV_PARAM_PROXY_STA, + .idle_ps_config = WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + .power_gating_sleep = WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + .fast_channel_reset = WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + .burst_dur = WMI_10_4_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_10_4_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10_4_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_10_4_PDEV_PARAM_AGGR_BURST, + .rx_decap_mode = WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + .smart_antenna_default_antenna = + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + .igmpmld_override = WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + .igmpmld_tid = WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + .antenna_gain = WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + .rx_filter = WMI_10_4_PDEV_PARAM_RX_FILTER, + .set_mcast_to_ucast_tid = WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + .proxy_sta_mode = WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + .set_mcast2ucast_mode = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + .set_mcast2ucast_buffer = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + .remove_mcast2ucast_buffer = + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + .peer_sta_ps_statechg_enable = + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + .igmpmld_ac_override = WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + .block_interbss = WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + .set_disable_reset_cmdid = WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + .set_msdu_ttl_cmdid = WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + .set_ppdu_duration_cmdid = WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + .txbf_sound_period_cmdid = WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + .set_promisc_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + .set_burst_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + .en_stats = WMI_10_4_PDEV_PARAM_EN_STATS, + .mu_group_policy = WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + .noise_detection = WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + .noise_threshold = WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + .dpd_enable = WMI_10_4_PDEV_PARAM_DPD_ENABLE, + .set_mcast_bcast_echo = WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + .atf_strict_sch = WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + .atf_sched_duration = WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + .ant_plzn = WMI_10_4_PDEV_PARAM_ANT_PLZN, + .mgmt_retry_limit = WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + .sensitivity_level = WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + .signed_txpower_2g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + .signed_txpower_5g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + .enable_per_tid_amsdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + .enable_per_tid_ampdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + .cca_threshold = WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + .rts_fixed_rate = WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + .pdev_reset = WMI_10_4_PDEV_PARAM_PDEV_RESET, + .wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + .arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + .arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, const struct wmi_channel_arg *arg) { @@ -5887,6 +6114,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; + ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index ecc7288ff119..f6ee163259f6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3011,6 +3011,48 @@ struct wmi_pdev_param_map { u32 burst_dur; u32 burst_enable; u32 cal_period; + u32 aggr_burst; + u32 rx_decap_mode; + u32 smart_antenna_default_antenna; + u32 igmpmld_override; + u32 igmpmld_tid; + u32 antenna_gain; + u32 rx_filter; + u32 set_mcast_to_ucast_tid; + u32 proxy_sta_mode; + u32 set_mcast2ucast_mode; + u32 set_mcast2ucast_buffer; + u32 remove_mcast2ucast_buffer; + u32 peer_sta_ps_statechg_enable; + u32 igmpmld_ac_override; + u32 block_interbss; + u32 set_disable_reset_cmdid; + u32 set_msdu_ttl_cmdid; + u32 set_ppdu_duration_cmdid; + u32 txbf_sound_period_cmdid; + u32 set_promisc_mode_cmdid; + u32 set_burst_mode_cmdid; + u32 en_stats; + u32 mu_group_policy; + u32 noise_detection; + u32 noise_threshold; + u32 dpd_enable; + u32 set_mcast_bcast_echo; + u32 atf_strict_sch; + u32 atf_sched_duration; + u32 ant_plzn; + u32 mgmt_retry_limit; + u32 sensitivity_level; + u32 signed_txpower_2g; + u32 signed_txpower_5g; + u32 enable_per_tid_amsdu; + u32 enable_per_tid_ampdu; + u32 cca_threshold; + u32 rts_fixed_rate; + u32 pdev_reset; + u32 wapi_mbssid_offset; + u32 arp_srcaddr; + u32 arp_dstaddr; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -3226,6 +3268,100 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_CAL_PERIOD }; +enum wmi_10_4_pdev_param { + WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + WMI_10_4_PDEV_PARAM_LTR_ENABLE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PMF_QOS, + WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_DCS, + WMI_10_4_PDEV_PARAM_ANI_ENABLE, + WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + WMI_10_4_PDEV_PARAM_PROXY_STA, + WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + WMI_10_4_PDEV_PARAM_AGGR_BURST, + WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + WMI_10_4_PDEV_PARAM_BURST_DUR, + WMI_10_4_PDEV_PARAM_BURST_ENABLE, + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + WMI_10_4_PDEV_PARAM_RX_FILTER, + WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + WMI_10_4_PDEV_PARAM_EN_STATS, + WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + WMI_10_4_PDEV_PARAM_DPD_ENABLE, + WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + WMI_10_4_PDEV_PARAM_ANT_PLZN, + WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_PDEV_PARAM_CAL_PERIOD, + WMI_10_4_PDEV_PARAM_PDEV_RESET, + WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + struct wmi_pdev_set_param_cmd { __le32 param_id; __le32 param_value; -- cgit v1.2.3-70-g09d2 From d1e52a8ed2bf34ed5b839c190209deb80828d189 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:15 +0530 Subject: ath10k: fill 10.4 fw wmi init cmd default values Define 10.4 wmi init command structure and introduce new function ath10k_wmi_10_4_op_gen_init() to fill default values for each field which goes as part of wmi init cmd to 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 7 ++ drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/hw.h | 54 ++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 83 +++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 220 +++++++++++++++++++++++++++++++++ 5 files changed, 366 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5e8d8af5d0d0..020ac9f10168 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1116,6 +1116,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->max_num_peers = TARGET_10_4_NUM_PEERS; + ar->max_num_stations = TARGET_10_4_NUM_STATIONS; + ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; + ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; + ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->fw_stats_req_mask = WMI_STAT_PEER; + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index afd21d5b25ae..58b02ae81706 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -684,6 +684,8 @@ struct ath10k { int max_num_stations; int max_num_vdevs; int max_num_tdls_vdevs; + int num_active_peers; + int num_tids; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b0c89b48092d..52fc0249378b 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -354,6 +354,60 @@ enum ath10k_hw_rate_cck { #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan +/* Target specific defines for 10.4 firmware */ +#define TARGET_10_4_NUM_VDEVS 16 +#define TARGET_10_4_NUM_STATIONS 32 +#define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ + (TARGET_10_4_NUM_VDEVS)) +#define TARGET_10_4_ACTIVE_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 +#define TARGET_10_4_NUM_PEER_KEYS 2 +#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2) +#define TARGET_10_4_AST_SKID_LIMIT 32 +#define TARGET_10_4_TX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) +#define TARGET_10_4_RX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) + +/* 100 ms for video, best-effort, and background */ +#define TARGET_10_4_RX_TIMEOUT_LO_PRI 100 + +/* 40 ms for voice */ +#define TARGET_10_4_RX_TIMEOUT_HI_PRI 40 + +#define TARGET_10_4_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI +#define TARGET_10_4_SCAN_MAX_REQS 4 +#define TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES 8 + +/* Note: mcast to ucast is disabled by default */ +#define TARGET_10_4_NUM_MCAST_GROUPS 0 +#define TARGET_10_4_NUM_MCAST_TABLE_ELEMS 0 +#define TARGET_10_4_MCAST2UCAST_MODE 0 + +#define TARGET_10_4_TX_DBG_LOG_SIZE 1024 +#define TARGET_10_4_NUM_WDS_ENTRIES 32 +#define TARGET_10_4_DMA_BURST_SIZE 1 +#define TARGET_10_4_MAC_AGGR_DELIM 0 +#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 +#define TARGET_10_4_VOW_CONFIG 0 +#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400) +#define TARGET_10_4_11AC_TX_MAX_FRAGS 2 +#define TARGET_10_4_MAX_PEER_EXT_STATS 16 +#define TARGET_10_4_SMART_ANT_CAP 0 +#define TARGET_10_4_BK_MIN_FREE 0 +#define TARGET_10_4_BE_MIN_FREE 0 +#define TARGET_10_4_VI_MIN_FREE 0 +#define TARGET_10_4_VO_MIN_FREE 0 +#define TARGET_10_4_RX_BATCH_MODE 1 +#define TARGET_10_4_THERMAL_THROTTLING_CONFIG 0 +#define TARGET_10_4_ATF_CONFIG 0 +#define TARGET_10_4_IPHDR_PAD_CONFIG 1 +#define TARGET_10_4_QWRAP_CONFIG 0 + /* Number of Copy Engines supported */ #define CE_COUNT ar->hw_values->ce_count diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3f29886dc880..6c51b20dc8c5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4641,6 +4641,88 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) return buf; } +static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) +{ + struct wmi_init_cmd_10_4 *cmd; + struct sk_buff *buf; + struct wmi_resource_config_10_4 config = {}; + u32 len; + + config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); + config.num_peers = __cpu_to_le32(ar->max_num_peers); + config.num_active_peers = __cpu_to_le32(ar->num_active_peers); + config.num_tids = __cpu_to_le32(ar->num_tids); + + config.num_offload_peers = __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_PEERS); + config.num_offload_reorder_buffs = + __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS); + config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS); + config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT); + config.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK); + config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK); + + config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); + + config.rx_decap_mode = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE); + config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); + config.bmiss_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); + config.roam_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV); + config.roam_offload_max_ap_profiles = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES); + config.num_mcast_groups = __cpu_to_le32(TARGET_10_4_NUM_MCAST_GROUPS); + config.num_mcast_table_elems = + __cpu_to_le32(TARGET_10_4_NUM_MCAST_TABLE_ELEMS); + + config.mcast2ucast_mode = __cpu_to_le32(TARGET_10_4_MCAST2UCAST_MODE); + config.tx_dbg_log_size = __cpu_to_le32(TARGET_10_4_TX_DBG_LOG_SIZE); + config.num_wds_entries = __cpu_to_le32(TARGET_10_4_NUM_WDS_ENTRIES); + config.dma_burst_size = __cpu_to_le32(TARGET_10_4_DMA_BURST_SIZE); + config.mac_aggr_delim = __cpu_to_le32(TARGET_10_4_MAC_AGGR_DELIM); + + config.rx_skip_defrag_timeout_dup_detection_check = + __cpu_to_le32(TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK); + + config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG); + config.gtk_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV); + config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC); + config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS); + config.max_peer_ext_stats = + __cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS); + config.smart_ant_cap = __cpu_to_le32(TARGET_10_4_SMART_ANT_CAP); + + config.bk_minfree = __cpu_to_le32(TARGET_10_4_BK_MIN_FREE); + config.be_minfree = __cpu_to_le32(TARGET_10_4_BE_MIN_FREE); + config.vi_minfree = __cpu_to_le32(TARGET_10_4_VI_MIN_FREE); + config.vo_minfree = __cpu_to_le32(TARGET_10_4_VO_MIN_FREE); + + config.rx_batchmode = __cpu_to_le32(TARGET_10_4_RX_BATCH_MODE); + config.tt_support = + __cpu_to_le32(TARGET_10_4_THERMAL_THROTTLING_CONFIG); + config.atf_config = __cpu_to_le32(TARGET_10_4_ATF_CONFIG); + config.iphdr_pad_config = __cpu_to_le32(TARGET_10_4_IPHDR_PAD_CONFIG); + config.qwrap_config = __cpu_to_le32(TARGET_10_4_QWRAP_CONFIG); + + len = sizeof(*cmd) + + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + + buf = ath10k_wmi_alloc_skb(ar, len); + if (!buf) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_init_cmd_10_4 *)buf->data; + memcpy(&cmd->resource_config, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.4\n"); + return buf; +} + int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { if (arg->ie_len && !arg->ie) @@ -6105,6 +6187,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, + .gen_init = ath10k_wmi_10_4_op_gen_init, }; int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f6ee163259f6..dbb9f1c8c917 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2380,6 +2380,221 @@ struct wmi_resource_config_10_2 { #define NUM_UNITS_IS_NUM_VDEVS 0x1 #define NUM_UNITS_IS_NUM_PEERS 0x2 +struct wmi_resource_config_10_4 { + /* Number of virtual devices (VAPs) to support */ + __le32 num_vdevs; + + /* Number of peer nodes to support */ + __le32 num_peers; + + /* Number of active peer nodes to support */ + __le32 num_active_peers; + + /* In offload mode, target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. + * This determines maximum number of peers supported by target in + * offload mode. + */ + __le32 num_offload_peers; + + /* Number of reorder buffers available for doing target based reorder + * Rx reorder buffering + */ + __le32 num_offload_reorder_buffs; + + /* Number of keys per peer */ + __le32 num_peer_keys; + + /* Total number of TX/RX data TIDs */ + __le32 num_tids; + + /* Max skid for resolving hash collisions. + * The address search table is sparse, so that if two MAC addresses + * result in the same hash value, the second of these conflicting + * entries can slide to the next index in the address search table, + * and use it, if it is unoccupied. This ast_skid_limit parameter + * specifies the upper bound on how many subsequent indices to search + * over to find an unoccupied space. + */ + __le32 ast_skid_limit; + + /* The nominal chain mask for transmit. + * The chain mask may be modified dynamically, e.g. to operate AP tx + * with a reduced number of chains if no clients are associated. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of tx chains. + */ + __le32 tx_chain_mask; + + /* The nominal chain mask for receive. + * The chain mask may be modified dynamically, e.g. for a client to use + * a reduced number of chains for receive if the traffic to the client + * is low enough that it doesn't require downlink MIMO or antenna + * diversity. This configuration parameter specifies the nominal + * chain-mask that should be used when not operating with a reduced + * set of rx chains. + */ + __le32 rx_chain_mask; + + /* What rx reorder timeout (ms) to use for the AC. + * Each WMM access class (voice, video, best-effort, background) will + * have its own timeout value to dictate how long to wait for missing + * rx MPDUs to arrive before flushing subsequent MPDUs that have already + * been received. This parameter specifies the timeout in milliseconds + * for each class. + */ + __le32 rx_timeout_pri[4]; + + /* What mode the rx should decap packets to. + * MAC can decap to RAW (no decap), native wifi or Ethernet types. + * This setting also determines the default TX behavior, however TX + * behavior can be modified on a per VAP basis during VAP init + */ + __le32 rx_decap_mode; + + __le32 scan_max_pending_req; + + __le32 bmiss_offload_max_vdev; + + __le32 roam_offload_max_vdev; + + __le32 roam_offload_max_ap_profiles; + + /* How many groups to use for mcast->ucast conversion. + * The target's WAL maintains a table to hold information regarding + * which peers belong to a given multicast group, so that if + * multicast->unicast conversion is enabled, the target can convert + * multicast tx frames to a series of unicast tx frames, to each peer + * within the multicast group. This num_mcast_groups configuration + * parameter tells the target how many multicast groups to provide + * storage for within its multicast group membership table. + */ + __le32 num_mcast_groups; + + /* Size to alloc for the mcast membership table. + * This num_mcast_table_elems configuration parameter tells the target + * how many peer elements it needs to provide storage for in its + * multicast group membership table. These multicast group membership + * table elements are shared by the multicast groups stored within + * the table. + */ + __le32 num_mcast_table_elems; + + /* Whether/how to do multicast->unicast conversion. + * This configuration parameter specifies whether the target should + * perform multicast --> unicast conversion on transmit, and if so, + * what to do if it finds no entries in its multicast group membership + * table for the multicast IP address in the tx frame. + * Configuration value: + * 0 -> Do not perform multicast to unicast conversion. + * 1 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, drop the frame + * 2 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, transmit the + * frame as multicast. + */ + __le32 mcast2ucast_mode; + + /* How much memory to allocate for a tx PPDU dbg log. + * This parameter controls how much memory the target will allocate to + * store a log of tx PPDU meta-information (how large the PPDU was, + * when it was sent, whether it was successful, etc.) + */ + __le32 tx_dbg_log_size; + + /* How many AST entries to be allocated for WDS */ + __le32 num_wds_entries; + + /* MAC DMA burst size. 0 -default, 1 -256B */ + __le32 dma_burst_size; + + /* Fixed delimiters to be inserted after every MPDU to account for + * interface latency to avoid underrun. + */ + __le32 mac_aggr_delim; + + /* Determine whether target is responsible for detecting duplicate + * non-aggregate MPDU and timing out stale fragments. A-MPDU reordering + * is always performed on the target. + * + * 0: target responsible for frag timeout and dup checking + * 1: host responsible for frag timeout and dup checking + */ + __le32 rx_skip_defrag_timeout_dup_detection_check; + + /* Configuration for VoW : No of Video nodes to be supported and max + * no of descriptors for each video link (node). + */ + __le32 vow_config; + + /* Maximum vdev that could use gtk offload */ + __le32 gtk_offload_max_vdev; + + /* Number of msdu descriptors target should use */ + __le32 num_msdu_desc; + + /* Max number of tx fragments per MSDU. + * This parameter controls the max number of tx fragments per MSDU. + * This will passed by target as part of the WMI_SERVICE_READY event + * and is overridden by the OS shim as required. + */ + __le32 max_frag_entries; + + /* Max number of extended peer stats. + * This parameter controls the max number of peers for which extended + * statistics are supported by target + */ + __le32 max_peer_ext_stats; + + /* Smart antenna capabilities information. + * 1 - Smart antenna is enabled + * 0 - Smart antenna is disabled + * In future this can contain smart antenna specific capabilities. + */ + __le32 smart_ant_cap; + + /* User can configure the buffers allocated for each AC (BE, BK, VI, VO) + * during init. + */ + __le32 bk_minfree; + __le32 be_minfree; + __le32 vi_minfree; + __le32 vo_minfree; + + /* Rx batch mode capability. + * 1 - Rx batch mode enabled + * 0 - Rx batch mode disabled + */ + __le32 rx_batchmode; + + /* Thermal throttling capability. + * 1 - Capable of thermal throttling + * 0 - Not capable of thermal throttling + */ + __le32 tt_support; + + /* ATF configuration. + * 1 - Enable ATF + * 0 - Disable ATF + */ + __le32 atf_config; + + /* Configure padding to manage IP header un-alignment + * 1 - Enable padding + * 0 - Disable padding + */ + __le32 iphdr_pad_config; + + /* qwrap configuration + * 1 - This is qwrap configuration + * 0 - This is not qwrap + */ + __le32 qwrap_config; +} __packed; + /* strucutre describing host memory chunk. */ struct host_memory_chunk { /* id of the request that is passed up in service ready */ @@ -2412,6 +2627,11 @@ struct wmi_init_cmd_10_2 { struct wmi_host_mem_chunks mem_chunks; } __packed; +struct wmi_init_cmd_10_4 { + struct wmi_resource_config_10_4 resource_config; + struct wmi_host_mem_chunks mem_chunks; +} __packed; + struct wmi_chan_list_entry { __le16 freq; u8 phy_mode; /* valid for 10.2 only */ -- cgit v1.2.3-70-g09d2 From 1c0929614ac429a32509307e790e813325562dc1 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:16 +0530 Subject: ath10k: handle 10.4 fw wmi mgmt rx event 10.4 firmware wmi mgmt rx event format differs from non 10.4 firmware and changing existing wmi mgmt rx event parsing function ath10k_wmi_op_pull_mgmt_rx_ev() for 10.4 would add more complex. This patch adds new function to receive any wmi rx event from 10.4 firmware and also introduce new function to parse wmi mgmt rx event. In addition, fw main branch service rdy event parsing function is linked in wmi ops table. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 64 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 15 ++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c51b20dc8c5..9502032f46dc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2124,6 +2124,40 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + struct wmi_10_4_mgmt_rx_event *ev; + struct wmi_10_4_mgmt_rx_hdr *ev_hdr; + size_t pull_len; + u32 msdu_len; + + ev = (struct wmi_10_4_mgmt_rx_event *)skb->data; + ev_hdr = &ev->hdr; + pull_len = sizeof(*ev); + + if (skb->len < pull_len) + return -EPROTO; + + skb_pull(skb, pull_len); + arg->channel = ev_hdr->channel; + arg->buf_len = ev_hdr->buf_len; + arg->status = ev_hdr->status; + arg->snr = ev_hdr->snr; + arg->phy_mode = ev_hdr->phy_mode; + arg->rate = ev_hdr->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + if (skb->len < msdu_len) + return -EPROTO; + + /* Make sure bytes added for padding are removed. */ + skb_trim(skb, msdu_len); + + return 0; +} + int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; @@ -4267,6 +4301,33 @@ out: dev_kfree_skb(skb); } +static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_10_4_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr))) + goto out; + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + + switch (id) { + case WMI_10_4_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; + } + +out: + dev_kfree_skb(skb); +} + static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { int ret; @@ -6186,7 +6247,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { }; static const struct wmi_ops wmi_10_4_ops = { + .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index dbb9f1c8c917..b1bec031c111 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2947,6 +2947,21 @@ struct wmi_mgmt_rx_event_v2 { u8 buf[0]; } __packed; +struct wmi_10_4_mgmt_rx_hdr { + __le32 channel; + __le32 snr; + u8 rssi_ctl[4]; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; +} __packed; + +struct wmi_10_4_mgmt_rx_event { + struct wmi_10_4_mgmt_rx_hdr hdr; + u8 buf[0]; +} __packed; + #define WMI_RX_STATUS_OK 0x00 #define WMI_RX_STATUS_ERR_CRC 0x01 #define WMI_RX_STATUS_ERR_DECRYPT 0x08 -- cgit v1.2.3-70-g09d2 From b039941704452d8f89e83cba352b5c89a6ebf2ab Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:17 +0530 Subject: ath10k: adjust default peer limits if qcache enabled in 10.4 fw 10.4 firmware supports upto 512 clients when qcache feature is enabled. Make adjustment on default max peer count, active peers, number of tid in such case to meet qcache requirement. 10.4 fw has extra unit info flag NUM_UNITS_IS_NUM_ACTIVE_PEERS which is also handled in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 27 +++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.h | 5 +++-- 3 files changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 52fc0249378b..568c5ea5561f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -360,6 +360,12 @@ enum ath10k_hw_rate_cck { #define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ (TARGET_10_4_NUM_VDEVS)) #define TARGET_10_4_ACTIVE_PEERS 0 + +/* TODO: increase qcache max client limit to 512 after + * testing with 512 client. + */ +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 256 +#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 #define TARGET_10_4_NUM_PEER_KEYS 2 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9502032f46dc..62ea0bca03e1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3826,20 +3826,39 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) return; } + if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { + ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX + + TARGET_10_4_NUM_VDEVS; + ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS + + TARGET_10_4_NUM_VDEVS; + ar->num_tids = ar->num_active_peers * 2; + ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX; + } + + /* TODO: Adjust max peer count for cases like WMI_SERVICE_RATECTRL_CACHE + * and WMI_SERVICE_IRAM_TIDS, etc. + */ + for (i = 0; i < num_mem_reqs; ++i) { req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id); num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units); unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size); num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); - if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) + if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) { + if (ar->num_active_peers) + num_units = ar->num_active_peers + 1; + else + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) { /* number of units to allocate is number of * peers, 1 extra for self peer on target */ /* this needs to be tied, host and target * can get out of sync */ - num_units = TARGET_10X_NUM_PEERS + 1; - else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) - num_units = TARGET_10X_NUM_VDEVS + 1; + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) { + num_units = ar->max_num_vdevs + 1; + } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1bec031c111..b1e4932f97f9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2377,8 +2377,9 @@ struct wmi_resource_config_10_2 { __le32 feature_mask; } __packed; -#define NUM_UNITS_IS_NUM_VDEVS 0x1 -#define NUM_UNITS_IS_NUM_PEERS 0x2 +#define NUM_UNITS_IS_NUM_VDEVS BIT(0) +#define NUM_UNITS_IS_NUM_PEERS BIT(1) +#define NUM_UNITS_IS_NUM_ACTIVE_PEERS BIT(2) struct wmi_resource_config_10_4 { /* Number of virtual devices (VAPs) to support */ -- cgit v1.2.3-70-g09d2 From d02e752f732a91e2a6de9a3547c682914ae0bbe7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:18 +0530 Subject: ath10k: handle 10.4 fw wmi ready event Reuse existing function ath10k_wmi_op_pull_rdy_ev() to parse WMI_10_4_READY_EVENTID and handle the same event in ath10k_wmi_10_4_op_rx(). Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 62ea0bca03e1..271ad2f86d24 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4338,6 +4338,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_READY_EVENTID: + ath10k_wmi_event_ready(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6270,6 +6273,7 @@ static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; -- cgit v1.2.3-70-g09d2 From b24fc6fc7c0f6425793fd46ccc4ea48f49447617 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 10:34:03 +0200 Subject: ath: DFS - limit number of potential PRI sequences In the PRI detector, after the current radar pulse has been checked agains existing PRI sequences, it is considered as part of a new potential sequence. Previously, the condition to accept a new sequence was to have at least the same number of pulses as the longest matching sequence. This was wrong, since it led to duplicates of PRI sequences. This patch changes the acceptance criteria for new potential sequences from 'at least' to 'more than' the longest existing. Detection performance remains unaffected, while the number of PRI sequences accounted at runtime (and with it CPU load) is reduced by up to 50%. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/dfs_pri_detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 1b5ad1965607..cc5c592fc4c0 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -273,7 +273,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde, tmp_false_count++; } } - if (ps.count < min_count) + if (ps.count <= min_count) /* did not reach minimum count, drop sequence */ continue; -- cgit v1.2.3-70-g09d2 From 33190ebfb1e846f97366a334e45b03caf4a65c84 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 15 Jun 2015 17:42:32 +0300 Subject: wil6210: restart AP upon change in privacy settings privacy settings might change while AP is running. Inside wil_cfg80211_change_beacon(), detect change in privacy settings and handle it by stopping and re-starting the AP. Firmware cannot handle on-the-fly privacy settings change and so AP restart is required. Signed-off-by: Dedy Lansky Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 217 +++++++++++++++++----------- drivers/net/wireless/ath/wil6210/wil6210.h | 2 + 2 files changed, 135 insertions(+), 84 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c79cfe02ec80..e4be2d9bbac4 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -736,6 +736,92 @@ static int wil_fix_bcon(struct wil6210_priv *wil, return rc; } +/* internal functions for device reset and starting AP */ +static int _wil_cfg80211_set_ies(struct wiphy *wiphy, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies) + +{ + int rc; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + /* FW do not form regular beacon, so bcon IE's are not set + * For the DMG bcon, when it will be supported, bcon IE's will + * be reused; add something like: + * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, + * bcon->beacon_ies); + */ + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, probe_ies_len, probe_ies); + if (rc) { + wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + return rc; + } + + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, assoc_ies_len, assoc_ies); + if (rc) { + wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); + return rc; + } + + return 0; +} + +static int _wil_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *ssid, size_t ssid_len, u32 privacy, + int bi, u8 chan, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies, + u8 hidden_ssid) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); + + wil_set_recovery_state(wil, fw_recovery_idle); + + mutex_lock(&wil->mutex); + + __wil_down(wil); + rc = __wil_up(wil); + if (rc) + goto out; + + rc = wmi_set_ssid(wil, ssid_len, ssid); + if (rc) + goto out; + + rc = _wil_cfg80211_set_ies(wiphy, probe_ies_len, probe_ies, + assoc_ies_len, assoc_ies); + if (rc) + goto out; + + wil->privacy = privacy; + wil->channel = chan; + wil->hidden_ssid = hidden_ssid; + + netif_carrier_on(ndev); + + rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid); + if (rc) + goto err_pcp_start; + + rc = wil_bcast_init(wil); + if (rc) + goto err_bcast; + + goto out; /* success */ + +err_bcast: + wmi_pcp_stop(wil); +err_pcp_start: + netif_carrier_off(ndev); +out: + mutex_unlock(&wil->mutex); + return rc; +} + static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *bcon) @@ -746,6 +832,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, const u8 *pr_ies = NULL; size_t pr_ies_len = 0; int rc; + u32 privacy = 0; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); @@ -760,40 +847,41 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - /* FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - if (rc) { - wil_err(wil, "set_ie(PROBE_RESP) failed\n"); - return rc; - } + if (pr_ies && cfg80211_find_ie(WLAN_EID_RSN, pr_ies, pr_ies_len)) + privacy = 1; - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, - bcon->assocresp_ies_len, - bcon->assocresp_ies); - if (rc) { - wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); - return rc; + /* in case privacy has changed, need to restart the AP */ + if (wil->privacy != privacy) { + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", + wil->privacy, privacy); + + rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, + wdev->ssid_len, privacy, + wdev->beacon_interval, + wil->channel, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + wil->hidden_ssid); + } else { + rc = _wil_cfg80211_set_ies(wiphy, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies); } - return 0; + return rc; } static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) { - int rc = 0; + int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wireless_dev *wdev = ndev->ieee80211_ptr; struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; - u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; @@ -807,6 +895,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } + switch (info->hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hidden_ssid = WMI_HIDDEN_SSID_DISABLED; + break; + + case NL80211_HIDDEN_SSID_ZERO_LEN: + hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; + break; + + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hidden_ssid = WMI_HIDDEN_SSID_CLEAR; + break; + + default: + wil_err(wil, "AP: Invalid hidden SSID %d\n", info->hidden_ssid); + return -EOPNOTSUPP; + } wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", @@ -830,70 +935,14 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - wil_set_recovery_state(wil, fw_recovery_idle); - - mutex_lock(&wil->mutex); - - __wil_down(wil); - rc = __wil_up(wil); - if (rc) - goto out; - - rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); - if (rc) - goto out; - - /* IE's */ - /* bcon 'head IE's are not relevant for 60g band */ - /* - * FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, - bcon->assocresp_ies); - - wil->privacy = info->privacy; - - switch (info->hidden_ssid) { - case NL80211_HIDDEN_SSID_NOT_IN_USE: - hidden_ssid = WMI_HIDDEN_SSID_DISABLED; - break; - - case NL80211_HIDDEN_SSID_ZERO_LEN: - hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; - break; - - case NL80211_HIDDEN_SSID_ZERO_CONTENTS: - hidden_ssid = WMI_HIDDEN_SSID_CLEAR; - break; - - default: - rc = -EOPNOTSUPP; - goto out; - } - - netif_carrier_on(ndev); - - rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, - channel->hw_value, hidden_ssid); - if (rc) - goto err_pcp_start; + rc = _wil_cfg80211_start_ap(wiphy, ndev, + info->ssid, info->ssid_len, info->privacy, + info->beacon_interval, channel->hw_value, + pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + hidden_ssid); - rc = wil_bcast_init(wil); - if (rc) - goto err_bcast; - - goto out; /* success */ -err_bcast: - wmi_pcp_stop(wil); -err_pcp_start: - netif_carrier_off(ndev); -out: - mutex_unlock(&wil->mutex); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 275355d46a36..c63e4a35eaa0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -559,6 +559,8 @@ struct wil6210_priv { /* profile */ u32 monitor_flags; u32 privacy; /* secure connection? */ + u8 hidden_ssid; /* relevant in AP mode */ + u16 channel; /* relevant in AP mode */ int sinfo_gen; u32 ap_isolate; /* no intra-BSS communication */ /* interrupt moderation */ -- cgit v1.2.3-70-g09d2 From a03fee347cdcbf101820b2984366a37043ffc62b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:20 +0530 Subject: ath10k: enhance swba event handler to adapt different size tim bitmap Due to 512 client support in 10.4 firmware, size of tim ie is going to be slightly higher than non 10.4 firmware. So, size of tim_bitmap what is carried in swba event from 10.4 firmware is bit higher. The only bottle neck to reuse existing swba handler ath10k_wmi_event_host_swba() for 10.4 is that code designed to deal with fixed size tim bitmap(ie, tim_info[].tim_bitmap in wmi_swba_ev_arg). This patch removes such size limitation and makes it more suitable to handle swba event which has different size tim bitmap. All existing swba event parsing functions are changed to adapt this change. Actual support to handle 10.4 swba event is added in next patch. Only preparation is made in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 18 ++++++++++- drivers/net/wireless/ath/ath10k/wmi.c | 53 +++++++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/wmi.h | 10 +++++- 3 files changed, 66 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 620b37b59784..ced35a1e0675 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -709,6 +709,8 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, const void *ptr, void *data) { struct wmi_tlv_swba_parse *swba = data; + struct wmi_tim_info_arg *tim_info_arg; + const struct wmi_tim_info *tim_info_ev = ptr; if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) return -EPROTO; @@ -716,7 +718,21 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) return -ENOBUFS; - swba->arg->tim_info[swba->n_tim++] = ptr; + if (__le32_to_cpu(tim_info_ev->tim_len) > + sizeof(tim_info_ev->tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_info_arg = &swba->arg->tim_info[swba->n_tim]; + tim_info_arg->tim_len = tim_info_ev->tim_len; + tim_info_arg->tim_mcast = tim_info_ev->tim_mcast; + tim_info_arg->tim_bitmap = tim_info_ev->tim_bitmap; + tim_info_arg->tim_changed = tim_info_ev->tim_changed; + tim_info_arg->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending; + + swba->n_tim++; + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 271ad2f86d24..228c3dd6713a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2874,33 +2874,42 @@ exit: static void ath10k_wmi_update_tim(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - const struct wmi_tim_info *tim_info) + const struct wmi_tim_info_arg *tim_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; struct ieee80211_tim_ie *tim; u8 *ies, *ie; u8 ie_len, pvm_len; __le32 t; - u32 v; + u32 v, tim_len; + + /* When FW reports 0 in tim_len, ensure atleast first byte + * in tim_bitmap is considered for pvm calculation. + */ + tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1; /* if next SWBA has no tim_changed the tim_bitmap is garbage. * we must copy the bitmap upon change and reuse it later */ if (__le32_to_cpu(tim_info->tim_changed)) { int i; - BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != - sizeof(tim_info->tim_bitmap)); + if (sizeof(arvif->u.ap.tim_bitmap) < tim_len) { + ath10k_warn(ar, "SWBA TIM field is too big (%u), truncated it to %zu", + tim_len, sizeof(arvif->u.ap.tim_bitmap)); + tim_len = sizeof(arvif->u.ap.tim_bitmap); + } - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { + for (i = 0; i < tim_len; i++) { t = tim_info->tim_bitmap[i / 4]; v = __le32_to_cpu(t); arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; } - /* FW reports either length 0 or 16 - * so we calculate this on our own */ + /* FW reports either length 0 or length based on max supported + * station. so we calculate this on our own + */ arvif->u.ap.tim_len = 0; - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) + for (i = 0; i < tim_len; i++) if (arvif->u.ap.tim_bitmap[i]) arvif->u.ap.tim_len = i; @@ -2924,7 +2933,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ if (pvm_len < arvif->u.ap.tim_len) { - int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; + int expand_size = tim_len - pvm_len; int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); void *next_ie = ie + 2 + ie_len; @@ -2939,7 +2948,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, } } - if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { + if (pvm_len > tim_len) { ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len); return; } @@ -3003,7 +3012,21 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) break; - arg->tim_info[i] = &ev->bcn_info[i].tim_info; + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len; + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; i++; } @@ -3016,7 +3039,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_swba_ev_arg arg = {}; u32 map; int i = -1; - const struct wmi_tim_info *tim_info; + const struct wmi_tim_info_arg *tim_info; const struct wmi_p2p_noa_info *noa_info; struct ath10k_vif *arvif; struct sk_buff *bcn; @@ -3045,7 +3068,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) break; } - tim_info = arg.tim_info[i]; + tim_info = &arg.tim_info[i]; noa_info = arg.noa_info[i]; ath10k_dbg(ar, ATH10K_DBG_MGMT, @@ -3060,6 +3083,10 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(tim_info->tim_bitmap[1]), __le32_to_cpu(tim_info->tim_bitmap[0])); + /* TODO: Only first 4 word from tim_bitmap is dumped. + * Extend debug code to dump full tim_bitmap. + */ + arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { ath10k_warn(ar, "no vif for vdev_id %d found\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1e4932f97f9..7c4a15f1ae77 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5160,6 +5160,14 @@ struct wmi_tim_info { __le32 tim_num_ps_pending; } __packed; +struct wmi_tim_info_arg { + __le32 tim_len; + __le32 tim_mcast; + const __le32 *tim_bitmap; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + /* Maximum number of NOA Descriptors supported */ #define WMI_P2P_MAX_NOA_DESCRIPTORS 4 #define WMI_P2P_OPPPS_ENABLE_BIT BIT(0) @@ -5710,7 +5718,7 @@ struct wmi_peer_kick_ev_arg { struct wmi_swba_ev_arg { __le32 vdev_map; - const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; + struct wmi_tim_info_arg tim_info[WMI_MAX_AP_VDEV]; const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; }; -- cgit v1.2.3-70-g09d2 From 3cec3be3d101bfec7136841cbb9b32ca49ac0328 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:21 +0530 Subject: ath10k: handle 10.4 firmware wmi swba event 10.4 firmware swba event payload has space to accommodate upto 512 client traffic indication info & one p2p noa descriptor. It's is not matching with exiting swba event format defined for non 10.4 firmware. Non 10.4 firmware swba event format is designed to support only upto only 128 client and four p2p notice of absence descriptor. following changes are done in this patch to enable ath10k to handle 10.4 firmware swba event, - link generic ath10k_wmi_event_host_swba() to handle 10.4 swba event in 10.4 wmi rx handler. - add 10.4 specific swba event structure wmi_10_4_host_swba_event. - new function ath10k_wmi_10_4_op_pull_swba_ev() to parse 10.4 swba event. - increase tim_bitmap[] size in ath10k_vif to 64 to hold 512 station power save state. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 4 +-- drivers/net/wireless/ath/ath10k/wmi.c | 61 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 41 +++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 58b02ae81706..86c4015270e9 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -328,8 +328,8 @@ struct ath10k_vif { u32 uapsd; } sta; struct { - /* 127 stations; wmi limit */ - u8 tim_bitmap[16]; + /* 512 stations */ + u8 tim_bitmap[64]; u8 tim_len; u32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 228c3dd6713a..7f9800ac15ec 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3034,6 +3034,63 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_10_4_host_swba_event *ev = (void *)skb->data; + u32 map, tim_len; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_len = __le32_to_cpu(ev->bcn_info[i].tim_info.tim_len); + if (tim_len) { + /* Exclude 4 byte guard length */ + tim_len -= 4; + arg->tim_info[i].tim_len = __cpu_to_le32(tim_len); + } else { + arg->tim_info[i].tim_len = 0; + } + + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + + /* 10.4 firmware doesn't have p2p support. notice of absence + * info can be ignored for now. + */ + + i++; + } + + return 0; +} + void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { struct wmi_swba_ev_arg arg = {}; @@ -4368,6 +4425,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6299,6 +6359,7 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7c4a15f1ae77..395742d3ff61 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5199,6 +5199,47 @@ struct wmi_host_swba_event { struct wmi_bcn_info bcn_info[0]; } __packed; +/* 16 words = 512 client + 1 word = for guard */ +#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17 + +struct wmi_10_4_tim_info { + __le32 tim_len; + __le32 tim_mcast; + __le32 tim_bitmap[WMI_10_4_TIM_BITMAP_ARRAY_SIZE]; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + +#define WMI_10_4_P2P_MAX_NOA_DESCRIPTORS 1 + +struct wmi_10_4_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + */ + u8 changed; + /* NOA index */ + u8 index; + /* Bit 0 - Opp PS state of the AP + * Bits 1-7 - Ctwindow in TUs + */ + u8 ctwindow_oppps; + /* Number of NOA descriptors */ + u8 num_descriptors; + + struct wmi_p2p_noa_descriptor + noa_descriptors[WMI_10_4_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + +struct wmi_10_4_bcn_info { + struct wmi_10_4_tim_info tim_info; + struct wmi_10_4_p2p_noa_info p2p_noa_info; +} __packed; + +struct wmi_10_4_host_swba_event { + __le32 vdev_map; + struct wmi_10_4_bcn_info bcn_info[0]; +} __packed; + #define WMI_MAX_AP_VDEV 16 struct wmi_tbtt_offset_event { -- cgit v1.2.3-70-g09d2 From 373b48cfe77ff8c0ff94564a280dbfea56e769d4 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:22 +0530 Subject: ath10k: enable vdev and peer related operations for 10.4 fw Most of existing vdev and peer related functions (vdev create, vdev delete, vdev start, peer create, peer delete, peer flush, etc) are reusable for 10.4 firmware. Link those general vdev and peer functions to 10.4 wmi function table. Existing general pktlog enable/disable, dbglog configuration functions are reusable for 10.4 and add them also in wmi function table. Also handle few wmi events (sevice rdy, echo, dbg msg, tbtt offset update, dbg print) in ath10k_wmi_10_4_op_rx(). wow event is not applicable in 10.4 firmware, have it under not implemented print. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7f9800ac15ec..a83a3636842b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4422,12 +4422,40 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_10_4_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_10_4_SERVICE_READY_EVENTID: + ath10k_wmi_event_service_ready(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; case WMI_10_4_HOST_SWBA_EVENTID: ath10k_wmi_event_host_swba(ar, skb); break; + case WMI_10_4_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_10_4_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_10_4_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_10_4_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: + ath10k_dbg(ar, ATH10K_DBG_WMI, + "received event id %d not implemented\n", id); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6359,10 +6387,44 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + + /* shared with 10.2 */ + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.2.3-70-g09d2 From b2297baa273b2a73d7408a97d0163c5a0dfccf8c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:23 +0530 Subject: ath10k: add scan support for 10.4 fw Existing non 10.4 firmware scan related events and commands are matching with 10.4 firmware (except chan info event). Link general start scan,stop scan, scan channel list configuration functions to 10.4 wmi function table and add a new handler to parse 10.4 specific chan info event. 10.4 firmware has extra scan completion reason WMI_SCAN_REASON_INTERNAL_FAILURE and new scan event WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT compared to previous firmware versions. These things are added in respective enum. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 42 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 36 ++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a83a3636842b..9f73c5784f45 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1923,6 +1923,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "completed [preempted]"; case WMI_SCAN_REASON_TIMEDOUT: return "completed [timedout]"; + case WMI_SCAN_REASON_INTERNAL_FAILURE: + return "completed [internal err]"; case WMI_SCAN_REASON_MAX: break; } @@ -1937,6 +1939,10 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "preempted"; case WMI_SCAN_EVENT_START_FAILED: return "start failed"; + case WMI_SCAN_EVENT_RESTARTED: + return "restarted"; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: + return "foreign channel exit"; default: return "unknown"; } @@ -2012,6 +2018,8 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: + case WMI_SCAN_EVENT_RESTARTED: + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: default: break; } @@ -2318,6 +2326,29 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + struct wmi_10_4_chan_info_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + arg->chan_tx_pwr_range = ev->chan_tx_pwr_range; + arg->chan_tx_pwr_tp = ev->chan_tx_pwr_tp; + arg->rx_frame_count = ev->rx_frame_count; + + return 0; +} + void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { struct wmi_ch_info_ev_arg arg = {}; @@ -4431,6 +4462,12 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); break; + case WMI_10_4_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_10_4_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -6386,7 +6423,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev, .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, @@ -6398,6 +6438,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_start_scan = ath10k_wmi_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 395742d3ff61..6e806cb7ebe2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2879,15 +2879,17 @@ enum wmi_bss_filter { }; enum wmi_scan_event_type { - WMI_SCAN_EVENT_STARTED = 0x1, - WMI_SCAN_EVENT_COMPLETED = 0x2, - WMI_SCAN_EVENT_BSS_CHANNEL = 0x4, - WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, - WMI_SCAN_EVENT_DEQUEUED = 0x10, - WMI_SCAN_EVENT_PREEMPTED = 0x20, /* possibly by high-prio scan */ - WMI_SCAN_EVENT_START_FAILED = 0x40, - WMI_SCAN_EVENT_RESTARTED = 0x80, - WMI_SCAN_EVENT_MAX = 0x8000 + WMI_SCAN_EVENT_STARTED = BIT(0), + WMI_SCAN_EVENT_COMPLETED = BIT(1), + WMI_SCAN_EVENT_BSS_CHANNEL = BIT(2), + WMI_SCAN_EVENT_FOREIGN_CHANNEL = BIT(3), + WMI_SCAN_EVENT_DEQUEUED = BIT(4), + /* possibly by high-prio scan */ + WMI_SCAN_EVENT_PREEMPTED = BIT(5), + WMI_SCAN_EVENT_START_FAILED = BIT(6), + WMI_SCAN_EVENT_RESTARTED = BIT(7), + WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = BIT(8), + WMI_SCAN_EVENT_MAX = BIT(15), }; enum wmi_scan_completion_reason { @@ -2895,6 +2897,7 @@ enum wmi_scan_completion_reason { WMI_SCAN_REASON_CANCELLED, WMI_SCAN_REASON_PREEMPTED, WMI_SCAN_REASON_TIMEDOUT, + WMI_SCAN_REASON_INTERNAL_FAILURE, WMI_SCAN_REASON_MAX, }; @@ -5564,6 +5567,18 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_10_4_chan_info_event { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; +} __packed; + struct wmi_peer_sta_kickout_event { struct wmi_mac_addr peer_macaddr; } __packed; @@ -5744,6 +5759,9 @@ struct wmi_ch_info_ev_arg { __le32 noise_floor; __le32 rx_clear_count; __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; }; struct wmi_vdev_start_ev_arg { -- cgit v1.2.3-70-g09d2 From 721ad3ca7956ce66e11fdcb187769130486feb28 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:24 +0530 Subject: ath10k: add 10.4 fw specific htt msg definitions New htt event table is added for 10.4 firmware. Following new htt events are available only 10.4. adding this to generic htt event table, HTT_T2H_MSG_TYPE_EN_STATS, HTT_T2H_MSG_TYPE_TX_FETCH_IND, HTT_T2H_MSG_TYPE_TX_FETCH_CONF, HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/htt.c | 41 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt.h | 36 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 4 ++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 5 files changed, 84 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 020ac9f10168..7ef960792dbc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1121,6 +1121,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6da6ef26143a..6f71f94939fa 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -102,6 +102,43 @@ static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = { [HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, }; +static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { + [HTT_10_4_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH, + [HTT_10_4_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP, + [HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP, + [HTT_10_4_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA, + [HTT_10_4_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA, + [HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND, + [HTT_10_4_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG, + [HTT_10_4_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND, + [HTT_10_4_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND, + [HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND] = + HTT_T2H_MSG_TYPE_TX_INSPECT_IND, + [HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] = + HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION, + [HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE, + [HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] = + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] = + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND, + [HTT_10_4_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, + [HTT_10_4_T2H_MSG_TYPE_EN_STATS] = HTT_T2H_MSG_TYPE_EN_STATS, + [HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] = + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] = + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + [HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] = + HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, + [HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] = + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, +}; + int ath10k_htt_connect(struct ath10k_htt *htt) { struct ath10k_htc_svc_conn_req conn_req; @@ -147,6 +184,10 @@ int ath10k_htt_init(struct ath10k *ar) 2; /* ip4 dscp or ip6 priority */ switch (ar->htt.op_version) { + case ATH10K_FW_HTT_OP_VERSION_10_4: + ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types; + ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS; + break; case ATH10K_FW_HTT_OP_VERSION_10_1: ar->htt.t2h_msg_types = htt_10x_t2h_msg_types; ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7e8a0d835663..8e64ace0119b 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -349,6 +349,38 @@ enum htt_tlv_t2h_msg_type { HTT_TLV_T2H_NUM_MSGS }; +enum htt_10_4_t2h_msg_type { + HTT_10_4_T2H_MSG_TYPE_VERSION_CONF = 0x0, + HTT_10_4_T2H_MSG_TYPE_RX_IND = 0x1, + HTT_10_4_T2H_MSG_TYPE_RX_FLUSH = 0x2, + HTT_10_4_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP = 0x4, + HTT_10_4_T2H_MSG_TYPE_RX_ADDBA = 0x5, + HTT_10_4_T2H_MSG_TYPE_RX_DELBA = 0x6, + HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND = 0x7, + HTT_10_4_T2H_MSG_TYPE_PKTLOG = 0x8, + HTT_10_4_T2H_MSG_TYPE_STATS_CONF = 0x9, + HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND = 0xa, + HTT_10_4_T2H_MSG_TYPE_SEC_IND = 0xb, + HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, + HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, + HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe, + HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE = 0xf, + HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0x10, + HTT_10_4_T2H_MSG_TYPE_RX_PN_IND = 0x11, + HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x12, + HTT_10_4_T2H_MSG_TYPE_TEST = 0x13, + HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14, + HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF = 0x17, + HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, + /* 0x19 to 0x2f are reserved */ + HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND = 0x30, + /* keep this last */ + HTT_10_4_T2H_NUM_MSGS +}; + enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_VERSION_CONF, HTT_T2H_MSG_TYPE_RX_IND, @@ -375,6 +407,10 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_AGGR_CONF, HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, HTT_T2H_MSG_TYPE_TEST, + HTT_T2H_MSG_TYPE_EN_STATS, + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, /* keep this last */ HTT_T2H_NUM_MSGS }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 7399e45a016e..d7d118328f31 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2072,6 +2072,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_CHAN_CHANGE: break; + case HTT_T2H_MSG_TYPE_EN_STATS: + case HTT_T2H_MSG_TYPE_TX_FETCH_IND: + case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: + case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND: default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 568c5ea5561f..917228517546 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -153,6 +153,8 @@ enum ath10k_fw_htt_op_version { ATH10K_FW_HTT_OP_VERSION_TLV = 3, + ATH10K_FW_HTT_OP_VERSION_10_4 = 4, + /* keep last */ ATH10K_FW_HTT_OP_VERSION_MAX, }; -- cgit v1.2.3-70-g09d2 From cf36fef08a85c815d9358e1571d3d83da02474f7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:25 +0530 Subject: ath10k: advertise 10.4 fw ap and sta iface combination to mac80211 10.4 fw supports upto 16 interface in ap mode and 1 interface in station mode, overall total interfaces supported are 16 interfaces. Populate this limit in wiphy->iface_combinations. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a8561d1f26e3..0f3c17c0c8f8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6620,6 +6620,33 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { }, }; +static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 16, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { + { + .limits = ath10k_10_4_if_limits, + .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), + .max_interfaces = 16, + .num_different_channels = 1, + .beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), +#endif + }, +}; + static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; @@ -6944,6 +6971,9 @@ int ath10k_mac_register(struct ath10k *ar) ARRAY_SIZE(ath10k_10x_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10_4_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: -- cgit v1.2.3-70-g09d2 From 5c8726eca3e4080615f09328d1f28013b6e5c837 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:26 +0530 Subject: ath10k: set max spatial stream to 4 for 10.4 fw 10.4 fw supports upto 4 spatial stream. Limit max spatial stream to 4 for 10.4 firmware and to 3 for non 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 6 +++--- drivers/net/wireless/ath/ath10k/wmi.h | 3 ++- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7ef960792dbc..79d40d904296 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1095,6 +1095,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: @@ -1104,6 +1105,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: ar->max_num_peers = TARGET_TLV_NUM_PEERS; @@ -1114,6 +1116,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_4: ar->max_num_peers = TARGET_10_4_NUM_PEERS; @@ -1123,6 +1126,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 86c4015270e9..f0811d0a8a7c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -546,6 +546,7 @@ struct ath10k { u32 ht_cap_info; u32 vht_cap_info; u32 num_rf_chains; + u32 max_spatial_stream; /* protected by conf_mutex */ bool ani_enabled; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9f73c5784f45..638332e96931 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3915,10 +3915,10 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) if (ar->fw_api == 1 && ar->fw_version_build > 636) set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); - if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { + if (ar->num_rf_chains > ar->max_spatial_stream) { ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", - ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); - ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; + ar->num_rf_chains, ar->max_spatial_stream); + ar->num_rf_chains = ar->max_spatial_stream; } ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6e806cb7ebe2..0d4efc9c5796 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1747,7 +1747,8 @@ enum wmi_channel_change_cause { /* Indicate reason for channel switch */ #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13) -#define WMI_MAX_SPATIAL_STREAM 3 +#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */ +#define WMI_10_4_MAX_SPATIAL_STREAM 4 /* HT Capabilities*/ #define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ -- cgit v1.2.3-70-g09d2 From d9156b5f6849a1b1185ac62790f36df013b1ade6 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:27 +0530 Subject: ath10k: configure frag desc memory to target for qca99X0 Pre qca99X0 chipsets follows the model where dynamically allocate memory for frag desc on getting new skb for TX. But, this is not going to be the case in qca99X0. It expects frag desc memory to be allocated at boot time and let the driver to reuse allocated memory after every TX completion. So there won't be any dynamic frag memory memory allocation in qca99X0 during data transmission. qca99X0 hardware doesn't need fragment desc address to be programmed in msdu descriptor for every data transaction. It needs to know only starting address of fragment descriptor at the time of the boot. During data transmission, qca99X0 hardware can retrieve corresponding frag addr by adding programmed frag desc base addr + msdu id. Allocate continuous fragment descriptor memory (same size as number of descriptor) at the time of target initialization and configure allocated dma address to the target via HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG. How this is allocated continuous memory is going to be used is not covered in this patch. It just allocates memory and hand over to firmware. If we don't do it at init time, qca99X0 will stall when firmware tries to do TX. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 6 +++ drivers/net/wireless/ath/ath10k/htt.c | 4 ++ drivers/net/wireless/ath/ath10k/htt.h | 11 +++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 76 +++++++++++++++++++++++++++++++- 5 files changed, 96 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 79d40d904296..f79fa6c67ebc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -111,6 +111,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0x00000700, + .continuous_frag_desc = true, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f0811d0a8a7c..2e5c935579c4 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -582,6 +582,12 @@ struct ath10k { */ bool has_shifted_cc_wraparound; + /* Some of chip expects fragment descriptor to be continuous + * memory for any TX operation. Set continuous_frag_desc flag + * for the hardware which have such requirement. + */ + bool continuous_frag_desc; + struct ath10k_hw_params_fw { const char *dir; const char *fw; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6f71f94939fa..4474c3e839db 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -249,5 +249,9 @@ int ath10k_htt_setup(struct ath10k_htt *htt) if (status) return status; + status = ath10k_htt_send_frag_desc_bank_cfg(htt); + if (status) + return status; + return ath10k_htt_send_rx_ring_cfg_ll(htt); } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8e64ace0119b..8bdf1e7dd171 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -87,6 +87,11 @@ struct htt_data_tx_desc_frag { __le32 len; } __packed; +struct htt_msdu_ext_desc { + __le32 tso_flag[4]; + struct htt_data_tx_desc_frag frags[6]; +}; + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, @@ -1466,6 +1471,11 @@ struct ath10k_htt { /* rx_status template */ struct ieee80211_rx_status rx_status; + + struct { + dma_addr_t paddr; + struct htt_msdu_ext_desc *vaddr; + } frag_desc; }; #define RX_HTT_HDR_STATUS_LEN 64 @@ -1533,6 +1543,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt); int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_ampdu, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a60ef7d1d5fc..148d5b607c3c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -84,6 +84,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; + int ret, size; ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); @@ -94,11 +95,31 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, sizeof(struct ath10k_htt_txbuf), 4, 0); if (!htt->tx_pool) { - idr_destroy(&htt->pending_tx); - return -ENOMEM; + ret = -ENOMEM; + goto free_idr_pending_tx; + } + + if (!ar->hw_params.continuous_frag_desc) + goto skip_frag_desc_alloc; + + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->frag_desc.paddr, + GFP_DMA); + if (!htt->frag_desc.vaddr) { + ath10k_warn(ar, "failed to alloc fragment desc memory\n"); + ret = -ENOMEM; + goto free_tx_pool; } +skip_frag_desc_alloc: return 0; + +free_tx_pool: + dma_pool_destroy(htt->tx_pool); +free_idr_pending_tx: + idr_destroy(&htt->pending_tx); + return ret; } static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) @@ -121,9 +142,18 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) void ath10k_htt_tx_free(struct ath10k_htt *htt) { + int size; + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); idr_destroy(&htt->pending_tx); dma_pool_destroy(htt->tx_pool); + + if (htt->frag_desc.vaddr) { + size = htt->max_num_pending_tx * + sizeof(struct htt_msdu_ext_desc); + dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr, + htt->frag_desc.paddr); + } } void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) @@ -201,6 +231,48 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) return 0; } +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + struct sk_buff *skb; + struct htt_cmd *cmd; + int ret, size; + + if (!ar->hw_params.continuous_frag_desc) + return 0; + + if (!htt->frag_desc.paddr) { + ath10k_warn(ar, "invalid frag desc memory\n"); + return -EINVAL; + } + + size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg); + skb = ath10k_htc_alloc_skb(ar, size); + if (!skb) + return -ENOMEM; + + skb_put(skb, size); + cmd = (struct htt_cmd *)skb->data; + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; + cmd->frag_desc_bank_cfg.info = 0; + cmd->frag_desc_bank_cfg.num_banks = 1; + cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); + cmd->frag_desc_bank_cfg.bank_base_addrs[0] = + __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = + __cpu_to_le16(htt->max_num_pending_tx - 1); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", + ret); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; -- cgit v1.2.3-70-g09d2 From 66337b7c67f6237720ba13f6d41b9d8dbcb59cda Mon Sep 17 00:00:00 2001 From: "Dreyfuss, Haim" Date: Thu, 4 Jun 2015 11:45:33 +0300 Subject: iwlwifi: pcie: Fix bug in NIC's PM registers access While cleanig the access to those hw-dependent registers, instead of using the product family type, wrong condition was added mistakenly and enabled 8000 family devices a forbidden access to HW registers, fix it. Fixes: 95411d0455cc ("iwlwifi: pcie: Control access to the NIC's PM registers via iwl_cfg") Signed-off-by: Dreyfuss, Haim Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 43ae658af6ec..608ba1e39a0f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -182,7 +182,7 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val) static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) { - if (!trans->cfg->apmg_not_supported) + if (trans->cfg->apmg_not_supported) return; if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) -- cgit v1.2.3-70-g09d2 From af3f2f740173f8b5c61dba46f900998c5984ccd9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 4 Jun 2015 09:51:11 +0300 Subject: iwlwifi: pcie: don't panic if pcie transport alloc fails iwl_trans_pcie_alloc needs to return a non-zero value if it fails. Otherwise the iwl_drv_start will think that the allocation succeeded. Remove the duplication of err and ret variable and use ret which is the name we usually use in other places of the driver. Fixes: c278754a21e6 ("iwlwifi: mvm: support family 8000 B2/C steps") CC: [4.1] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 608ba1e39a0f..fe61d0aa5550 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2459,7 +2459,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans_pcie *trans_pcie; struct iwl_trans *trans; u16 pci_cmd; - int err; + int ret; trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, cfg, &trans_ops_pcie, 0); @@ -2474,8 +2474,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->ref_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); - err = pci_enable_device(pdev); - if (err) + ret = pci_enable_device(pdev); + if (ret) goto out_no_pci; if (!cfg->base_params->pcie_l1_allowed) { @@ -2491,23 +2491,23 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); - if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!err) - err = pci_set_consistent_dma_mask(pdev, + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); + if (!ret) + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); + if (ret) { + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (!ret) + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); /* both attempts failed: */ - if (err) { + if (ret) { dev_err(&pdev->dev, "No suitable DMA available\n"); goto out_pci_disable_device; } } - err = pci_request_regions(pdev, DRV_NAME); - if (err) { + ret = pci_request_regions(pdev, DRV_NAME); + if (ret) { dev_err(&pdev->dev, "pci_request_regions failed\n"); goto out_pci_disable_device; } @@ -2515,7 +2515,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->hw_base = pci_ioremap_bar(pdev, 0); if (!trans_pcie->hw_base) { dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); - err = -ENODEV; + ret = -ENODEV; goto out_pci_release_regions; } @@ -2527,9 +2527,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->pci_dev = pdev; iwl_disable_interrupts(trans); - err = pci_enable_msi(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err); + ret = pci_enable_msi(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret); /* enable rfkill interrupt: hw bug w/a */ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { @@ -2547,7 +2547,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { unsigned long flags; - int ret; trans->hw_rev = (trans->hw_rev & 0xfff0) | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); @@ -2591,13 +2590,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); - if (iwl_pcie_alloc_ict(trans)) + ret = iwl_pcie_alloc_ict(trans); + if (ret) goto out_pci_disable_msi; - err = request_threaded_irq(pdev->irq, iwl_pcie_isr, + ret = request_threaded_irq(pdev->irq, iwl_pcie_isr, iwl_pcie_irq_handler, IRQF_SHARED, DRV_NAME, trans); - if (err) { + if (ret) { IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); goto out_free_ict; } @@ -2617,5 +2617,5 @@ out_pci_disable_device: pci_disable_device(pdev); out_no_pci: iwl_trans_free(trans); - return ERR_PTR(err); + return ERR_PTR(ret); } -- cgit v1.2.3-70-g09d2 From a052158aa981ca470673f49c636b289ee16894ea Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Fri, 3 Jul 2015 15:33:49 +0200 Subject: ath10k: fix QCA61X4 boot up commit a521ee983d312db7 ("ath10k: Add new reg_address/mask to hw register table") broke QCA61x4 support by providing wrong fw_indicator_address, which should have been 0x0003a028 instead of 0x00009028. User experience was a failing boot up sequence (crashing device during initialization): [ 181.663874] ath10k_pci 0000:02:00.0: enabling device (0000 -> 0002) [ 181.664787] ath10k_pci 0000:02:00.0: pci irq msi-x interrupts 8 irq_mode 0 reset_mode 0 [ 181.688886] ath10k_pci 0000:02:00.0: device has crashed during init [ 181.688897] ath10k_pci 0000:02:00.0: failed to wait for target after cold reset: -70 [ 181.688902] ath10k_pci 0000:02:00.0: failed to reset chip: -70 [ 181.689774] ath10k_pci: probe of 0000:02:00.0 failed with error -70 Fix it by updating the address with correct value. Fixes: a521ee983d31 ("ath10k: Add new reg_address/mask to hw register table") Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1414e1f3c7ac..fef7ccf6e185 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -63,7 +63,7 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_reset_control_ce_rst_mask = 0x00000001, .soc_chip_id_address = 0x000000f0, .scratch_3_address = 0x00000028, - .fw_indicator_address = 0x00009028, + .fw_indicator_address = 0x0003a028, .pcie_local_base_address = 0x00080000, .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, -- cgit v1.2.3-70-g09d2 From 3c7e256a6de378e01098147527082abae05b146e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 3 Jul 2015 19:25:27 +0530 Subject: ath10k: Fix target to cpu address conversion logic In commit 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") mask 0x7fff is added by mistake instead of 0x7ff. Fix this regression. Fixes: 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1b4634a6374d..5778e5277823 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -765,7 +765,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) case ATH10K_HW_QCA6174: val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) & - 0x7fff) << 21; + 0x7ff) << 21; break; case ATH10K_HW_QCA99X0: val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); -- cgit v1.2.3-70-g09d2 From 835d56a10c1fcfb0fee28bb6aceb722e1a6f643a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:34 +0200 Subject: ath10k: don't set cck/ofdm scan flags mac80211 already does provide complete IEs for Probe Requests for hw scan and ath10k firmware was appending duplicate Supported Rates IEs unnecessarily. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 --- drivers/net/wireless/ath/ath10k/wmi.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0f3c17c0c8f8..1a3368dc98a1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4641,9 +4641,6 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.vdev_id = arvif->vdev_id; arg.scan_id = ATH10K_SCAN_ID; - if (!req->no_cck) - arg.scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; - if (req->ie_len) { arg.ie_len = req->ie_len; memcpy(arg.ie, req->ie, arg.ie_len); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 638332e96931..0791a4336e80 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5180,7 +5180,6 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, | WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHANNEL | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->n_bssids = 1; arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; -- cgit v1.2.3-70-g09d2 From 424f26301467daf241a4afe4b6fe82750d4ac624 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:35 +0200 Subject: ath10k: limit multi-vif ps more aggresivelly Further testing proved that multi-channel AP+STA on QCA6174 with RM.2.0-00088 should have powersave force-disabled to avoid beacon misses/skipping on either side which in turn could disrupt communication. Since AP never has arvif->ps don't even bother checking it. Other combinations may be broken as well so disallow powersave with multivif outright unless firmware advertises otherwise. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1a3368dc98a1..c08ad1d994cd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1668,7 +1668,7 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) return 0; } -static int ath10k_mac_ps_vif_count(struct ath10k *ar) +static int ath10k_mac_num_vifs_started(struct ath10k *ar) { struct ath10k_vif *arvif; int num = 0; @@ -1676,7 +1676,7 @@ static int ath10k_mac_ps_vif_count(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) - if (arvif->ps) + if (arvif->is_started) num++; return num; @@ -1700,7 +1700,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) enable_ps = arvif->ps; - if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && + if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 && !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, ar->fw_features)) { ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", -- cgit v1.2.3-70-g09d2 From d710e75d1050cb66fbf6e906addb4a661e444729 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:36 +0200 Subject: ath10k: fix hw roc expiration notifcation The expiration function must not be called when roc is explicitly cancelled by mac80211. However since fcf9844636be ("ath10k: fix hw roc expiration") the notification was never sent when roc actually expired. This fixes some P2P connection setup issues. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2e5c935579c4..78e07051b897 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -633,6 +633,7 @@ struct ath10k { bool is_roc; int vdev_id; int roc_freq; + bool roc_notify; } scan; struct { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c08ad1d994cd..b842612e0b61 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3449,14 +3449,13 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_IDLE: break; case ATH10K_SCAN_RUNNING: - if (ar->scan.is_roc) - ieee80211_remain_on_channel_expired(ar->hw); - /* fall through */ case ATH10K_SCAN_ABORTING: if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, (ar->scan.state == ATH10K_SCAN_ABORTING)); + else if (ar->scan.roc_notify) + ieee80211_remain_on_channel_expired(ar->hw); /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -5459,6 +5458,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ar->scan.is_roc = true; ar->scan.vdev_id = arvif->vdev_id; ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; ret = 0; break; case ATH10K_SCAN_STARTING: @@ -5522,7 +5522,13 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + ath10k_scan_abort(ar); + mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); -- cgit v1.2.3-70-g09d2 From f23e587e55f3607741e29a789efa61ea999f13f8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:37 +0200 Subject: ath10k: update vdev ps state on start Psmode can be forcefully enabled when vdev isn't started. It isn't guaranteed that mac80211 will re-issue psmode setting after vdev is started unless actual bss_conf.ps value has changed. Even if this doesn't fix any problems now it may prevent future breakage. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b842612e0b61..8049d77cfc35 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6222,6 +6222,13 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = true; + ret = ath10k_mac_vif_setup_ps(arvif); + if (ret) { + ath10k_warn(ar, "failed to update vdev %i ps: %d\n", + arvif->vdev_id, ret); + goto err_stop; + } + if (vif->type == NL80211_IFTYPE_MONITOR) { ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr); if (ret) { @@ -6239,6 +6246,7 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, err_stop: ath10k_vdev_stop(arvif); arvif->is_started = false; + ath10k_mac_vif_setup_ps(arvif); err: mutex_unlock(&ar->conf_mutex); -- cgit v1.2.3-70-g09d2 From acd0b27bb13a09dd0a56d4562d3eb4137a7318b2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:38 +0200 Subject: ath10k: fix per-vif queue locking Whenever any vdev was supposed to be paused all Tx queues were stopped (except offchannel) instead of only these associated with the given vdev. This caused subtle issues with multi-channel/multi-vif scenarios, e.g. authentication of station vif could sometimes fail depending on fw tx pause request timing. Fixes: b4aa539dd8f2 ("ath10k: implement tx pause wmi event") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 47 +++++++++---------------------- drivers/net/wireless/ath/ath10k/mac.h | 6 ++-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 34 ++++++++++++++++++---- 3 files changed, 45 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8049d77cfc35..b2e3fe9a9cae 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3034,38 +3034,16 @@ static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif, lockdep_assert_held(&ar->htt.tx_lock); - switch (pause_id) { - case WMI_TLV_TX_PAUSE_ID_MCC: - case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: - case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PS: - case WMI_TLV_TX_PAUSE_ID_IBSS_PS: - switch (action) { - case WMI_TLV_TX_PAUSE_ACTION_STOP: - ath10k_mac_vif_tx_lock(arvif, pause_id); - break; - case WMI_TLV_TX_PAUSE_ACTION_WAKE: - ath10k_mac_vif_tx_unlock(arvif, pause_id); - break; - default: - ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", - action, arvif->vdev_id); - break; - } + switch (action) { + case WMI_TLV_TX_PAUSE_ACTION_STOP: + ath10k_mac_vif_tx_lock(arvif, pause_id); + break; + case WMI_TLV_TX_PAUSE_ACTION_WAKE: + ath10k_mac_vif_tx_unlock(arvif, pause_id); break; - case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: - case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: - case WMI_TLV_TX_PAUSE_ID_HOST: default: - /* FIXME: Some pause_ids aren't vdev specific. Instead they - * target peer_id and tid. Implementing these could improve - * traffic scheduling fairness across multiple connected - * stations in AP/IBSS modes. - */ - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac ignoring unsupported tx pause vdev %i id %d\n", - arvif->vdev_id, pause_id); + ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", + action, arvif->vdev_id); break; } } @@ -3082,12 +3060,15 @@ static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_mac_tx_pause *arg = data; + if (arvif->vdev_id != arg->vdev_id) + return; + ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action); } -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action) +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action) { struct ath10k_mac_tx_pause arg = { .vdev_id = vdev_id, diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index b291f063705c..e3cefe4c7cfd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -61,9 +61,9 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif, void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb); void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id); -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action); +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action); u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, u8 hw_rate); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index ced35a1e0675..4189d4a90ce0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -377,12 +377,34 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n", pause_id, action, vdev_map, peer_id, tid_map); - for (vdev_id = 0; vdev_map; vdev_id++) { - if (!(vdev_map & BIT(vdev_id))) - continue; - - vdev_map &= ~BIT(vdev_id); - ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action); + switch (pause_id) { + case WMI_TLV_TX_PAUSE_ID_MCC: + case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: + case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PS: + case WMI_TLV_TX_PAUSE_ID_IBSS_PS: + for (vdev_id = 0; vdev_map; vdev_id++) { + if (!(vdev_map & BIT(vdev_id))) + continue; + + vdev_map &= ~BIT(vdev_id); + ath10k_mac_handle_tx_pause_vdev(ar, vdev_id, pause_id, + action); + } + break; + case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: + case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: + case WMI_TLV_TX_PAUSE_ID_HOST: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unsupported tx pause id %d\n", + pause_id); + break; + default: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unknown tx pause vdev %d\n", + pause_id); + break; } kfree(tb); -- cgit v1.2.3-70-g09d2 From ed25b113a955e62aeaba49a3ec71faea4f25bf34 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:39 +0200 Subject: ath10k: tweak interface combinations Concurrent AP/GO operation on different channels isn't really supported well by the firmware so it's better to remove it from being advertised. Also tune the way station and p2p client interface limits are expressed to allow station + 2x p2p client or station + p2p client + p2p go. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 39 ++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b2e3fe9a9cae..caa56ce5d907 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6557,8 +6557,11 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { { .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO), }, @@ -6568,6 +6571,26 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { }, }; +static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = { { .max = 1, @@ -6586,7 +6609,7 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { { .limits = ath10k_tlv_if_limit, .num_different_channels = 1, - .max_interfaces = 3, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, { @@ -6600,10 +6623,16 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { { .limits = ath10k_tlv_if_limit, - .num_different_channels = 2, - .max_interfaces = 3, + .num_different_channels = 1, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, + { + .limits = ath10k_tlv_qcs_if_limit, + .num_different_channels = 2, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_tlv_qcs_if_limit), + }, { .limits = ath10k_tlv_if_limit_ibss, .num_different_channels = 1, -- cgit v1.2.3-70-g09d2 From 00798c38f49eb028b0c5fac01293783206af29fb Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 19:24:35 +0200 Subject: ipw2100: fix timeout bug - always evaluated to 0 commit 2c86c275015c ("Add ipw2100 wireless driver.") introduced HW_PHY_OFF_LOOP_DELAY (HZ / 5000) which always evaluated to 0. Clarified by Stanislav Yakovlev that it should be 50 milliseconds thus fixed up to msecs_to_jiffies(50). Signed-off-by: Nicholas Mc Guire Acked-by: Stanislav Yakovlev Signed-off-by: Kalle Valo --- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 08eb229e7816..36818c7f30b9 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1410,7 +1410,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) { -#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) +#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50)) struct host_command cmd = { .host_command = CARD_DISABLE_PHY_OFF, -- cgit v1.2.3-70-g09d2 From 8f010d9ca88f9023650b2e54b74c84ab63a19d02 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 11:46:42 +0200 Subject: ath9k: DFS - consider ext_channel pulses only in HT40 mode The chip reports radar pulses on extension channel even if operating in HT20 mode. This patch adds a sanity check for HT40 mode before it feeds pulses on extension channel to the pattern detector. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index e98a9eaba7ff..5025a4e91a8b 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, sc->dfs_prev_pulse_ts = pe.ts; if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) ath9k_dfs_process_radar_pulse(sc, &pe); - if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { + if (IS_CHAN_HT40(ah->curchan) && + ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; ath9k_dfs_process_radar_pulse(sc, &pe); } -- cgit v1.2.3-70-g09d2 From 8fc2b61a36fe17f744b445a26599a6cac9e6c1c0 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 12:52:16 +0200 Subject: ath9k: DFS - add pulse chirp detection for FCC FCC long pulse radar (type 5) requires pulses to be checked for chirping. This patch implements chirp detection based on the FFT data provided for long pulses. A chirp is detected when a set of criteria defined by FCC pulse characteristics is met, including * have at least 4 FFT samples * max_bin index moves equidistantly between samples * the gradient is within defined range The chirp detection has been tested with reference radar generating devices and proved to work reliably. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 167 +++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 5025a4e91a8b..1ece42c2443d 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -30,6 +30,157 @@ struct ath_radar_data { u8 pulse_length_pri; }; +/**** begin: CHIRP ************************************************************/ + +/* min and max gradients for defined FCC chirping pulses, given by + * - 20MHz chirp width over a pulse width of 50us + * - 5MHz chirp width over a pulse width of 100us + */ +static const int BIN_DELTA_MIN = 1; +static const int BIN_DELTA_MAX = 10; + +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ +#define NUM_DIFFS 3 +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1); + +/* Threshold for difference of delta peaks */ +static const int MAX_DIFF = 2; + +/* width range to be checked for chirping */ +static const int MIN_CHIRP_PULSE_WIDTH = 20; +static const int MAX_CHIRP_PULSE_WIDTH = 110; + +struct ath9k_dfs_fft_20 { + u8 bin[28]; + u8 lower_bins[3]; +} __packed; +struct ath9k_dfs_fft_40 { + u8 bin[64]; + u8 lower_bins[3]; + u8 upper_bins[3]; +} __packed; + +static inline int fft_max_index(u8 *bins) +{ + return (bins[2] & 0xfc) >> 2; +} +static inline int fft_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; +} +static inline u8 fft_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, + bool is_ctl, bool is_ext) +{ + const int DFS_UPPER_BIN_OFFSET = 64; + /* if detected radar on both channels, select the significant one */ + if (is_ctl && is_ext) { + /* first check wether channels have 'strong' bins */ + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; + is_ext = fft_bitmap_weight(fft->upper_bins) != 0; + + /* if still unclear, take higher magnitude */ + if (is_ctl && is_ext) { + int mag_lower = fft_max_magnitude(fft->lower_bins); + int mag_upper = fft_max_magnitude(fft->upper_bins); + if (mag_upper > mag_lower) + is_ctl = false; + else + is_ext = false; + } + } + if (is_ctl) + return fft_max_index(fft->lower_bins); + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; +} +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, + int datalen, bool is_ctl, bool is_ext) +{ + int i; + int max_bin[FFT_NUM_SAMPLES]; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int prev_delta; + + if (IS_CHAN_HT40(ah->curchan)) { + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* HW sometimes adds 2 garbage bytes in front of FFT samples */ + if ((datalen % sizeof(*fft)) == 2) { + fft = (struct ath9k_dfs_fft_40 *) (data + 2); + ath_dbg(common, DFS, "fixing datalen by 2\n"); + } + if (IS_CHAN_HT40MINUS(ah->curchan)) { + int temp = is_ctl; + is_ctl = is_ext; + is_ext = temp; + } + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, + is_ext); + } else { + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* in ht20, this is a 6-bit signed number => shift it to 0 */ + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; + } + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", + max_bin[0], max_bin[1], max_bin[2], max_bin[3]); + + /* Check for chirp attributes within specs + * a) delta of adjacent max_bins is within range + * b) delta of adjacent deltas are within tolerance + */ + prev_delta = 0; + for (i = 0; i < NUM_DIFFS; i++) { + int ddelta = -1; + int delta = max_bin[i + 1] - max_bin[i]; + + /* ensure gradient is within valid range */ + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { + ath_dbg(common, DFS, "CHIRP: invalid delta %d " + "in sample %d\n", delta, i); + return false; + } + if (i == 0) + goto done; + ddelta = delta - prev_delta; + if (abs(ddelta) > MAX_DIFF) { + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", + ddelta); + return false; + } +done: + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", + i, delta, ddelta); + prev_delta = delta; + } + return true; +} +/**** end: CHIRP **************************************************************/ + /* convert pulse duration to usecs, considering clock mode */ static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) { @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, return false; } - /* - * TODO: check chirping pulses - * checks for chirping are dependent on the DFS regulatory domain - * used, which is yet TBD - */ - /* convert duration to usecs */ pe->width = dur_to_usecs(sc->sc_ah, dur); pe->rssi = rssi; @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) return; + if (pe.width > MIN_CHIRP_PULSE_WIDTH && + pe.width < MAX_CHIRP_PULSE_WIDTH) { + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); + int clen = datalen - 3; + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); + } else { + pe.chirp = false; + } + ath_dbg(common, DFS, "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " "width=%d, rssi=%d, delta_ts=%llu\n", -- cgit v1.2.3-70-g09d2 From 7865598ec24ab4162d976d0bd75a9b2a2f58cd64 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 21 Jun 2015 19:47:46 +0200 Subject: ath9k_hw: fix device ID check for AR956x Because of the missing return, the macVersion value was being overwritten with an invalid register read Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5e15e8e10ed3..a31a6804dc34 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) return; case AR9300_DEVID_QCA956X: ah->hw_version.macVersion = AR_SREV_VERSION_9561; + return; } val = REG_READ(ah, AR_SREV) & AR_SREV_ID; -- cgit v1.2.3-70-g09d2 From f9e5554cd8ca1d1212ec922755b397a20f737923 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 4 Jun 2015 11:09:47 +0300 Subject: iwlwifi: pcie: prepare the device before accessing it For 8000 series, we need to access the device to know what firmware to load. Before we do so, we need to prepare the device otherwise we might not be able to access the hardware. Fixes: c278754a21e6 ("iwlwifi: mvm: support family 8000 B2/C steps") CC: [4.1] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index fe61d0aa5550..6203c4ad9bba 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2551,6 +2551,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans->hw_rev = (trans->hw_rev & 0xfff0) | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); + ret = iwl_pcie_prepare_card_hw(trans); + if (ret) { + IWL_WARN(trans, "Exit HW not ready\n"); + goto out_pci_disable_msi; + } + /* * in-order to recognize C step driver should read chip version * id located at the AUX bus MISC address space. -- cgit v1.2.3-70-g09d2 From 00fd233ac491708d1f64b7176be73c84a18a54a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Jun 2015 16:04:01 +0200 Subject: iwlwifi: mvm: check time-event vif to avoid bad deletion The time event is initialized relatively late in interface (mvmvif) initialization, so it's possible to fail before that happens. As a consequence, the driver will crash if it ever tries to delete this time event in case initialization was unsuccessful. Avoid this by using the time event's vif pointer to indicate validity. The vif pointer is != NULL whenever the id is != TE_MAX, except for this special error case where the vif pointer will have the correct property (as the whole memory is cleared on allocation) whereas the id is 0, causing a crash in trying to delete the time event from the list. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index d24b6a83e68c..e472729e5f14 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -86,7 +86,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, { lockdep_assert_held(&mvm->time_event_lock); - if (te_data->id == TE_MAX) + if (!te_data->vif) return; list_del(&te_data->list); -- cgit v1.2.3-70-g09d2 From b8eee757077e2aced778cfad8c1d989e2deec584 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Mon, 22 Jun 2015 13:44:05 +0300 Subject: iwlwifi: edit the 3165 series and 8000 series PCI IDs Add new 3165 devices support. Add one new 8000 series device support. Remove support for 0x0000, 0xC030 and 0xD030 sub-system IDs in the 8000 series. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2ed1e4d2774d..9f65c1cff1b1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -368,12 +368,14 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 3165 Series */ {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3166, 0x4212, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)}, /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, @@ -426,9 +428,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, -- cgit v1.2.3-70-g09d2 From 8465fe6ac5cc054a7969e78e56aea40cd7808540 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Sun, 21 Jun 2015 12:06:13 +0300 Subject: iwlwifi: mvm: Add preemptive flag to scheulded scan Add preemptive flag to scheduled scan command flags. Without this flag, all scan requests after scheduled scan was started will be delayed until scheduled scan stops. As a result, P2P_FIND will be blocked while scheduled scan is active. This flag was omitted during refactoring. Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 3 ++- drivers/net/wireless/iwlwifi/mvm/scan.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 5e4cbdb44c60..737774a01c74 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -660,7 +660,8 @@ struct iwl_scan_config { * iwl_umac_scan_flags *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request * can be preempted by other scan requests with higher priority. - * The low priority scan is aborted. + * The low priority scan will be resumed when the higher proirity scan is + * completed. *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5de144968723..5000bfcded61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1109,6 +1109,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params)); + if (type == IWL_MVM_SCAN_SCHED) + cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); + if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | -- cgit v1.2.3-70-g09d2 From 255ba06533f09875973d6b400f9c5b88065938df Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sat, 11 Jul 2015 22:30:49 +0300 Subject: Revert "iwlwifi: pcie: New RBD allocation model" This reverts commit 5f17570354f91275b0a37a4da33d29a2ab57d32e. This patch introduced a high latency in buffer allocation under extreme load. This latency caused a firmwre crash. The same scenario works fine with this patch reverted. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fh.h | 6 + drivers/net/wireless/iwlwifi/pcie/internal.h | 51 +--- drivers/net/wireless/iwlwifi/pcie/rx.c | 414 ++++++--------------------- 3 files changed, 97 insertions(+), 374 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index d56064861a9c..d45dc021cda2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -438,6 +438,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RX_QUEUE_MASK 255 #define RX_QUEUE_SIZE_LOG 8 +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 31f72a61cc3f..376b84e54ad7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -44,15 +44,6 @@ #include "iwl-io.h" #include "iwl-op-mode.h" -/* - * RX related structures and functions - */ -#define RX_NUM_QUEUES 1 -#define RX_POST_REQ_ALLOC 2 -#define RX_CLAIM_REQ_ALLOC 8 -#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES) -#define RX_LOW_WATERMARK 8 - struct iwl_host_cmd; /*This file includes the declaration that are internal to the @@ -86,29 +77,29 @@ struct isr_statistics { * struct iwl_rxq - Rx queue * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) + * @pool: + * @queue: * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free - * @used_count: Number of RBDs handled to allocator to use for allocation * @write_actual: - * @rx_free: list of RBDs with allocated RB ready for use - * @rx_used: list of RBDs with no RB attached + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB * @need_update: flag to indicate we need to update read/write index * @rb_stts: driver's pointer to receive buffer status * @rb_stts_dma: bus address of receive buffer status * @lock: - * @pool: initial pool of iwl_rx_mem_buffer for the queue - * @queue: actual rx queue * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ struct iwl_rxq { __le32 *bd; dma_addr_t bd_dma; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; u32 read; u32 write; u32 free_count; - u32 used_count; u32 write_actual; struct list_head rx_free; struct list_head rx_used; @@ -116,32 +107,6 @@ struct iwl_rxq { struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE]; - struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; -}; - -/** - * struct iwl_rb_allocator - Rx allocator - * @pool: initial pool of allocator - * @req_pending: number of requests the allcator had not processed yet - * @req_ready: number of requests honored and ready for claiming - * @rbd_allocated: RBDs with pages allocated and ready to be handled to - * the queue. This is a list of &struct iwl_rx_mem_buffer - * @rbd_empty: RBDs with no page attached for allocator use. This is a list - * of &struct iwl_rx_mem_buffer - * @lock: protects the rbd_allocated and rbd_empty lists - * @alloc_wq: work queue for background calls - * @rx_alloc: work struct for background calls - */ -struct iwl_rb_allocator { - struct iwl_rx_mem_buffer pool[RX_POOL_SIZE]; - atomic_t req_pending; - atomic_t req_ready; - struct list_head rbd_allocated; - struct list_head rbd_empty; - spinlock_t lock; - struct workqueue_struct *alloc_wq; - struct work_struct rx_alloc; }; struct iwl_dma_ptr { @@ -285,7 +250,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data - * @rba: allocator for RX replenishing + * @rx_replenish: work that will be called when buffers need to be allocated * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM @@ -308,7 +273,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) */ struct iwl_trans_pcie { struct iwl_rxq rxq; - struct iwl_rb_allocator rba; + struct work_struct rx_replenish; struct iwl_trans *trans; struct iwl_drv *drv; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a3fbaa0ef5e0..adad8d0fae7f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -74,29 +74,16 @@ * resets the Rx queue buffers with new memory. * * The management in the driver is as follows: - * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free. - * When the interrupt handler is called, the request is processed. - * The page is either stolen - transferred to the upper layer - * or reused - added immediately to the iwl->rxq->rx_free list. - * + When the page is stolen - the driver updates the matching queue's used - * count, detaches the RBD and transfers it to the queue used list. - * When there are two used RBDs - they are transferred to the allocator empty - * list. Work is then scheduled for the allocator to start allocating - * eight buffers. - * When there are another 6 used RBDs - they are transferred to the allocator - * empty list and the driver tries to claim the pre-allocated buffers and - * add them to iwl->rxq->rx_free. If it fails - it continues to claim them - * until ready. - * When there are 8+ buffers in the free list - either from allocation or from - * 8 reused unstolen pages - restock is called to update the FW and indexes. - * + In order to make sure the allocator always has RBDs to use for allocation - * the allocator has initial pool in the size of num_queues*(8-2) - the - * maximum missing RBDs per allocation request (request posted with 2 - * empty RBDs, there is no guarantee when the other 6 RBDs are supplied). - * The queues supplies the recycle of the rest of the RBDs. + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replenish the iwl->rxq->rx_free. + * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) * + A received packet is processed and handed to the kernel network stack, * detached from the iwl->rxq. The driver 'processed' index is updated. - * + If there are no allocated buffers in iwl->rxq->rx_free, + * + The Host/Firmware iwl->rxq is replenished at irq thread time from the + * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. * If there were enough free buffers and RX_STALLED is set it is cleared. * @@ -105,32 +92,18 @@ * * iwl_rxq_alloc() Allocates rx_free * iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_pcie_rxq_restock. - * Used only during initialization. + * iwl_pcie_rxq_restock * iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates - * the WRITE index. - * iwl_pcie_rx_allocator() Background work for allocating pages. + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_pcie_rx_replenish * * -- enable interrupts -- * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. - * Posts and claims requests to the allocator. * Calls iwl_pcie_rxq_restock to refill any empty * slots. - * - * RBD life-cycle: - * - * Init: - * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue - * - * Regular Receive interrupt: - * Page Stolen: - * rxq.queue -> rxq.rx_used -> allocator.rbd_empty -> - * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue - * Page not Stolen: - * rxq.queue -> rxq.rx_free -> rxq.queue * ... * */ @@ -267,6 +240,10 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) rxq->free_count--; } spin_unlock(&rxq->lock); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ @@ -277,44 +254,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) } } -/* - * iwl_pcie_rx_alloc_page - allocates and returns a page. - * - */ -static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rxq *rxq = &trans_pcie->rxq; - struct page *page; - gfp_t gfp_mask = GFP_KERNEL; - - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - - if (trans_pcie->rx_page_order > 0) - gfp_mask |= __GFP_COMP; - - /* Alloc a new receive buffer */ - page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); - if (!page) { - if (net_ratelimit()) - IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n", - trans_pcie->rx_page_order); - /* Issue an error if the hardware has consumed more than half - * of its free buffer list and we don't have enough - * pre-allocated buffers. -` */ - if (rxq->free_count <= RX_LOW_WATERMARK && - iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) && - net_ratelimit()) - IWL_CRIT(trans, - "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n", - rxq->free_count); - return NULL; - } - return page; -} - /* * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD * @@ -324,12 +263,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans) * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly * allocated buffers. */ -static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans) +static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; + gfp_t gfp_mask = priority; while (1) { spin_lock(&rxq->lock); @@ -339,10 +279,32 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans) } spin_unlock(&rxq->lock); + if (rxq->free_count > RX_LOW_WATERMARK) + gfp_mask |= __GFP_NOWARN; + + if (trans_pcie->rx_page_order > 0) + gfp_mask |= __GFP_COMP; + /* Alloc a new receive buffer */ - page = iwl_pcie_rx_alloc_page(trans); - if (!page) + page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); + if (!page) { + if (net_ratelimit()) + IWL_DEBUG_INFO(trans, "alloc_pages failed, " + "order: %d\n", + trans_pcie->rx_page_order); + + if ((rxq->free_count <= RX_LOW_WATERMARK) && + net_ratelimit()) + IWL_CRIT(trans, "Failed to alloc_pages with %s." + "Only %u free buffers remaining.\n", + priority == GFP_ATOMIC ? + "GFP_ATOMIC" : "GFP_KERNEL", + rxq->free_count); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ return; + } spin_lock(&rxq->lock); @@ -393,7 +355,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) lockdep_assert_held(&rxq->lock); - for (i = 0; i < RX_QUEUE_SIZE; i++) { + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { if (!rxq->pool[i].page) continue; dma_unmap_page(trans->dev, rxq->pool[i].page_dma, @@ -410,144 +372,32 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) * When moving to rx_free an page is allocated for the slot. * * Also restock the Rx queue via iwl_pcie_rxq_restock. - * This is called only during initialization + * This is called as a scheduled work item (except for during initialization) */ -static void iwl_pcie_rx_replenish(struct iwl_trans *trans) +static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp) { - iwl_pcie_rxq_alloc_rbs(trans); + iwl_pcie_rxq_alloc_rbs(trans, gfp); iwl_pcie_rxq_restock(trans); } -/* - * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues - * - * Allocates for each received request 8 pages - * Called as a scheduled work item. - */ -static void iwl_pcie_rx_allocator(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rb_allocator *rba = &trans_pcie->rba; - - while (atomic_read(&rba->req_pending)) { - int i; - struct list_head local_empty; - struct list_head local_allocated; - - INIT_LIST_HEAD(&local_allocated); - spin_lock(&rba->lock); - /* swap out the entire rba->rbd_empty to a local list */ - list_replace_init(&rba->rbd_empty, &local_empty); - spin_unlock(&rba->lock); - - for (i = 0; i < RX_CLAIM_REQ_ALLOC;) { - struct iwl_rx_mem_buffer *rxb; - struct page *page; - - /* List should never be empty - each reused RBD is - * returned to the list, and initial pool covers any - * possible gap between the time the page is allocated - * to the time the RBD is added. - */ - BUG_ON(list_empty(&local_empty)); - /* Get the first rxb from the rbd list */ - rxb = list_first_entry(&local_empty, - struct iwl_rx_mem_buffer, list); - BUG_ON(rxb->page); - - /* Alloc a new receive buffer */ - page = iwl_pcie_rx_alloc_page(trans); - if (!page) - continue; - rxb->page = page; - - /* Get physical address of the RB */ - rxb->page_dma = dma_map_page(trans->dev, page, 0, - PAGE_SIZE << trans_pcie->rx_page_order, - DMA_FROM_DEVICE); - if (dma_mapping_error(trans->dev, rxb->page_dma)) { - rxb->page = NULL; - __free_pages(page, trans_pcie->rx_page_order); - continue; - } - /* dma address must be no more than 36 bits */ - BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); - /* and also 256 byte aligned! */ - BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); - - /* move the allocated entry to the out list */ - list_move(&rxb->list, &local_allocated); - i++; - } - - spin_lock(&rba->lock); - /* add the allocated rbds to the allocator allocated list */ - list_splice_tail(&local_allocated, &rba->rbd_allocated); - /* add the unused rbds back to the allocator empty list */ - list_splice_tail(&local_empty, &rba->rbd_empty); - spin_unlock(&rba->lock); - - atomic_dec(&rba->req_pending); - atomic_inc(&rba->req_ready); - } -} - -/* - * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages -.* -.* Called by queue when the queue posted allocation request and - * has freed 8 RBDs in order to restock itself. - */ -static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans, - struct iwl_rx_mem_buffer - *out[RX_CLAIM_REQ_ALLOC]) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rb_allocator *rba = &trans_pcie->rba; - int i; - - if (atomic_dec_return(&rba->req_ready) < 0) { - atomic_inc(&rba->req_ready); - IWL_DEBUG_RX(trans, - "Allocation request not ready, pending requests = %d\n", - atomic_read(&rba->req_pending)); - return -ENOMEM; - } - - spin_lock(&rba->lock); - for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) { - /* Get next free Rx buffer, remove it from free list */ - out[i] = list_first_entry(&rba->rbd_allocated, - struct iwl_rx_mem_buffer, list); - list_del(&out[i]->list); - } - spin_unlock(&rba->lock); - - return 0; -} - -static void iwl_pcie_rx_allocator_work(struct work_struct *data) +static void iwl_pcie_rx_replenish_work(struct work_struct *data) { - struct iwl_rb_allocator *rba_p = - container_of(data, struct iwl_rb_allocator, rx_alloc); struct iwl_trans_pcie *trans_pcie = - container_of(rba_p, struct iwl_trans_pcie, rba); + container_of(data, struct iwl_trans_pcie, rx_replenish); - iwl_pcie_rx_allocator(trans_pcie->trans); + iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL); } static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - struct iwl_rb_allocator *rba = &trans_pcie->rba; struct device *dev = trans->dev; memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); spin_lock_init(&rxq->lock); - spin_lock_init(&rba->lock); if (WARN_ON(rxq->bd || rxq->rb_stts)) return -EINVAL; @@ -637,49 +487,15 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); rxq->free_count = 0; - rxq->used_count = 0; - for (i = 0; i < RX_QUEUE_SIZE; i++) + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) list_add(&rxq->pool[i].list, &rxq->rx_used); } -static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba) -{ - int i; - - lockdep_assert_held(&rba->lock); - - INIT_LIST_HEAD(&rba->rbd_allocated); - INIT_LIST_HEAD(&rba->rbd_empty); - - for (i = 0; i < RX_POOL_SIZE; i++) - list_add(&rba->pool[i].list, &rba->rbd_empty); -} - -static void iwl_pcie_rx_free_rba(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rb_allocator *rba = &trans_pcie->rba; - int i; - - lockdep_assert_held(&rba->lock); - - for (i = 0; i < RX_POOL_SIZE; i++) { - if (!rba->pool[i].page) - continue; - dma_unmap_page(trans->dev, rba->pool[i].page_dma, - PAGE_SIZE << trans_pcie->rx_page_order, - DMA_FROM_DEVICE); - __free_pages(rba->pool[i].page, trans_pcie->rx_page_order); - rba->pool[i].page = NULL; - } -} - int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, err; if (!rxq->bd) { @@ -687,21 +503,11 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) if (err) return err; } - if (!rba->alloc_wq) - rba->alloc_wq = alloc_workqueue("rb_allocator", - WQ_HIGHPRI | WQ_UNBOUND, 1); - INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work); - - spin_lock(&rba->lock); - atomic_set(&rba->req_pending, 0); - atomic_set(&rba->req_ready, 0); - /* free all first - we might be reconfigured for a different size */ - iwl_pcie_rx_free_rba(trans); - iwl_pcie_rx_init_rba(rba); - spin_unlock(&rba->lock); spin_lock(&rxq->lock); + INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work); + /* free all first - we might be reconfigured for a different size */ iwl_pcie_rxq_free_rbs(trans); iwl_pcie_rx_init_rxb_lists(rxq); @@ -716,7 +522,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans); + iwl_pcie_rx_replenish(trans, GFP_KERNEL); iwl_pcie_rx_hw_init(trans, rxq); @@ -731,7 +537,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - struct iwl_rb_allocator *rba = &trans_pcie->rba; /*if rxq->bd is NULL, it means that nothing has been allocated, * exit now */ @@ -740,15 +545,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) return; } - cancel_work_sync(&rba->rx_alloc); - if (rba->alloc_wq) { - destroy_workqueue(rba->alloc_wq); - rba->alloc_wq = NULL; - } - - spin_lock(&rba->lock); - iwl_pcie_rx_free_rba(trans); - spin_unlock(&rba->lock); + cancel_work_sync(&trans_pcie->rx_replenish); spin_lock(&rxq->lock); iwl_pcie_rxq_free_rbs(trans); @@ -769,43 +566,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rxq->rb_stts = NULL; } -/* - * iwl_pcie_rx_reuse_rbd - Recycle used RBDs - * - * Called when a RBD can be reused. The RBD is transferred to the allocator. - * When there are 2 empty RBDs - a request for allocation is posted - */ -static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, - struct iwl_rx_mem_buffer *rxb, - struct iwl_rxq *rxq) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_rb_allocator *rba = &trans_pcie->rba; - - /* Count the used RBDs */ - rxq->used_count++; - - /* Move the RBD to the used list, will be moved to allocator in batches - * before claiming or posting a request*/ - list_add_tail(&rxb->list, &rxq->rx_used); - - /* If we have RX_POST_REQ_ALLOC new released rx buffers - - * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is - * used for the case we failed to claim RX_CLAIM_REQ_ALLOC, - * after but we still need to post another request. - */ - if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) { - /* Move the 2 RBDs to the allocator ownership. - Allocator has another 6 from pool for the request completion*/ - spin_lock(&rba->lock); - list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); - spin_unlock(&rba->lock); - - atomic_inc(&rba->req_pending); - queue_work(rba->alloc_wq, &rba->rx_alloc); - } -} - static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb) { @@ -928,13 +688,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, */ __free_pages(rxb->page, trans_pcie->rx_page_order); rxb->page = NULL; - iwl_pcie_rx_reuse_rbd(trans, rxb, rxq); + list_add_tail(&rxb->list, &rxq->rx_used); } else { list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; } } else - iwl_pcie_rx_reuse_rbd(trans, rxb, rxq); + list_add_tail(&rxb->list, &rxq->rx_used); } /* @@ -944,7 +704,10 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - u32 r, i, j; + u32 r, i; + u8 fill_rx = 0; + u32 count = 8; + int total_empty; restart: spin_lock(&rxq->lock); @@ -957,6 +720,14 @@ restart: if (i == r) IWL_DEBUG_RX(trans, "HW = SW = %d\n", r); + /* calculate total frames need to be restock after handling RX */ + total_empty = r - rxq->write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; + while (i != r) { struct iwl_rx_mem_buffer *rxb; @@ -968,48 +739,29 @@ restart: iwl_pcie_rx_handle_rb(trans, rxb); i = (i + 1) & RX_QUEUE_MASK; - - /* If we have RX_CLAIM_REQ_ALLOC released rx buffers - - * try to claim the pre-allocated buffers from the allocator */ - if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) { - struct iwl_rb_allocator *rba = &trans_pcie->rba; - struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC]; - - /* Add the remaining 6 empty RBDs for allocator use */ - spin_lock(&rba->lock); - list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); - spin_unlock(&rba->lock); - - /* If not ready - continue, will try to reclaim later. - * No need to reschedule work - allocator exits only on - * success */ - if (!iwl_pcie_rx_allocator_get(trans, out)) { - /* If success - then RX_CLAIM_REQ_ALLOC - * buffers were retrieved and should be added - * to free list */ - rxq->used_count -= RX_CLAIM_REQ_ALLOC; - for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) { - list_add_tail(&out[j]->list, - &rxq->rx_free); - rxq->free_count++; - } + /* If there are a lot of unused frames, + * restock the Rx queue so ucode wont assert. */ + if (fill_rx) { + count++; + if (count >= 8) { + rxq->read = i; + spin_unlock(&rxq->lock); + iwl_pcie_rx_replenish(trans, GFP_ATOMIC); + count = 0; + goto restart; } } - /* handle restock for two cases: - * - we just pulled buffers from the allocator - * - we have 8+ unstolen pages accumulated */ - if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { - rxq->read = i; - spin_unlock(&rxq->lock); - iwl_pcie_rxq_restock(trans); - goto restart; - } } /* Backtrack one entry */ rxq->read = i; spin_unlock(&rxq->lock); + if (fill_rx) + iwl_pcie_rx_replenish(trans, GFP_ATOMIC); + else + iwl_pcie_rxq_restock(trans); + if (trans_pcie->napi.poll) napi_gro_flush(&trans_pcie->napi, false); } -- cgit v1.2.3-70-g09d2 From be88a1ada9b97bb016196b7f4a1fc2fe2f798529 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 1 Jul 2015 17:28:34 +0300 Subject: iwlwifi: nvm: remove mac address byte swapping in 8000 family This fixes the byte order copying in the MAO (Mac Override Section) section from the PNVM, as the byte swapping is not required anymore in the 8000 family. Due to the byte swapping, the driver was reporting an incorrect MAC adddress. CC: [4.1] Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 80fefe7d7b8c..3b8e85e51002 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -540,13 +540,11 @@ static void iwl_set_hw_address_family_8000(struct device *dev, hw_addr = (const u8 *)(mac_override + MAC_ADDRESS_OVERRIDE_FAMILY_8000); - /* The byte order is little endian 16 bit, meaning 214365 */ - data->hw_addr[0] = hw_addr[1]; - data->hw_addr[1] = hw_addr[0]; - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[3] = hw_addr[2]; - data->hw_addr[4] = hw_addr[5]; - data->hw_addr[5] = hw_addr[4]; + /* + * Store the MAC address from MAO section. + * No byte swapping is required in MAO section + */ + memcpy(data->hw_addr, hw_addr, ETH_ALEN); /* * Force the use of the OTP MAC address in case of reserved MAC -- cgit v1.2.3-70-g09d2 From af9f9b22beee70aae58651cdbb9d6375e6e51797 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jun 2015 16:02:32 +0200 Subject: mac80211: don't store napi struct When introducing multiple RX queues, a single NAPI struct will not be sufficient. Instead of trying to store multiple, simply change the API to have the NAPI struct passed to the RX function. This of course means that drivers using rx_irqsafe() cannot use NAPI, but that seems a reasonable trade-off, particularly since only two of all drivers are currently using it at all. While at it, we can now remove the IEEE80211_RX_REORDER_TIMER flag again since this code path cannot have a napi struct anyway. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/dev.h | 2 ++ drivers/net/wireless/iwlwifi/dvm/main.c | 3 ++- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rx.c | 2 +- include/net/mac80211.h | 37 +++++++++++++++++++++------------ net/mac80211/ieee80211_i.h | 6 +----- net/mac80211/main.c | 12 ----------- net/mac80211/rx.c | 18 +++++++++------- 10 files changed, 44 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd..074977ede343 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -669,6 +669,8 @@ struct iwl_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; + struct napi_struct *napi; + struct list_head calib_results; struct workqueue_struct *workqueue; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 234e30f498b2..644819563cf0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2037,7 +2037,8 @@ static void iwl_napi_add(struct iwl_op_mode *op_mode, { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + priv->napi = napi; } static const struct iwl_op_mode_ops iwl_dvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610..5a91f5d6b1dc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -786,7 +786,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx(priv->hw, skb); + ieee80211_rx_napi(priv->hw, skb, priv->napi); } static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825..605f57a2c6be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -559,6 +559,7 @@ struct iwl_mvm { const struct iwl_cfg *cfg; struct iwl_phy_db *phy_db; struct ieee80211_hw *hw; + struct napi_struct *napi; /* for protecting access to iwl_mvm */ struct mutex mutex; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffd..3967df63e0f3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1316,7 +1316,8 @@ static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + mvm->napi = napi; } static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13a..9ff0b4321df3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -129,7 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, fraglen, rxb->truesize); } - ieee80211_rx(mvm->hw, skb); + ieee80211_rx_napi(mvm->hw, skb, mvm->napi); } /* diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 43dbddfa06c0..ff68b8c4ab35 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3694,20 +3694,28 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); void ieee80211_restart_hw(struct ieee80211_hw *hw); /** - * ieee80211_napi_add - initialize mac80211 NAPI context - * @hw: the hardware to initialize the NAPI context on - * @napi: the NAPI context to initialize - * @napi_dev: dummy NAPI netdevice, here to not waste the space if the - * driver doesn't use NAPI - * @poll: poll function - * @weight: default weight + * ieee80211_rx_napi - receive frame from NAPI context * - * See also netif_napi_add(). + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee80211 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls to + * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be + * mixed for a single hardware. Must not run concurrently with + * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * + * This function must be called with BHs disabled. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + * @napi: the NAPI context */ -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight); +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi); /** * ieee80211_rx - receive frame @@ -3729,7 +3737,10 @@ void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); +static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + ieee80211_rx_napi(hw, skb, NULL); +} /** * ieee80211_rx_irqsafe - receive frame diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 361bb3ca335c..7d75f93bac7d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -202,8 +202,6 @@ enum ieee80211_packet_rx_flags { * @IEEE80211_RX_CMNTR: received on cooked monitor already * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported * to cfg80211_report_obss_beacon(). - * @IEEE80211_RX_REORDER_TIMER: this frame is released by the - * reorder buffer timeout timer, not the normal RX path * * These flags are used across handling multiple interfaces * for a single frame. @@ -211,10 +209,10 @@ enum ieee80211_packet_rx_flags { enum ieee80211_rx_flags { IEEE80211_RX_CMNTR = BIT(0), IEEE80211_RX_BEACON_REPORTED = BIT(1), - IEEE80211_RX_REORDER_TIMER = BIT(2), }; struct ieee80211_rx_data { + struct napi_struct *napi; struct sk_buff *skb; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -1347,8 +1345,6 @@ struct ieee80211_local { struct ieee80211_sub_if_data __rcu *p2p_sdata; - struct napi_struct *napi; - /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; struct cfg80211_chan_def monitor_chandef; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3c63468b4dfb..dba0a86dee18 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1132,18 +1132,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_register_hw); -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - struct ieee80211_local *local = hw_to_local(hw); - - netif_napi_add(napi_dev, napi, poll, weight); - local->napi = napi; -} -EXPORT_SYMBOL_GPL(ieee80211_napi_add); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dd6bb2a54d45..817bf22dad5a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2148,9 +2148,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); - if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) && - rx->local->napi) - napi_gro_receive(rx->local->napi, skb); + if (rx->napi) + napi_gro_receive(rx->napi, skb); else netif_receive_skb(skb); } @@ -3256,7 +3255,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) /* This is OK -- must be QoS data frame */ .security_idx = tid, .seqno_idx = tid, - .flags = IEEE80211_RX_REORDER_TIMER, + .napi = NULL, /* must be NULL to not have races */ }; struct tid_ampdu_rx *tid_agg_rx; @@ -3433,7 +3432,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, * be called with rcu_read_lock protection. */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) + struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -3449,6 +3449,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; + rx.napi = napi; if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) I802_DEBUG_INC(local->dot11ReceivedFragmentCount); @@ -3550,7 +3551,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; @@ -3649,7 +3651,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) ieee80211_tpt_led_trig_rx(local, ((struct ieee80211_hdr *)skb->data)->frame_control, skb->len); - __ieee80211_rx_handle_packet(hw, skb); + __ieee80211_rx_handle_packet(hw, skb, napi); rcu_read_unlock(); @@ -3657,7 +3659,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) drop: kfree_skb(skb); } -EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL(ieee80211_rx_napi); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -- cgit v1.2.3-70-g09d2 From 33c2f538d8080845e11af500993cc61ad30934e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 13:07:14 +0200 Subject: mac80211_hwsim: support wider TDLS bandwidth There's no reason not to support this, allow it to test those code paths. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 99e873dc8684..08022ded6307 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2399,6 +2399,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, TDLS_WIDER_BW); if (rctbl) ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); -- cgit v1.2.3-70-g09d2 From 80b2089b4a0b08ff34619a8e07fc74a63b4e2d24 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sat, 20 Jun 2015 03:28:15 +0900 Subject: rtlwifi: rtl8192cu: Remove rtl8723 code In the rtlwifi/rtl8192cu, rtl8723 code is dead code. So I remove it. Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/def.h | 9 --------- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 16 +--------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 12 ------------ 3 files changed, 1 insertion(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h index c940a87175ca..74a479ac323d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -32,24 +32,15 @@ /*------------------------------------------------------------------------- * Chip specific *-------------------------------------------------------------------------*/ -#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ -#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ #define NORMAL_CHIP BIT(4) #define CHIP_VENDOR_UMC BIT(5) #define CHIP_VENDOR_UMC_B_CUT BIT(6) -#define IS_8723_SERIES(version) \ - (((version) & CHIP_8723) ? true : false) - #define IS_92C_1T2R(version) \ (((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R)) #define IS_VENDOR_UMC(version) \ (((version) & CHIP_VENDOR_UMC) ? true : false) -#define IS_VENDOR_8723_A_CUT(version) \ - (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ - false : true) : false) - #define CHIP_BONDING_92C_1T2R 0x1 #define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 767358a553fb..7cf36619f250 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -2280,7 +2280,6 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; u8 u1tmp = 0; bool actuallyset = false; @@ -2357,20 +2356,7 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) if (ppsc->pwrdown_mode && e_rfpowerstate_toset == ERFOFF) { /* Enable register area 0x0-0xc. */ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); - if (IS_HARDWARE_TYPE_8723U(rtlhal)) { - /* - * We should configure HW PDn source for WiFi - * ONLY, and then our HW will be set in - * power-down mode if PDn source from all - * functions are configured. - */ - u1tmp = rtl_read_byte(rtlpriv, - REG_MULTI_FUNC_CTRL); - rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, - (u1tmp|WL_HWPDN_EN)); - } else { - rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); - } + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); } if (e_rfpowerstate_toset == ERFOFF) { if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 490a7cf7c702..1c55a002d4bd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -69,8 +69,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) chip_version = NORMAL_CHIP; chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0); chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); - /* RTL8723 with BT function. */ - chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0); if (IS_VENDOR_UMC(chip_version)) chip_version |= ((value32 & CHIP_VER_RTL_MASK) ? CHIP_VENDOR_UMC_B_CUT : 0); @@ -78,10 +76,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) == CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); - } else if (IS_8723_SERIES(chip_version)) { - value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); - chip_version |= ((value32 & RF_RL_ID) ? - CHIP_8723_DRV_REV : 0); } } rtlhal->version = (enum version_8192c)chip_version; @@ -114,12 +108,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: versionid = "NORMAL_UMC_CHIP_88C_B_CUT"; break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_A_CUT"; - break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_B_CUT"; - break; case VERSION_TEST_CHIP_92C: versionid = "TEST_CHIP_92C"; break; -- cgit v1.2.3-70-g09d2 From 4e6ee91bb728a268b37c74e2dd083481bf5ebb98 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:07 +0530 Subject: mwifiex: add tx data pause support This patch adds support to enable TX data pause feature for mwifiex. Whenever FW TX buffers reach threshold, FW would send TX pause event to driver. Driver in turn would block data traffic to that particular receiver address. Signed-off-by: Avinash Patil Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 9 +++++ drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/sta_event.c | 66 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 38 ++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 + 5 files changed, 118 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cd09051710e6..8ab0d81e6437 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -169,6 +169,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) #define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) #define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) @@ -509,6 +510,7 @@ enum P2P_MODES { #define EVENT_TDLS_GENERIC_EVENT 0x00000052 #define EVENT_RADAR_DETECTED 0x00000053 #define EVENT_CHANNEL_REPORT_RDY 0x00000054 +#define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -1131,6 +1133,13 @@ struct host_cmd_ds_tx_rate_query { u8 ht_info; } __packed; +struct mwifiex_tx_pause_tlv { + struct mwifiex_ie_types_header header; + u8 peermac[ETH_ALEN]; + u8 tx_pause; + u8 pkt_cnt; +} __packed; + enum Host_Sleep_Action { HS_CONFIGURE = 0x0001, HS_ACTIVATE = 0x0002, diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ae98b5b83b1f..2106a5c24692 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -281,6 +281,7 @@ struct mwifiex_ra_list_tbl { u8 amsdu_in_ampdu; u16 total_pkt_count; bool tdls_link; + bool tx_paused; }; struct mwifiex_tid_tbl { @@ -294,6 +295,7 @@ struct mwifiex_tid_tbl { struct mwifiex_wmm_desc { struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; u32 packets_out[MAX_NUM_TID]; + u32 pkts_paused[MAX_NUM_TID]; /* spin lock to protect ra_list */ spinlock_t ra_list_spinlock; struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; @@ -768,6 +770,7 @@ struct mwifiex_sta_node { u8 tdls_status; struct mwifiex_tdls_capab tdls_cap; struct mwifiex_station_stats stats; + u8 tx_pause; }; struct mwifiex_auto_tdls_peer { diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 848de2621958..0a80814ddbb0 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -182,6 +182,67 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } +static void +mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 tlv_type, tlv_len; + int tlv_buf_left, status; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return; + + tlv_buf_left = event_skb->len - sizeof(u32); + tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len); + if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > + tlv_buf_left) { + mwifiex_dbg(priv->adapter, ERROR, + "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", + tlv_len, tlv_buf_left); + break; + } + if (tlv_type == TLV_TYPE_TX_PAUSE) { + tp_tlv = (void *)tlv; + mwifiex_dbg(priv->adapter, ERROR, + "TxPause: %pM pause=%d, pkts=%d\n", + tp_tlv->peermac, tp_tlv->tx_pause, + tp_tlv->pkt_cnt); + status = mwifiex_get_tdls_link_status + (priv, tp_tlv->peermac); + if (status == TDLS_SETUP_COMPLETE) { + spin_lock_irqsave(&priv->sta_list_spinlock, + flags); + sta_ptr = mwifiex_get_sta_entry + (priv, tp_tlv->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, + flags); + if (sta_ptr && sta_ptr->tx_pause != + tp_tlv->tx_pause) { + sta_ptr->tx_pause = tp_tlv->tx_pause; + mwifiex_update_ralist_tx_pause + (priv, tp_tlv->peermac, + tp_tlv->tx_pause); + } + } + } + + tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + + tlv_len; + tlv = (void *)((u8 *)tlv + tlv_len + + sizeof(struct mwifiex_ie_types_header)); + } +} + /* * This function handles coex events generated by firmware */ @@ -573,6 +634,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index a8ea21c3340c..bc920a5a947c 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -160,6 +160,7 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->tdls_link = false; ra_list->ba_status = BA_SETUP_NONE; ra_list->amsdu_in_ampdu = false; + ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { if (mwifiex_get_tdls_link_status(priv, ra) == TDLS_SETUP_COMPLETE) { @@ -603,6 +604,43 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, return NULL; } +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_get_ralist_node(priv, i, mac); + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 48ece0b35591..90edb8fc337d 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -126,6 +126,8 @@ struct mwifiex_ra_list_tbl * mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- cgit v1.2.3-70-g09d2 From b5b0f272d618a470c34619b25f15ca4aa9d3b395 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:08 +0530 Subject: mwifiex: block data traffic to tx paused receive address Data traffic to tx paused receive address should be blocked. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index bc920a5a947c..8a4dd248ff01 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1025,7 +1025,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, list_for_each_entry(ptr, &tid_ptr->ra_list, list) { - if (!skb_queue_empty(&ptr->skb_head)) + if (!ptr->tx_paused && + !skb_queue_empty(&ptr->skb_head)) /* holds both locks */ goto found; } -- cgit v1.2.3-70-g09d2 From 9186a1f37d190f433c64558a4efeac7ed776b571 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:09 +0530 Subject: mwifiex: do not increase tx_pkts_queued if receive address tx paused If tx_pkts_queued is increased for tx paused receive address, tx process will be triggered for this packet. But since RA list was tx paused, there will be an infinite loop in mwifiex_wmm_process_tx waiting for the event(tx pause, tdls cs) to cancel tx pause. This will be an dead loop, since main_process was locked at this time, there will be no opportunity to process event. So do not increase tx_pkts_queued if receive address tx paused, this will be restored RA list is unpaused. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8a4dd248ff01..8e343b3f60e9 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -803,7 +803,10 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, atomic_set(&priv->wmm.highest_queued_prio, priv->tos_to_tid_inv[tid_down]); - atomic_inc(&priv->wmm.tx_pkts_queued); + if (ra_list->tx_paused) + priv->wmm.pkts_paused[tid_down]++; + else + atomic_inc(&priv->wmm.tx_pkts_queued); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } -- cgit v1.2.3-70-g09d2 From ba101ad50a5024978f3f5007b4a6c20b304cdcbe Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:10 +0530 Subject: mwifiex: add tdls channel switch status This patch add new tdls status used for tdls channel switch. Driver in turn would block cmd path and data path if tdls channel switching. Data path to non tdls peer should be blocked if tdls channel switch to off-channel. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/decl.h | 3 ++ drivers/net/wireless/mwifiex/main.c | 14 +++++++-- drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/util.c | 59 +++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 51e344789ba2..098e1f14dc9a 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -141,6 +141,9 @@ enum mwifiex_tdls_status { TDLS_SETUP_COMPLETE, TDLS_SETUP_FAILURE, TDLS_LINK_TEARDOWN, + TDLS_CHAN_SWITCHING, + TDLS_IN_BASE_CHAN, + TDLS_IN_OFF_CHAN, }; enum mwifiex_tdls_error_code { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3ba4e0e04223..2a2e5dbab8dd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -299,9 +299,15 @@ process_start: if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || + mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || + !mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (!is_command_pending(adapter))) break; } @@ -342,7 +348,9 @@ process_start: continue; } - if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (!adapter->cmd_sent && !adapter->curr_cmd && + mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { if (mwifiex_exec_next_cmd(adapter) == -1) { ret = -1; break; @@ -365,7 +373,9 @@ process_start: if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && - !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { + !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2106a5c24692..d27e6aa63446 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1461,6 +1461,9 @@ struct mwifiex_sta_node * mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac); struct mwifiex_sta_node * mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac); +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv); +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv); +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv); int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *extra_ies, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 790e61953abf..2504e422364a 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -531,6 +531,65 @@ mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac) return NULL; } +static struct mwifiex_sta_node * +mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) +{ + struct mwifiex_sta_node *node; + + list_for_each_entry(node, &priv->sta_list, list) { + if (node->tdls_status == status) + return node; + } + + return NULL; +} + +/* If tdls channel switching is on-going, tx data traffic should be + * blocked until the switching stage completed. + */ +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); + if (sta_ptr) + return true; + + return false; +} + +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); + if (sta_ptr) + return true; + + return false; +} + +/* If tdls channel switching is on-going or tdls operate on off-channel, + * cmd path should be blocked until tdls switched to base-channel. + */ +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) +{ + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return true; + + if (mwifiex_is_tdls_chan_switching(priv) || + mwifiex_is_tdls_off_chan(priv)) + return false; + + return true; +} + /* This function will add a sta_node entry to associated station list * table with the given mac address. * If entry exist already, existing entry is returned. -- cgit v1.2.3-70-g09d2 From f7669877e7ab1c5c7fddf268d57f016d97e48198 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:11 +0530 Subject: mwifiex: process tdls channel switch event This patch add support for tdls channel switch event process. We block TX queues for particular RA list depending upon channel switch state. If channel switch state is moving to base channel, we unblock RA lists for AP. If channel switch state is moving to off channel, we unblock TDLS peer RA lists. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 17 +++++++++- drivers/net/wireless/mwifiex/sta_event.c | 54 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 45 ++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 ++ 4 files changed, 117 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 8ab0d81e6437..0785e645341f 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -547,7 +547,14 @@ enum P2P_MODES { #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CONFIG 0x02 -#define TDLS_EVENT_LINK_TEAR_DOWN 3 + +#define TDLS_EVENT_LINK_TEAR_DOWN 3 +#define TDLS_EVENT_CHAN_SWITCH_RESULT 7 +#define TDLS_EVENT_START_CHAN_SWITCH 8 +#define TDLS_EVENT_CHAN_SWITCH_STOPPED 9 + +#define TDLS_BASE_CHANNEL 0 +#define TDLS_OFF_CHANNEL 1 #define MWIFIEX_FW_V15 15 @@ -1936,10 +1943,18 @@ struct host_cmd_ds_802_11_subsc_evt { __le16 events; } __packed; +struct chan_switch_result { + u8 cur_chan; + u8 status; + u8 reason; +} __packed; + struct mwifiex_tdls_generic_event { __le16 type; u8 peer_mac[ETH_ALEN]; union { + struct chan_switch_result switch_result; + u8 cs_stop_reason; __le16 reason_code; __le16 reserved; } u; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0a80814ddbb0..0529b9a602d8 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -153,6 +153,7 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, struct mwifiex_sta_node *sta_ptr; struct mwifiex_tdls_generic_event *tdls_evt = (void *)event_skb->data + sizeof(adapter->event_cause); + u8 *mac = tdls_evt->peer_mac; /* reserved 2 bytes are not mandatory in tdls event */ if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) - @@ -175,6 +176,59 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, le16_to_cpu(tdls_evt->u.reason_code), GFP_KERNEL); break; + case TDLS_EVENT_CHAN_SWITCH_RESULT: + mwifiex_dbg(adapter, EVENT, "tdls channel switch result :\n"); + mwifiex_dbg(adapter, EVENT, + "status=0x%x, reason=0x%x cur_chan=%d\n", + tdls_evt->u.switch_result.status, + tdls_evt->u.switch_result.reason, + tdls_evt->u.switch_result.cur_chan); + + /* tdls channel switch failed */ + if (tdls_evt->u.switch_result.status != 0) { + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + return ret; + } + + /* tdls channel switch success */ + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_BASE_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + false); + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + true); + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + + break; + case TDLS_EVENT_START_CHAN_SWITCH: + mwifiex_dbg(adapter, EVENT, "tdls start channel switch...\n"); + sta_ptr->tdls_status = TDLS_CHAN_SWITCHING; + break; + case TDLS_EVENT_CHAN_SWITCH_STOPPED: + mwifiex_dbg(adapter, EVENT, + "tdls chan switch stopped, reason=%d\n", + tdls_evt->u.cs_stop_reason); + break; default: break; } diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8e343b3f60e9..21712cdcd95a 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -641,6 +641,51 @@ void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } +/* This function update non-tdls peer ralist tx_pause while + * tdls channel swithing + */ +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list, + list) { + if (!memcmp(ra_list->ra, mac, ETH_ALEN)) + continue; + + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 90edb8fc337d..c12dd0e9f008 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -128,6 +128,8 @@ mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, u8 tx_pause); +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- cgit v1.2.3-70-g09d2 From 449b8bbf45e636a684c287f3008d13939aeac58b Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:12 +0530 Subject: mwifiex: add tdls config command This patch add support for a new tdls configuration command which is used for configuration of tdls channel switch parameters. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 45 +++++++++++++++++++++ drivers/net/wireless/mwifiex/main.h | 7 ++++ drivers/net/wireless/mwifiex/sta_cmd.c | 48 ++++++++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 + drivers/net/wireless/mwifiex/tdls.c | 64 ++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 0785e645341f..427e36357519 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -360,6 +360,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_MGMT_FRAME_REG 0x010c #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 +#define HostCmd_CMD_TDLS_CONFIG 0x0100 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -556,6 +557,19 @@ enum P2P_MODES { #define TDLS_BASE_CHANNEL 0 #define TDLS_OFF_CHANNEL 1 +#define ACT_TDLS_CS_ENABLE_CONFIG 0x00 +#define ACT_TDLS_CS_INIT 0x06 +#define ACT_TDLS_CS_STOP 0x07 +#define ACT_TDLS_CS_PARAMS 0x08 + +#define MWIFIEX_DEF_CS_UNIT_TIME 2 +#define MWIFIEX_DEF_CS_THR_OTHERLINK 10 +#define MWIFIEX_DEF_THR_DIRECTLINK 0 +#define MWIFIEX_DEF_CS_TIME 10 +#define MWIFIEX_DEF_CS_TIMEOUT 16 +#define MWIFIEX_DEF_CS_REG_CLASS 12 +#define MWIFIEX_DEF_CS_PERIODICITY 1 + #define MWIFIEX_FW_V15 15 #define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1) @@ -1265,6 +1279,36 @@ struct host_cmd_ds_tdls_oper { u8 peer_mac[ETH_ALEN]; } __packed; +struct mwifiex_tdls_config { + __le16 enable; +}; + +struct mwifiex_tdls_config_cs_params { + u8 unit_time; + u8 thr_otherlink; + u8 thr_directlink; +}; + +struct mwifiex_tdls_init_cs_params { + u8 peer_mac[ETH_ALEN]; + u8 primary_chan; + u8 second_chan_offset; + u8 band; + __le16 switch_time; + __le16 switch_timeout; + u8 reg_class; + u8 periodicity; +} __packed; + +struct mwifiex_tdls_stop_cs_params { + u8 peer_mac[ETH_ALEN]; +}; + +struct host_cmd_ds_tdls_config { + __le16 tdls_action; + u8 tdls_data[1]; +} __packed; + struct mwifiex_chan_desc { __le16 start_freq; u8 chan_width; @@ -2059,6 +2103,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_sta_list sta_list; struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_coalesce_cfg coalesce_cfg; + struct host_cmd_ds_tdls_config tdls_config; struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d27e6aa63446..da2275221c03 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1494,6 +1494,13 @@ void mwifiex_check_auto_tdls(unsigned long context); void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_config_tdls_enable(struct mwifiex_private *priv); +int mwifiex_config_tdls_disable(struct mwifiex_private *priv); +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv); +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac); +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band); + int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 037adcd1f484..82e6c6ec0b73 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1575,6 +1575,50 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_tdls_config(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tdls_config *tdls_config = &cmd->params.tdls_config; + struct mwifiex_tdls_init_cs_params *config; + struct mwifiex_tdls_config *init_config; + u16 len; + + cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG); + cmd->size = cpu_to_le16(S_DS_GEN); + tdls_config->tdls_action = cpu_to_le16(cmd_action); + le16_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); + + switch (cmd_action) { + case ACT_TDLS_CS_ENABLE_CONFIG: + init_config = data_buf; + len = sizeof(*init_config); + memcpy(tdls_config->tdls_data, init_config, len); + break; + case ACT_TDLS_CS_INIT: + config = data_buf; + len = sizeof(*config); + memcpy(tdls_config->tdls_data, config, len); + break; + case ACT_TDLS_CS_STOP: + len = sizeof(struct mwifiex_tdls_stop_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + case ACT_TDLS_CS_PARAMS: + len = sizeof(struct mwifiex_tdls_config_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + default: + mwifiex_dbg(priv->adapter, ERROR, + "Unknown TDLS configuration\n"); + return -ENOTSUPP; + } + + le16_add_cpu(&cmd->size, len); + return 0; +} + static int mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -1958,6 +2002,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_TDLS_CONFIG: + ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action, + data_buf); + break; case HostCmd_CMD_CHAN_REPORT_REQUEST: ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b645884b3b97..6a85c774587a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1197,6 +1197,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); break; + case HostCmd_CMD_TDLS_CONFIG: + break; default: mwifiex_dbg(adapter, ERROR, "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 2faa1bc42abe..03eabd705abe 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1416,3 +1416,67 @@ void mwifiex_clean_auto_tdls(struct mwifiex_private *priv) mwifiex_flush_auto_tdls_list(priv); } } + +static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable) +{ + struct mwifiex_tdls_config config; + + config.enable = cpu_to_le16(enable); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true); +} + +int mwifiex_config_tdls_enable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, true); +} + +int mwifiex_config_tdls_disable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, false); +} + +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv) +{ + struct mwifiex_tdls_config_cs_params config_tdls_cs_params; + + config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME; + config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK; + config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_PARAMS, 0, + &config_tdls_cs_params, true); +} + +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac) +{ + struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params; + + ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac); + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_STOP, 0, + &stop_tdls_cs_params, true); +} + +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band) +{ + struct mwifiex_tdls_init_cs_params start_tdls_cs_params; + + ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac); + start_tdls_cs_params.primary_chan = primary_chan; + start_tdls_cs_params.second_chan_offset = second_chan_offset; + start_tdls_cs_params.band = band; + + start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME); + start_tdls_cs_params.switch_timeout = + cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT); + start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS; + start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_INIT, 0, + &start_tdls_cs_params, true); +} -- cgit v1.2.3-70-g09d2 From 20834343a8e6a9a1e90d47810f6fe991f1e3362a Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:13 +0530 Subject: mwifiex: enable tdls channel switch ext_cap This patch enable tdls channel switch ext capability in tdls action frame, and also configure basic tdls channel switch parameters while tdls setup completed and tdls link is enabled.. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 03eabd705abe..f862ca63506c 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -355,6 +355,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, extcap->ieee_hdr.len = 8; memset(extcap->ext_capab, 0, 8); extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED; + extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH; if (priv->adapter->is_hw_11ac_capable) extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED; @@ -1071,6 +1072,11 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) for (i = 0; i < MAX_NUM_TID; i++) sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; } + if (sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) { + mwifiex_config_tdls_enable(priv); + mwifiex_config_tdls_cs_params(priv); + } memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); -- cgit v1.2.3-70-g09d2 From 55a2c0770634a08009229aaf23cda885d2e4359e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:14 +0530 Subject: mwifiex: enhance tdls link setup condition TDLS link status - channel switching, off channel or base channel itself indicates that TDLS link is setup. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 15 +++++++++++++++ drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/tdls.c | 8 ++++---- drivers/net/wireless/mwifiex/wmm.c | 7 +++++-- 4 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index da2275221c03..0e6ebc9001c3 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1333,6 +1333,21 @@ static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv) return 0; } +static inline u8 mwifiex_is_tdls_link_setup(u8 status) +{ + switch (status) { + case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: + return true; + default: + break; + } + + return false; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0529b9a602d8..f1045d41abee 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -273,7 +273,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tp_tlv->pkt_cnt); status = mwifiex_get_tdls_link_status (priv, tp_tlv->peermac); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_ptr = mwifiex_get_sta_entry diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index f862ca63506c..aa3d3c5ed07b 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -49,7 +49,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, tid = skb->priority; tid_down = mwifiex_wmm_downgrade_tid(priv, tid); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac); ra_list->tdls_link = true; tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; @@ -1147,7 +1147,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv, spin_lock_irqsave(&priv->sta_list_spinlock, flags); list_for_each_entry(sta_ptr, &priv->sta_list, list) { - if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) { ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); peer++; count++; @@ -1301,7 +1301,7 @@ void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, if ((link_status == TDLS_NOT_SETUP) && (peer->tdls_status == TDLS_SETUP_INPROGRESS)) peer->failure_count++; - else if (link_status == TDLS_SETUP_COMPLETE) + else if (mwifiex_is_tdls_link_setup(link_status)) peer->failure_count = 0; peer->tdls_status = link_status; @@ -1373,7 +1373,7 @@ void mwifiex_check_auto_tdls(unsigned long context) if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) || !tdls_peer->rssi) && - tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) { + mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) { tdls_peer->tdls_status = TDLS_LINK_TEARDOWN; mwifiex_dbg(priv->adapter, MSG, "teardown TDLS link,peer=%pM rssi=%d\n", diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 21712cdcd95a..6196daad5a61 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -162,8 +162,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->amsdu_in_ampdu = false; ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { - if (mwifiex_get_tdls_link_status(priv, ra) == - TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup + (mwifiex_get_tdls_link_status(priv, ra))) { ra_list->tdls_link = true; ra_list->is_11n_enabled = mwifiex_tdls_peer_11n_enabled(priv, ra); @@ -806,6 +806,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, !mwifiex_is_skb_mgmt_frame(skb)) { switch (tdls_status) { case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; -- cgit v1.2.3-70-g09d2 From b04975970676d797dec434755a14285420a4189f Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:15 +0530 Subject: mwifiex: add cfg80211 tdls channel switch handler This patch add cfg80211 tdls_chan_switch and tdls_cancel_chan_switch handler. With this handlers, mwifiex would support TDLS channel switch feature. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b15e4c7acbec..ecc8278a8cfe 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -19,6 +19,7 @@ #include "cfg80211.h" #include "main.h" +#include "11n.h" static char *reg_alpha2; module_param(reg_alpha2, charp, 0); @@ -3359,6 +3360,72 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, peer, action); } +static int +mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr, u8 oper_class, + struct cfg80211_chan_def *chandef) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 chan; + u8 second_chan_offset, band; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + return -ENOENT; + } + + if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) { + wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); + return -ENOENT; + } + + if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) { + wiphy_err(wiphy, "channel switch is running, abort request\n"); + return -EALREADY; + } + + chan = chandef->chan->hw_value; + second_chan_offset = mwifiex_get_sec_chan_offset(chan); + band = chandef->chan->band; + mwifiex_start_tdls_cs(priv, addr, chan, second_chan_offset, band); + + return 0; +} + +static void +mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + } else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_BASE_CHAN || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) { + wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n", + addr); + } else + mwifiex_stop_tdls_cs(priv, addr); +} + static int mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_parameters *params) @@ -3575,6 +3642,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_coalesce = mwifiex_cfg80211_set_coalesce, .tdls_mgmt = mwifiex_cfg80211_tdls_mgmt, .tdls_oper = mwifiex_cfg80211_tdls_oper, + .tdls_channel_switch = mwifiex_cfg80211_tdls_chan_switch, + .tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, .get_channel = mwifiex_cfg80211_get_channel, @@ -3709,6 +3778,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_FEATURE_INACTIVITY_TIMER | NL80211_FEATURE_NEED_OBSS_SCAN; + if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) + wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; + if (adapter->fw_api_ver == MWIFIEX_FW_V15) wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; -- cgit v1.2.3-70-g09d2 From 65d48e5971065ccb831a93232d60deb7caa9d7cb Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:16 +0530 Subject: mwifiex: update domain_info upon band change in start_ap It was observed that AP beacons would not reflect correct regulatory information upon starting AP in A band. This was because of missing AP config band update in set_channel of start_ap. Also we configure 11D settings info FW only for specific band. So we need to download domain info to FW even if domain remains unchanged but band is changed. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/uap_cmd.c | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ecc8278a8cfe..1d445cbbb31b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -442,7 +442,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power) */ -static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) { u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0e6ebc9001c3..d74ef2dd21bc 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1550,6 +1550,8 @@ void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index b74930054b8c..4d5a6e3b6361 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -808,7 +808,7 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_chan_def chandef) { - u8 config_bands = 0; + u8 config_bands = 0, old_bands = priv->adapter->config_bands; priv->bss_chandef = chandef; @@ -834,6 +834,11 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, } priv->adapter->config_bands = config_bands; + + if (old_bands != config_bands) { + mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy); + mwifiex_dnld_txpwr_table(priv); + } } int mwifiex_config_start_uap(struct mwifiex_private *priv, -- cgit v1.2.3-70-g09d2 From a1777327126e184518e17e3c571540be72c73dce Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:17 +0530 Subject: mwifiex: support for bypass tx queue This patch adds support for another TX queue in driver- bypass TX queue. This queue is used for sending data/mgmt packets while in disconnected state i.e. when port is yet not unblocked. TDLS setup packets would also be queued in this queue. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++ drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.c | 49 ++++++++++++++++++++++++++++-- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/wmm.c | 53 +++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 4 +++ 6 files changed, 111 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1d445cbbb31b..46f9dc2b1736 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2789,6 +2789,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); @@ -2796,6 +2797,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) mwifiex_stop_net_dev_queue(priv->netdev, adapter); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index df7fdc09d38c..e1b62bf0f7b4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) INIT_LIST_HEAD(&priv->sta_list); INIT_LIST_HEAD(&priv->auto_tdls_list); skb_queue_head_init(&priv->tdls_txq); + skb_queue_head_init(&priv->bypass_txq); spin_lock_init(&priv->tx_ba_stream_tbl_lock); spin_lock_init(&priv->rx_reorder_tbl_lock); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2a2e5dbab8dd..278dc94eaecb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -276,6 +276,7 @@ process_start: !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || !skb_queue_empty(&adapter->tx_data_q) || + !mwifiex_bypass_txlist_empty(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); @@ -303,6 +304,7 @@ process_start: (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || !mwifiex_is_send_cmd_allowed @@ -371,6 +373,22 @@ process_start: } } + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !mwifiex_bypass_txlist_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { + mwifiex_process_bypass_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && @@ -389,6 +407,7 @@ process_start: if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), @@ -659,6 +678,26 @@ mwifiex_close(struct net_device *dev) return 0; } +static bool +mwifiex_bypass_tx_queue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + + if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || + mwifiex_is_skb_mgmt_frame(skb) || + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && + ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && + (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { + mwifiex_dbg(priv->adapter, DATA, + "bypass txqueue; eth type %#x, mgmt %d\n", + ntohs(eth_hdr->h_proto), + mwifiex_is_skb_mgmt_frame(skb)); + return true; + } + + return false; +} /* * Add buffer into wmm tx queue and queue work to transmit it. */ @@ -676,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) } } - atomic_inc(&priv->adapter->tx_pending); - mwifiex_wmm_add_buf_txqueue(priv, skb); + if (mwifiex_bypass_tx_queue(priv, skb)) { + atomic_inc(&priv->adapter->tx_pending); + atomic_inc(&priv->adapter->bypass_tx_pending); + mwifiex_wmm_add_buf_bypass_txqueue(priv, skb); + } else { + atomic_inc(&priv->adapter->tx_pending); + mwifiex_wmm_add_buf_txqueue(priv, skb); + } mwifiex_queue_main_work(priv->adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d74ef2dd21bc..c59430e906ae 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -664,6 +664,7 @@ struct mwifiex_private { struct cfg80211_beacon_data beacon_after; struct mwifiex_11h_intf_state state_11h; struct mwifiex_ds_mem_rw mem_rw; + struct sk_buff_head bypass_txq; }; @@ -834,6 +835,7 @@ struct mwifiex_adapter { wait_queue_head_t init_wait_q; void *card; struct mwifiex_if_ops if_ops; + atomic_t bypass_tx_pending; atomic_t rx_pending; atomic_t tx_pending; atomic_t cmd_pending; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 6196daad5a61..7995f92bc2d4 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -449,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) } } +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter) +{ + return atomic_read(&adapter->bypass_tx_pending) ? false : true; +} + /* * This function checks if WMM Tx queue is empty. */ @@ -581,6 +586,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + atomic_set(&priv->adapter->bypass_tx_pending, 0); + idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); idr_destroy(&priv->ack_status_frames); } @@ -752,6 +761,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv, return false; } +/* + * This function adds a packet to bypass TX queue. + * This is special TX queue for packets which can be sent even when port_open + * is false. + */ +void +mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + skb_queue_tail(&priv->bypass_txq, skb); +} + /* * This function adds a packet to WMM queue. * @@ -1429,6 +1450,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) return 0; } +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter) +{ + struct mwifiex_tx_param tx_param; + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + struct mwifiex_private *priv; + int i; + + if (adapter->data_sent || adapter->tx_lock_flag) + return; + + for (i = 0; i < adapter->priv_num; ++i) { + priv = adapter->priv[i]; + + if (skb_queue_empty(&priv->bypass_txq)) + continue; + + skb = skb_dequeue(&priv->bypass_txq); + tx_info = MWIFIEX_SKB_TXCB(skb); + + /* no aggregation for bypass packets */ + tx_param.next_pkt_len = 0; + + if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { + skb_queue_head(&priv->bypass_txq, skb); + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + } else { + atomic_dec(&adapter->bypass_tx_pending); + } + } +} + /* * This function transmits the highest priority packet awaiting in the * WMM Queues. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index c12dd0e9f008..38f09762bd2f 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, struct sk_buff *skb); +void mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra); void mwifiex_rotate_priolists(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra, int tid); int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter); void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter); int mwifiex_is_ralist_valid(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list, int tid); -- cgit v1.2.3-70-g09d2 From 5c8946330abfa4c0476b94070d8833cfbbca5b28 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:18 +0530 Subject: mwifiex: enable traffic only when port is open This patch adds support to enable data traffic only when port is open. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/join.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 4 +++- drivers/net/wireless/mwifiex/uap_event.c | 3 +++ drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 7 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e1b62bf0f7b4..8fa363add970 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -77,7 +77,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->media_connected = false; eth_broadcast_addr(priv->curr_addr); - + priv->port_open = false; priv->pkt_tx_ctrl = 0; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->data_rate = 0; /* Initially indicate the rate as auto */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 56b024a6aaa5..3cda1f956f0b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -783,6 +783,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; + else + priv->port_open = true; done: /* Need to indicate IOCTL complete */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c59430e906ae..6f98d7ea9338 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -519,6 +519,7 @@ struct mwifiex_private { u8 frame_type; u8 curr_addr[ETH_ALEN]; u8 media_connected; + u8 port_open; u32 num_tx_timeout; /* track consecutive timeout */ u8 tx_timeout_cnt; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 6a85c774587a..18f269eaed60 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -599,6 +599,7 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } @@ -629,6 +630,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f1045d41abee..72be16eca758 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -54,6 +54,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->media_connected = false; priv->scan_block = false; + priv->port_open = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { @@ -474,7 +475,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PS_AWAKE: mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); - if (!adapter->pps_uapsd_mode && + if (!adapter->pps_uapsd_mode && priv->port_open && priv->media_connected && adapter->sleep_period.period) { adapter->pps_uapsd_mode = true; mwifiex_dbg(adapter, EVENT, @@ -553,6 +554,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PORT_RELEASE: mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); + priv->port_open = true; break; case EVENT_EXT_SCAN_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 7bc1f850e3b7..a412c3d4c365 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -176,6 +176,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_IDLE: priv->media_connected = false; + priv->port_open = false; if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); mwifiex_stop_net_dev_queue(priv->netdev, adapter); @@ -185,6 +186,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_ACTIVE: priv->media_connected = true; + priv->port_open = true; if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); @@ -192,6 +194,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) case EVENT_UAP_BSS_START: mwifiex_dbg(adapter, EVENT, "AP EVENT: event id: %#x\n", eventcause); + priv->port_open = false; memcpy(priv->netdev->dev_addr, adapter->event_body + 2, ETH_ALEN); if (priv->hist_data) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 7995f92bc2d4..173d3663c2e0 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -465,6 +465,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; ++i) { priv = adapter->priv[i]; + if (priv && !priv->port_open) + continue; if (priv && atomic_read(&priv->wmm.tx_pkts_queued)) return false; } @@ -1080,7 +1082,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv; - if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0) + if (!priv_tmp->port_open || + (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)) continue; /* iterate over the WMM queues of the BSS */ -- cgit v1.2.3-70-g09d2 From ddd7ceb3f6dd9071fd0e2058252d1fc4645313db Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:19 +0530 Subject: mwifiex: extend tx_data pause to AP interface as well This patch adds support to extend TX Data pause for AP intefaces. Also for station role, support for pausing/unpausing all traffic when mac address parameter is BSSID is added. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/sta_event.c | 121 ++++++++++++++++++++++--------- drivers/net/wireless/mwifiex/uap_event.c | 4 + 3 files changed, 93 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6f98d7ea9338..6e82058c0eab 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1554,6 +1554,8 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 72be16eca758..a2777d16c98f 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -237,58 +237,110 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } -static void -mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, - struct sk_buff *event_skb) +static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) { - struct mwifiex_ie_types_header *tlv; - struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_tx_pause_tlv *tp; struct mwifiex_sta_node *sta_ptr; unsigned long flags; - u16 tlv_type, tlv_len; - int tlv_buf_left, status; - if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) - return; + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "uap tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->netdev->dev_addr)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else if (is_multicast_ether_addr(tp->peermac)) { + mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); + } else { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, tp->peermac, + tp->tx_pause); + } + } +} + +static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) +{ + struct mwifiex_tx_pause_tlv *tp; + struct mwifiex_sta_node *sta_ptr; + int status; + unsigned long flags; + + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "sta tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->cfg_bssid)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else { + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + status = mwifiex_get_tdls_link_status(priv, tp->peermac); + if (mwifiex_is_tdls_link_setup(status)) { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, + tp->peermac, + tp->tx_pause); + } + } + } +} + +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + u16 tlv_type, tlv_len; + int tlv_buf_left; - if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + if (!priv->media_connected) { + mwifiex_dbg(priv->adapter, ERROR, + "tx_pause event while disconnected; bss_role=%d\n", + priv->bss_role); return; + } tlv_buf_left = event_skb->len - sizeof(u32); tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { tlv_type = le16_to_cpu(tlv->type); tlv_len = le16_to_cpu(tlv->len); if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > - tlv_buf_left) { + tlv_buf_left) { mwifiex_dbg(priv->adapter, ERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, tlv_buf_left); break; } if (tlv_type == TLV_TYPE_TX_PAUSE) { - tp_tlv = (void *)tlv; - mwifiex_dbg(priv->adapter, ERROR, - "TxPause: %pM pause=%d, pkts=%d\n", - tp_tlv->peermac, tp_tlv->tx_pause, - tp_tlv->pkt_cnt); - status = mwifiex_get_tdls_link_status - (priv, tp_tlv->peermac); - if (mwifiex_is_tdls_link_setup(status)) { - spin_lock_irqsave(&priv->sta_list_spinlock, - flags); - sta_ptr = mwifiex_get_sta_entry - (priv, tp_tlv->peermac); - spin_unlock_irqrestore(&priv->sta_list_spinlock, - flags); - if (sta_ptr && sta_ptr->tx_pause != - tp_tlv->tx_pause) { - sta_ptr->tx_pause = tp_tlv->tx_pause; - mwifiex_update_ralist_tx_pause - (priv, tp_tlv->peermac, - tp_tlv->tx_pause); - } - } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + mwifiex_process_sta_tx_pause(priv, tlv); + else + mwifiex_process_uap_tx_pause(priv, tlv); } tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + @@ -296,6 +348,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tlv = (void *)((u8 *)tlv + tlv_len + sizeof(struct mwifiex_ie_types_header)); } + } /* @@ -691,8 +744,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_TX_DATA_PAUSE: - mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; case EVENT_TX_STATUS_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a412c3d4c365..a9d34c619181 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -300,6 +300,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_bt_coex_wlan_param_update_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); + break; default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- cgit v1.2.3-70-g09d2 From d5b036c403f811c6d1856b8e6891a6438cf56f61 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:20 +0530 Subject: mwifiex: support to set multichannel policy to FW This patch adds support for setting multichannel policy as module parameter to FW. Value of 1 indicates Multichannel support is enabled and value of 0 disables it. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 ++++++++ drivers/net/wireless/mwifiex/sta_cmd.c | 31 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 1 + 3 files changed, 40 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 427e36357519..976b58587c27 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -201,6 +201,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_DRCS_ENABLED(FwCapInfo) (FwCapInfo & BIT(15)) #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ @@ -361,6 +362,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 #define HostCmd_CMD_TDLS_CONFIG 0x0100 +#define HostCmd_CMD_MC_POLICY 0x0121 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -2039,6 +2041,11 @@ struct host_cmd_ds_coalesce_cfg { struct coalesce_receive_filt_rule rule[0]; } __packed; +struct host_cmd_ds_multi_chan_policy { + __le16 action; + __le16 policy; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2107,6 +2114,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; + struct host_cmd_ds_multi_chan_policy mc_policy; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 82e6c6ec0b73..f250b61a9ff7 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@ #include "11n.h" #include "11ac.h" +static bool drcs; +module_param(drcs, bool, 0644); +MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0"); + static bool disable_auto_ds; module_param(disable_auto_ds, bool, 0); MODULE_PARM_DESC(disable_auto_ds, @@ -1511,6 +1515,22 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_set_mc_policy(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_multi_chan_policy *mc_pol = &cmd->params.mc_policy; + const u16 *drcs_info = data_buf; + + mc_pol->action = cpu_to_le16(cmd_action); + mc_pol->policy = cpu_to_le16(*drcs_info); + cmd->command = cpu_to_le16(HostCmd_CMD_MC_POLICY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_multi_chan_policy) + + S_DS_GEN); + return 0; +} + static int mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -2014,6 +2034,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_MC_POLICY: + ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action, + data_buf); + break; default: mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -2130,6 +2154,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; } + + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, &drcs, + true); + if (ret) + return -1; } /* get tx rate */ diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 18f269eaed60..89e8dafb4738 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1193,6 +1193,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_TDLS_OPER: ret = mwifiex_ret_tdls_oper(priv, resp); + case HostCmd_CMD_MC_POLICY: break; case HostCmd_CMD_CHAN_REPORT_REQUEST: break; -- cgit v1.2.3-70-g09d2 From de9e9932b76d5458edabd2692d8ad6504501edf1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:21 +0530 Subject: mwifiex: advertise multichannel support to cfg80211 This patch adds support to advetise mwifiex multichannel support to cfg80211. If module parameter drcs is enabled and FW supports multichannel operation we advertise this support to cfg80211. As of now 2 simultaneous channels are supported. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 14 +++++++++++++- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmd.c | 13 +++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 46f9dc2b1736..bc863e951140 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -43,6 +43,15 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { .beacon_int_infra_match = true, }; +static const struct +ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, +}; + /* * This function maps the nl802.11 channel type into driver channel type. * @@ -3745,7 +3754,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) else wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; + if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + else + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; /* Initialize cipher suits */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6e82058c0eab..f3264f2231d3 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -985,6 +985,7 @@ struct mwifiex_adapter { u8 coex_win_size; u8 coex_tx_win_size; u8 coex_rx_win_size; + bool drcs_enabled; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f250b61a9ff7..36cb6bdbe49b 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -2155,12 +2155,17 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) return -1; } - if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, - HostCmd_ACT_GEN_SET, 0, &drcs, - true); + if (drcs) { + adapter->drcs_enabled = true; + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, + &adapter->drcs_enabled, + true); if (ret) return -1; + } } /* get tx rate */ -- cgit v1.2.3-70-g09d2 From cc7359b5c82f67a1a19a0cf66f84f465403edb5d Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:22 +0530 Subject: mwifiex: separate interface combination for multichannel and DFS Multichannel and DFS cannot be supported at same time. So when multichannel operation is enabled by module parameter, we enable number of channel as 2 while registering wiphy. For all other cases we advertise DFS support to cfg80211. Patch also adds support for radar detect widths parameter. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index bc863e951140..93e40d0e9086 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -35,16 +35,33 @@ static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { }, }; -static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 1, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), .max_interfaces = MWIFIEX_MAX_BSS_NUM, .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +}; + +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta_vht = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), }; static const struct -ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { +ieee80211_iface_combination mwifiex_iface_comb_ap_sta_drcs = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 2, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), @@ -3755,7 +3772,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; + else if (adapter->is_hw_11ac_capable) + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_vht; else wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; -- cgit v1.2.3-70-g09d2 From 8d6b538a5eac1fec259d22ffa5b47ac585582432 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:23 +0530 Subject: mwifiex: handle multichannel event This patch adds support to handle multichannel event from FW. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 ++++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/uap_event.c | 6 ++++++ 4 files changed, 46 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 976b58587c27..98269bfd2b31 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -172,6 +172,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) #define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) #define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) @@ -516,6 +517,7 @@ enum P2P_MODES { #define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f +#define EVENT_MULTI_CHAN_INFO 0x0000006a #define EVENT_TX_STATUS_REPORT 0x00000074 #define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 @@ -1970,6 +1972,12 @@ struct mwifiex_radar_det_event { __le32 passed; } __packed; +struct mwifiex_ie_types_multi_chan_info { + struct mwifiex_ie_types_header header; + __le16 status; + u8 tlv_buffer[0]; +} __packed; + struct meas_rpt_map { u8 rssi:3; u8 unmeasured:1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f3264f2231d3..face7478937f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1557,6 +1557,8 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event); +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index a2777d16c98f..3d18c585e543 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -309,6 +309,31 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, } } +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_multi_chan_info *chan_info; + u16 status; + + chan_info = (void *)event_skb->data + sizeof(u32); + + if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) { + mwifiex_dbg(priv->adapter, ERROR, + "unknown TLV in chan_info event\n"); + return; + } + + status = le16_to_cpu(chan_info->status); + + if (status) { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation started\n"); + } else { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation over\n"); + } +} + void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event_skb) { @@ -748,6 +773,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a9d34c619181..492a8b3c636e 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -304,6 +304,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- cgit v1.2.3-70-g09d2 From 9030d52cfb340f57d86e1b5d995a463eaddb977b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:53:05 +0800 Subject: wireless: cw1200: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo To: Solomon Peachy To: Kalle Valo To: linux-wireless@vger.kernel.org To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/cw1200_spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 7603546d2de3..29185aeccba8 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -467,7 +467,6 @@ static struct spi_driver spi_driver = { .remove = cw1200_spi_disconnect, .driver = { .name = "cw1200_wlan_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &cw1200_pm_ops, -- cgit v1.2.3-70-g09d2 From 722d26680af10bd128b5228ba23e5d11ef2256c4 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 14:45:45 -0400 Subject: mwifiex: avoid freeing improper pointer in mwifiex_set_wowlan_mef_entry mwifiex_set_wowlan_mef_entry attempts to free a passed-in pointer in case of an error. The only caller (mwifiex_set_mef_filter) passes that pointer as an offset into allocated memory, so any attempt to free that will not be the actual allocated pointer. Address this by changing mwifiex_set_wowlan_mef_entry to not do any free, and to cause mwifiex_set_mef_filter to do the appropriate free if the call to mwifiex_set_wowlan_mef_entry fails. Coverity CID #1295879 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 93e40d0e9086..69ee6dbafd61 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2985,7 +2985,6 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, MWIFIEX_MEF_MAX_BYTESEQ)) { mwifiex_dbg(priv->adapter, ERROR, "Pattern not supported\n"); - kfree(mef_entry); return -EOPNOTSUPP; } @@ -3067,9 +3066,12 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); - if (wowlan->n_patterns || wowlan->magic_pkt) + if (wowlan->n_patterns || wowlan->magic_pkt) { ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, &mef_entry[1], wowlan); + if (ret) + goto err; + } if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -3079,6 +3081,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); + +err: kfree(mef_entry); return ret; } -- cgit v1.2.3-70-g09d2 From 8b2c621c9f6f6240edaf4359c3148068fff8b1c7 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 15:04:03 -0400 Subject: mwifiex: do not short circuit exit from mwifiex_set_mgmt_ies Without this change, the code simply exits after calling mwifiex_uap_set_head_tail_ies, leving the call to mwifiex_set_mgmt_beacon_data_ies as dead code. Coverity CID #1271292 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 0ba894509413..23e368c77c08 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -409,6 +409,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, int ret; ret = mwifiex_uap_parse_tail_ies(priv, info); + + if (ret) return ret; return mwifiex_set_mgmt_beacon_data_ies(priv, info); -- cgit v1.2.3-70-g09d2 From b5c103f20f0fdd736c51c996b07a42594d683b1c Mon Sep 17 00:00:00 2001 From: John Linville Date: Fri, 26 Jun 2015 15:29:36 -0400 Subject: mwifiex: fix leak of gen_ie storage on exit from mwifiex_del_mgmt_ies Storage pointed to by gen_ie is allocated with kmalloc, but was never freed. Coverity CID #1271251 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 23e368c77c08..abf52d25b981 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -479,6 +479,7 @@ int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) ar_ie, &priv->assocresp_idx); done: + kfree(gen_ie); kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); -- cgit v1.2.3-70-g09d2 From 11bdc44093555829eb4a5d9318eece469e2873e8 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Sun, 28 Jun 2015 20:07:38 -0500 Subject: mwifiex: usb: Fix double add error when submitting rx urb There is an error that can occur where the driver adds the same URB to USB submission list twice. This happens since mwifiex_usb_submit_rem_rx can submit packets at same time as an rx urb complete callback. This causes list corruption and is fixed by not setting the skb to NULL when submitting an rx packet. [ 84.461242] WARNING: CPU: 1 PID: 748 at lib/list_debug.c:36 __list_add+0xcb/0xd0() [ 84.461245] list_add double add: new=ffff8800c92b0c50, prev=ffff8800c92b0c50, next=ffff8800ced6c430. [ 84.461247] Modules linked in: rfcomm fuse cmac nf_conntrack_netbios_ns nf_conntrack_broadcast ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack bnep iptable_mangle iptable_security iptable_raw btusb btintel bluetooth mwifiex_usb mwifiex x86_pkg_temp_thermal cfg80211 coretemp r8712u(C) kvm_intel kvm hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger hid_sensor_iio_common industrialio_triggered_buffer kfifo_buf rfkill iTCO_wdt industrialio iTCO_vendor_support [ 84.461316] crc32_pclmul crc32c_intel ghash_clmulni_intel microcode snd_hda_codec_realtek vfat snd_hda_codec_generic fat snd_hda_codec_hdmi snd_hda_intel snd_hda_controller uvcvideo snd_hda_codec videobuf2_vmalloc videobuf2_memops snd_hwdep videobuf2_core snd_hda_core joydev v4l2_common videodev hid_sensor_hub snd_seq hid_multitouch media snd_seq_device snd_pcm snd_timer mei_me snd i2c_i801 lpc_ich mei soundcore tpm_infineon tpm_tis tpm i2c_hid i2c_designware_platform i2c_designware_core nfsd auth_rpcgss nfs_acl lockd grace sunrpc sch_fq_codel i915 i2c_algo_bit drm_kms_helper drm xhci_pci xhci_hcd ehci_pci sd_mod ehci_hcd video [ 84.461383] CPU: 1 PID: 748 Comm: kworker/u9:0 Tainted: G C 4.1.0-rc5+ #163 [ 84.461386] Hardware name: Microsoft Corporation Surface Pro 2/Surface Pro 2, BIOS 2.05.0250 04/10/2015 [ 84.461396] Workqueue: MWIFIEX_RX_WORK_QUEUE mwifiex_rx_work_queue [mwifiex] [ 84.461399] ffffffff81a8150e ffff8801174cf8e8 ffffffff817df830 0000000000000000 [ 84.461405] ffff8801174cf938 ffff8801174cf928 ffffffff810a54ba ffff8800c86bd750 [ 84.461410] ffff8800c92b0c50 ffff8800c92b0c50 ffff8800ced6c430 ffff88010c057178 [ 84.461416] Call Trace: [ 84.461421] [] dump_stack+0x4f/0x7b [ 84.461428] [] warn_slowpath_common+0x8a/0xc0 [ 84.461432] [] warn_slowpath_fmt+0x46/0x50 [ 84.461436] [] __list_add+0xcb/0xd0 [ 84.461442] [] ? usb_hcd_link_urb_to_ep+0x2a/0xa0 [ 84.461446] [] usb_hcd_link_urb_to_ep+0x80/0xa0 [ 84.461459] [] prepare_transfer+0xaa/0x130 [xhci_hcd] [ 84.461470] [] xhci_queue_bulk_tx+0xb7/0x7a0 [xhci_hcd] [ 84.461480] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461489] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461498] [] xhci_urb_enqueue+0x5c5/0x660 [xhci_hcd] [ 84.461503] [] usb_hcd_submit_urb+0x93/0xa70 [ 84.461507] [] ? __alloc_skb+0x78/0x1f0 [ 84.461511] [] ? __kmalloc_reserve.isra.26+0x31/0x90 [ 84.461515] [] ? __alloc_skb+0x4c/0x1f0 [ 84.461519] [] ? __alloc_skb+0x8c/0x1f0 [ 84.461523] [] ? skb_dequeue+0x5d/0x80 [ 84.461527] [] usb_submit_urb+0x42e/0x5f0 [ 84.461531] [] ? __alloc_rx_skb+0x39/0x100 [ 84.461536] [] mwifiex_usb_submit_rx_urb+0xb2/0x170 [mwifiex_usb] [ 84.461542] [] mwifiex_usb_submit_rem_rx_urbs+0x45/0x50 [mwifiex_usb] [ 84.461550] [] mwifiex_rx_work_queue+0x10e/0x140 [mwifiex] [ 84.461556] [] process_one_work+0x229/0x890 [ 84.461559] [] ? process_one_work+0x18c/0x890 [ 84.461565] [] worker_thread+0x53/0x470 [ 84.461569] [] ? process_one_work+0x890/0x890 [ 84.461572] [] kthread+0xf2/0x110 [ 84.461577] [] ? trace_hardirqs_on+0xd/0x10 [ 84.461581] [] ? kthread_create_on_node+0x230/0x230 [ 84.461586] [] ret_from_fork+0x42/0x70 [ 84.461590] [] ? kthread_create_on_node+0x230/0x230 [ 84.461593] ---[ end trace 65103af5e6fb3444 ]--- Signed-off-by: Reyad Attiyat Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index aada93425f80..fbad99c50307 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -244,9 +244,11 @@ setup_for_next: if (card->rx_cmd_ep == context->ep) { mwifiex_usb_submit_rx_urb(context, size); } else { - context->skb = NULL; - if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) + if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){ mwifiex_usb_submit_rx_urb(context, size); + }else{ + context->skb = NULL; + } } return; -- cgit v1.2.3-70-g09d2 From 33b8261e0e1c6d95901d62808d65141d4df525bd Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:17:55 -0400 Subject: rtlwifi: fix typo in comments This fixes a typo in two comments: "paht" -> "path". Signed-off-by: Nik Nyby Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 1961b8e28dc1..bb06fe836fe7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3515,14 +3515,14 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { if (rtlhal->current_bandtype == BAND_ON_2_4G) { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), 0); /* RF0x0b[16:14] =3b'111 */ rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, 0x1c000, 0x07); } else { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), (BIT(16) | BIT(8)) >> 8); -- cgit v1.2.3-70-g09d2 From 277bf09e8be9fa35d6bc0175c2c5a1e6bdb0626e Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:45:47 -0400 Subject: b43: Fix typo in function name This fixes a typo in the "b43_lo_g_maintenance_work" function name. Signed-off-by: Nik Nyby Acked-by: Larry Finger Acked-by: Michael Buesch Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/lo.c | 4 ++-- drivers/net/wireless/b43/lo.h | 2 +- drivers/net/wireless/b43/phy_g.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 916123a3d74e..a335f94c72ff 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -929,8 +929,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, b43_lo_write(dev, &cal->ctl); } -/* Periodic LO maintanance work */ -void b43_lo_g_maintanance_work(struct b43_wldev *dev) +/* Periodic LO maintenance work */ +void b43_lo_g_maintenance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 3b27e20eff80..7b4df3883bc2 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -80,7 +80,7 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_maintenance_work(struct b43_wldev *dev); void b43_lo_g_cleanup(struct b43_wldev *dev); void b43_lo_g_init(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 727ce6edb4b3..462310e6e88f 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3004,7 +3004,7 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) phy->rev == 1) { //TODO: implement rev1 workaround } - b43_lo_g_maintanance_work(dev); + b43_lo_g_maintenance_work(dev); b43_mac_enable(dev); } -- cgit v1.2.3-70-g09d2 From cf7d5a80201066daac467d57a47b0826c2e88354 Mon Sep 17 00:00:00 2001 From: Raphaël Poggi Date: Thu, 2 Jul 2015 10:34:49 +0200 Subject: wlcore: sdio: return correct error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When wlcore_probe_of failed, return the correct error code instead of ENOMEM Signed-off-by: Raphaël Poggi Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index ea7e07abca4e..c172da56b550 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -293,7 +293,8 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - if (wlcore_probe_of(&func->dev, &irq, &pdev_data)) + ret = wlcore_probe_of(&func->dev, &irq, &pdev_data); + if (ret) goto out_free_glue; /* if sdio can keep power while host is suspended, enable wow */ -- cgit v1.2.3-70-g09d2 From e60ac9c7a4c8776b2503892dfd01f1b4d651245d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jul 2015 13:40:29 +0200 Subject: ath9k: make DMA stop related messages debug-only A long time ago, ath9k had issues during reset where the DMA engine would stay active and could potentially corrupt memory. To debug those issues, the driver would print warnings whenever they occur. Nowadays, these issues are gone and the primary cause of these messages is if the MAC is stuck during reset or busy processing a long transmission. This is fairly harmless, yet these messages continue to worry users. To reduce the number of bogus bug reports, turn these messages into debug messages and count their occurence in the "reset" debugfs file. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 2 ++ drivers/net/wireless/ath/ath9k/debug.h | 2 ++ drivers/net/wireless/ath/ath9k/recv.c | 7 +++---- drivers/net/wireless/ath/ath9k/xmit.c | 7 +++++-- 4 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dbf8f4959642..da32c8faad94 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -765,6 +765,8 @@ static int read_file_reset(struct seq_file *file, void *data) [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", [RESET_TYPE_MCI] = "MCI Reset", [RESET_TYPE_CALIBRATION] = "Calibration error", + [RESET_TX_DMA_ERROR] = "Tx DMA stop error", + [RESET_RX_DMA_ERROR] = "Rx DMA stop error", }; int i; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a8e9319958e6..cd68c5f0e751 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -50,6 +50,8 @@ enum ath_reset_type { RESET_TYPE_BEACON_STUCK, RESET_TYPE_MCI, RESET_TYPE_CALIBRATION, + RESET_TX_DMA_ERROR, + RESET_RX_DMA_ERROR, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6c75fb1ab77d..d3189daf9996 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc) if (!(ah->ah_flags & AH_UNPLUGGED) && unlikely(!stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "Could not stop RX, we could be " - "confusing the DMA engine when we start RX up\n"); - ATH_DBG_WARN_ON_ONCE(!stopped); + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + "Failed to stop Rx DMA\n"); + RESET_STAT_INC(sc, RESET_RX_DMA_ERROR); } return stopped && !reset; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3ad79bb4f2c2..2c627f1233da 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc *sc) npend |= BIT(i); } - if (npend) - ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend); + if (npend) { + RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); + ath_dbg(common, RESET, + "Failed to stop TX DMA, queues=0x%03x!\n", npend); + } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) -- cgit v1.2.3-70-g09d2 From ae86c587b5b53da4f7859f236f6c22ff9941cff9 Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 2 Jul 2015 06:07:02 -0700 Subject: mwifiex: fix for p2p broken link This patch fixes following issues in p2p code paths. 1) bss role, bss type and connection type was not set correctly for p2p GO and p2p client at couple of places. 2) Driver appends a proprietary header to management frames which will be parsed by our firmware. Later while informing TX status to cfg80211, modified frame buffer was passed to cfg80211_mgmt_tx_status() instead of original one. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 5 ++++- drivers/net/wireless/mwifiex/sta_cmd.c | 6 ++++-- drivers/net/wireless/mwifiex/txrx.c | 22 +++++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 69ee6dbafd61..d4b327752a5e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -831,10 +831,13 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_P2P_GO: priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; + case NL80211_IFTYPE_P2P_GO: + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + priv->bss_type = MWIFIEX_BSS_TYPE_P2P; + break; case NL80211_IFTYPE_AP: priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 36cb6bdbe49b..a49a80dd773e 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1997,10 +1997,12 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, if (priv->bss_mode == NL80211_IFTYPE_ADHOC) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC; - else if (priv->bss_mode == NL80211_IFTYPE_STATION) + else if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA; - else if (priv->bss_mode == NL80211_IFTYPE_AP) + else if (priv->bss_mode == NL80211_IFTYPE_AP || + priv->bss_mode == NL80211_IFTYPE_P2P_GO) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP; cmd_ptr->size = cpu_to_le16(sizeof(struct host_cmd_ds_set_bss_mode) + S_DS_GEN); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 5ed9b794053e..8b1e5b5d47fe 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -370,8 +370,28 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, /* consumes ack_skb */ skb_complete_wifi_ack(ack_skb, !tx_status->status); } else { + /* Remove broadcast address which was added by driver */ + memmove(ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), + ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN, ack_skb->len - + (sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN)); + ack_skb->len = ack_skb->len - ETH_ALEN; + /* Remove driver's proprietary header including 2 bytes + * of packet length and pass actual management frame buffer + * to cfg80211. + */ cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, - ack_skb->data, ack_skb->len, + ack_skb->data + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16), ack_skb->len - + (MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16)), !tx_status->status, GFP_ATOMIC); dev_kfree_skb_any(ack_skb); } -- cgit v1.2.3-70-g09d2 From 251086f588720277a6f5782020a648ce32c4e00b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 8 Jul 2015 10:18:50 -0500 Subject: rtlwifi: rtl8821ae: Fix an expression that is always false In routine _rtl8821ae_set_media_status(), an incorrect mask results in a test for AP status to always be false. Similar bugs were fixed in rtl8192cu and rtl8192de, but this instance was missed at that time. Reported-by: David Binderman Signed-off-by: Larry Finger Cc: Stable [3.18+] Cc: David Binderman Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8821ae/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 3236d44b459d..b7f18e2155eb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c @@ -2180,7 +2180,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h index 53668fc8f23e..1d6110f9c1fb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h @@ -429,6 +429,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- cgit v1.2.3-70-g09d2 From 77661208a87b458f353fd0b7a4729cf2887449a6 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Wed, 8 Jul 2015 22:22:46 +0200 Subject: brcmsmac: Use kstrdup to simplify code Replace a kmalloc+strcpy by an equivalent kstrdup in order to improve readability. Signed-off-by: Christophe JAILLET Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ab775a5d5b33..d2c5747e3ac9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1472,9 +1472,7 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl, wl->timers = t; #ifdef DEBUG - t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); - if (t->name) - strcpy(t->name, name); + t->name = kstrdup(name, GFP_ATOMIC); #endif return t; -- cgit v1.2.3-70-g09d2 From 92cd40322848a12f1f3ef2d7804233b93030c532 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 12:27:22 +0200 Subject: ath9k: fix moredata flag endianness in cabq tx While compiling ath9k with some extra flags I've found that: ath9k/xmit.c +2473 ## 16: warning: restricted __le16 degrades to integer ath9k/xmit.c +2474 ## 36: warning: invalid assignment: &= ath9k/xmit.c +2474 ## 36: left side has type restricted __le16 ath9k/xmit.c +2474 ## 36: right side has type int There's no way for frame ftype/stype to be mistreated as the offending 'moredata' flag when considering cab queue. This could've however theoretically led sometimes to increased power consumption on connected stations as they would keep their Rx active waiting for frames that would never come. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c627f1233da..b766a7fc60aa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2473,8 +2473,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bf = list_first_entry(&bf_q, struct ath_buf, list); hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; - if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) { - hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA; + if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) { + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, sizeof(*hdr), DMA_TO_DEVICE); } -- cgit v1.2.3-70-g09d2 From e3faa866d5e4d6199b45f821343ee24510881823 Mon Sep 17 00:00:00 2001 From: Rafa? Mi?ecki Date: Thu, 9 Jul 2015 17:07:08 +0200 Subject: brcmfmac: set wiphy's addresses to provide valid MACs Broadcom's firmware requires every BSS to use MAC address with unique last few bits. The amount of bits may depend on a particular firmware, it was verified to be 2 for BCM43602 one. If this condition won't be fulfilled firmware will reject such MAC: brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52 We don't want to simply set addr_mask as it would also disallow using locally administrated bit. Instead let's build a list of addresses manually enabling 0x2 bit for extra interfaces. Signed-off-by: Rafa? Mi?ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 14 ++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/core.h | 3 +++ 2 files changed, 17 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index d86d1f1f1c91..ffe526070d6f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5785,6 +5785,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; struct ieee80211_supported_band *band; __le32 bandlist[3]; u32 n_bands; @@ -5798,6 +5799,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) if (err) return err; + for (i = 0; i < wiphy->iface_combinations->max_interfaces && + i < ARRAY_SIZE(drvr->addresses); i++) { + u8 *addr = drvr->addresses[i].addr; + + memcpy(addr, drvr->mac, ETH_ALEN); + if (i) { + addr[0] |= BIT(1); + addr[ETH_ALEN - 1] ^= i; + } + } + wiphy->addresses = drvr->addresses; + wiphy->n_addresses = i; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index fd74a9c6e9ac..746304121cdb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -21,6 +21,7 @@ #ifndef BRCMFMAC_CORE_H #define BRCMFMAC_CORE_H +#include #include "fweh.h" #define TOE_TX_CSUM_OL 0x00000001 @@ -118,6 +119,8 @@ struct brcmf_pub { /* Multicast data packets sent to dongle */ unsigned long tx_multicast; + struct mac_address addresses[BRCMF_MAX_IFS]; + struct brcmf_if *iflist[BRCMF_MAX_IFS]; struct mutex proto_block; -- cgit v1.2.3-70-g09d2 From fa5b8c8a5ae4088a590d59fffb022da3ea17bd15 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:06 +0800 Subject: ath9k: Fix register definitions for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fc595b92ac56..c5f8bc4b5595 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -455,7 +455,7 @@ #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) #define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) -#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) +#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x1c : 0x24)) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) #define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) @@ -495,7 +495,7 @@ #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 -#define AR_PHY_TEST (AR_SM_BASE + 0x160) +#define AR_PHY_TEST (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x15c : 0x160)) #define AR_PHY_TEST_BBB_OBS_SEL 0x780000 #define AR_PHY_TEST_BBB_OBS_SEL_S 19 @@ -521,24 +521,29 @@ #define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 -#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) +#define AR_PHY_TSTDAC (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x164 : 0x168)) -#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x168 : 0x16c)) #define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 -#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174) -#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178) -#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c) -#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + 0x180) -#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) -#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) +#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x170 : 0x174)) +#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x174 : 0x178)) +#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x178 : 0x17c)) +#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x17c : 0x180)) +#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x184 : 0x190)) +#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x188 : 0x194)) #define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) +#define AR_PHY_HEAVYCLIP_1 (AR_SM_BASE + 0x19c) +#define AR_PHY_HEAVYCLIP_2 (AR_SM_BASE + 0x1a0) +#define AR_PHY_HEAVYCLIP_3 (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_4 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_5 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) #define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) -- cgit v1.2.3-70-g09d2 From 6301566e0b2dafa7d6779598621bca867962a0a2 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:07 +0800 Subject: ath9k: export HW random number generator We measured the FFT-based entropy in 3 ways, Shannon entropy, collision entropy, and directly measured min-entropy. Just to be conservative, we recommend the estimated min-Entropy to be 10 bits per 16-bit value. Analysis was done by Jacobson,David(djacobso@qti.qualcomm.com). Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Kconfig | 7 +++ drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 23 ++++++++++ drivers/net/wireless/ath/ath9k/main.c | 4 ++ drivers/net/wireless/ath/ath9k/rng.c | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 drivers/net/wireless/ath/ath9k/rng.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index fee0cadb0f5e..bde62ec98bc7 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,3 +176,10 @@ 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--- + Provides a hardware random number generator to the kernel. 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 a7a81b3969ce..45596e5ae4db 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" @@ -1041,6 +1042,12 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif + +#ifdef CONFIG_ATH9K_HWRNG + struct hwrng rng; + bool rng_initialized; + u32 rng_last; +#endif }; /********/ @@ -1063,6 +1070,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_register(struct ath_softc *sc); +void ath9k_rng_unregister(struct ath_softc *sc); +#else +static inline void ath9k_rng_register(struct ath_softc *sc) +{ +} + +static inline void ath9k_rng_unregister(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/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc..5916ab2f4a3d 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_register(sc); + return 0; } @@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); + ath9k_rng_unregister(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c new file mode 100644 index 000000000000..d8fa7a535ab8 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -0,0 +1,75 @@ +/* + * 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 "ath9k.h" +#include "hw.h" +#include "ar9003_phy.h" + +static int ath9k_rng_data_read(struct hwrng *rng, u32 *data) +{ + u32 v1, v2; + struct ath_softc *sc = (struct ath_softc *)rng->priv; + struct ath_hw *ah = sc->sc_ah; + + ath9k_ps_wakeup(sc); + + REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 5); + 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); + + v1 = REG_READ(ah, AR_PHY_TST_ADC); + v2 = REG_READ(ah, AR_PHY_TST_ADC); + + ath9k_ps_restore(sc); + + /* wait for data ready */ + if (v1 && v2 && sc->rng_last != v1 && v1 != v2) { + *data = (v1 & 0xffff) | (v2 << 16); + sc->rng_last = v2; + + return sizeof(u32); + } + + sc->rng_last = v2; + + return 0; +} + +void ath9k_rng_register(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (WARN_ON(sc->rng_initialized)) + return; + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + + sc->rng.name = "ath9k"; + sc->rng.data_read = ath9k_rng_data_read; + sc->rng.priv = (unsigned long)sc; + + if (!hwrng_register(&sc->rng)) + sc->rng_initialized = true; +} + +void ath9k_rng_unregister(struct ath_softc *sc) +{ + if (sc->rng_initialized) { + hwrng_unregister(&sc->rng); + sc->rng_initialized = false; + } +} -- cgit v1.2.3-70-g09d2 From 5d6af28a2d240602a594cea236406a9d29bc719a Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Thu, 16 Jul 2015 11:22:47 +0300 Subject: wlcore: add antenna diversity reading update the rssi reading on rx_status to read both RSSI level (7 bits) and antenna diversity (msb) Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/rx.c | 3 ++- drivers/net/wireless/ti/wlcore/rx.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index e125974285cc..7df672a84530 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,7 +74,8 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; - status->signal = desc->rssi; + status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); + status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index a3b1618db27c..f5a7087cfb97 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -30,6 +30,9 @@ #define WL1271_RX_MAX_RSSI -30 #define WL1271_RX_MIN_RSSI -95 +#define RSSI_LEVEL_BITMASK 0x7F +#define ANT_DIVERSITY_BITMASK BIT(7) + #define SHORT_PREAMBLE_BIT BIT(0) #define OFDM_RATE_BIT BIT(6) #define PBCC_RATE_BIT BIT(7) -- cgit v1.2.3-70-g09d2 From 8358491d893e08d4b82af0d6012e078158f57ed9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 16 Jul 2015 15:42:15 +0300 Subject: iwlegacy: convert hex_dump_to_buffer() to %*ph There is no need to use hex_dump_to_buffer() in the cases like this: hexdump_to_buffer(buf, len, 16, 1, outbuf, outlen, false); /* len <= 16 */ sprintf("%s\n", outbuf); since it maybe easily converted to simple: sprintf("%*ph\n", len, buf); Note: it seems in the case the output is groupped by 2 bytes and looks like a typo. Thus, patch changes that to plain byte stream. Signed-off-by: Andy Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/debug.c | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 7f4cb692cc57..af1b3e6839fa 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3259,7 +3259,7 @@ il3945_show_measurement(struct device *d, struct device_attribute *attr, while (size && PAGE_SIZE - len) { hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); + PAGE_SIZE - len, true); len = strlen(buf); if (PAGE_SIZE - len) buf[len++] = '\n'; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index 344010153196..908b9f4fef6f 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -515,12 +515,8 @@ il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n", eeprom_ver); for (ofs = 0; ofs < eeprom_len; ofs += 16) { - pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 2, buf + pos, - buf_size - pos, 0); - pos += strlen(buf + pos); - if (buf_size - pos > 0) - buf[pos++] = '\n'; + pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", + ofs, ptr + ofs); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -- cgit v1.2.3-70-g09d2 From 40d7412b56f02160291a5153551c4ada8e76f6ed Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:21 -0700 Subject: mwifiex: add bss mode TLV to extended scan command We are setting BSS mode as ANY so that firmware will provide all types of scan entries. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 6 ++++++ drivers/net/wireless/mwifiex/scan.c | 10 ++++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 98269bfd2b31..cff38ad129aa 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -179,6 +179,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198) #define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202) #define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203) +#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 206) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -1434,6 +1435,11 @@ struct host_cmd_ds_802_11_scan_ext { u8 tlv_buffer[1]; } __packed; +struct mwifiex_ie_types_bss_mode { + struct mwifiex_ie_types_header header; + u8 bss_mode; +} __packed; + struct mwifiex_ie_types_bss_scan_rsp { struct mwifiex_ie_types_header header; u8 bssid[ETH_ALEN]; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index baf9715ddc10..ef2bef8399c2 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -823,6 +823,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, int i; u8 ssid_filter; struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_bss_mode *bss_mode; /* The tlv_buf_len is calculated for each scan command. The TLVs added in this routine will be preserved since the routine that sends the @@ -968,6 +969,15 @@ mwifiex_config_scan(struct mwifiex_private *priv, else *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + if (adapter->ext_scan) { + bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; + bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); + bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); + bss_mode->bss_mode = scan_cfg_out->bss_mode; + tlv_pos += sizeof(bss_mode->header) + + le16_to_cpu(bss_mode->header.len); + } + /* If the input config or adapter has the number of Probes set, add tlv */ if (num_probes) { -- cgit v1.2.3-70-g09d2 From 0c6303cc06954c336a8221522e9ddf056125afab Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:22 -0700 Subject: mwifiex: use maximum ssid length as 0xfe for p2p 0xfe is basically a magic number used to ask firmware match provided string in a SSID. In this case, firmware will return scan results containing"DIRECT-" string. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/scan.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index ef2bef8399c2..ef8da8ebcbab 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -909,6 +909,10 @@ mwifiex_config_scan(struct mwifiex_private *priv, wildcard_ssid_tlv->max_ssid_length = IEEE80211_MAX_SSID_LEN; + if (!memcmp(user_scan_in->ssid_list[i].ssid, + "DIRECT-", 7)) + wildcard_ssid_tlv->max_ssid_length = 0xfe; + memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[i].ssid, ssid_len); -- cgit v1.2.3-70-g09d2 From e79801ffe9c862597750359b8c6825f3a3bfaa4f Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:48:43 -0700 Subject: mwifiex: correct p2p and station interface counters While changing interface type from p2p client or p2p go to station, we should update counters for p2p interface and station interface. Also calling mwifiex_cfg80211_deinit_p2p method instead of mwifiex_cfg80211_init_p2p_client method to deinit p2p interface. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d4b327752a5e..ff63cb5632eb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1145,8 +1145,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_GO: switch (type) { case NL80211_IFTYPE_STATION: - if (mwifiex_cfg80211_init_p2p_client(priv)) + if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT; + priv->adapter->curr_iface_comb.p2p_intf--; + priv->adapter->curr_iface_comb.sta_intf++; dev->ieee80211_ptr->iftype = type; break; case NL80211_IFTYPE_ADHOC: -- cgit v1.2.3-70-g09d2 From acd195800ffca556e9c78c51d1efe534d71dd236 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 10 Jul 2015 14:31:20 +0530 Subject: ath10k: delay device access after cold reset It is observed that during cold reset pcie access right after a write operation to SOC_GLOBAL_RESET_ADDRESS causes Data Bus Error and system hard lockup. The reason for bus error is that pcie needs some time to get back to stable state for any transaction during cold reset. Add delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS to fix this issue. This patch is tested on QCA988X. This is also tested on QCA99X0 which is WIP. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5778e5277823..a69bfa41c68b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2761,7 +2761,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) static int ath10k_pci_cold_reset(struct ath10k *ar) { - int i; u32 val; ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); @@ -2777,23 +2776,18 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) val |= 1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK) - break; - msleep(1); - } + /* After writing into SOC_GLOBAL_RESET to put device into + * reset and pulling out of reset pcie may not be stable + * for any immediate pcie register access and cause bus error, + * add delay before any pcie access request to fix this issue. + */ + msleep(20); /* Pull Target, including PCIe, out of RESET. */ val &= ~1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK)) - break; - msleep(1); - } + msleep(20); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); -- cgit v1.2.3-70-g09d2 From fbc03a466fd48bc8be2e675be948001feea29e4d Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:19 -0700 Subject: ath10k: update tx path to support QCA99X0 Since QCA99X0 uses fragmentation descriptor differently from other ones on tx path, we need to handle it separately. QCA99X0 is using 48 bits for address and 16 bits for length out of 2 dword and each values have to be programmed by frag desc base addr + msdu id, so that hardware can retrieve corresponding frag data. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 13 ++++++++++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 35 +++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8bdf1e7dd171..e31cd74dded6 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -83,8 +83,17 @@ struct htt_ver_req { * around the mask + shift defs. */ struct htt_data_tx_desc_frag { - __le32 paddr; - __le32 len; + union { + struct double_word_addr { + __le32 paddr; + __le32 len; + } __packed dword_addr; + struct triple_word_addr { + __le32 paddr_lo; + __le16 paddr_hi; + __le16 len_16; + } __packed tword_addr; + } __packed; } __packed; struct htt_msdu_ext_desc { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 148d5b607c3c..c49ecffc2905 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -63,7 +63,8 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) lockdep_assert_held(&htt->tx_lock); - ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); + ret = idr_alloc(&htt->pending_tx, skb, 0, + htt->max_num_pending_tx, GFP_ATOMIC); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); @@ -259,6 +260,7 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); cmd->frag_desc_bank_cfg.bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0; cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - 1); @@ -537,16 +539,29 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; /* pass through */ case ATH10K_HW_TXRX_ETHERNET: - frags = skb_cb->htt.txbuf->frags; - - frags[0].paddr = __cpu_to_le32(skb_cb->paddr); - frags[0].len = __cpu_to_le32(msdu->len); - frags[1].paddr = 0; - frags[1].len = 0; - + if (ar->hw_params.continuous_frag_desc) { + frags = (struct htt_data_tx_desc_frag *) + &htt->frag_desc.vaddr[msdu_id].frags; + frags[0].tword_addr.paddr_lo = + __cpu_to_le32(skb_cb->paddr); + frags[0].tword_addr.paddr_hi = 0; + frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); + frags[1].tword_addr.paddr_lo = 0; + frags[1].tword_addr.paddr_hi = 0; + + frags_paddr = htt->frag_desc.paddr + + (sizeof(struct htt_msdu_ext_desc) * msdu_id); + } else { + frags = skb_cb->htt.txbuf->frags; + frags[0].dword_addr.paddr = + __cpu_to_le32(skb_cb->paddr); + frags[0].dword_addr.len = __cpu_to_le32(msdu->len); + frags[1].dword_addr.paddr = 0; + frags[1].dword_addr.len = 0; + + frags_paddr = skb_cb->htt.txbuf_paddr; + } flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - - frags_paddr = skb_cb->htt.txbuf_paddr; break; case ATH10K_HW_TXRX_MGMT: flags0 |= SM(ATH10K_HW_TXRX_MGMT, -- cgit v1.2.3-70-g09d2 From 05a2cb0daa49af4e240834ff3736fd35ba83320f Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:20 -0700 Subject: ath10k: redefine rx_ppdu_end_common structure to cover qca99x0 rx_ppdu_end_common structure is valid for both of qca998x and qca6174, but not for qca99x0 since it has new additional members. Hence update the common structure to cover qca99x0 as well. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/rx_desc.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 492b5a5af434..6cb078d6c3cc 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -891,13 +891,13 @@ struct rx_ppdu_end_common { __le32 evm_p15; __le32 tsf_timestamp; __le32 wb_timestamp; +} __packed; + +struct rx_ppdu_end_qca988x { u8 locationing_timestamp; u8 phy_err_code; __le16 flags; /* %RX_PPDU_END_FLAGS_ */ __le32 info0; /* %RX_PPDU_END_INFO0_ */ -} __packed; - -struct rx_ppdu_end_qca988x { __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; @@ -909,6 +909,10 @@ struct rx_ppdu_end_qca988x { #define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) struct rx_ppdu_end_qca6174 { + u8 locationing_timestamp; + u8 phy_err_code; + __le16 flags; /* %RX_PPDU_END_FLAGS_ */ + __le32 info0; /* %RX_PPDU_END_INFO0_ */ __le32 rtt; /* %RX_PPDU_END_RTT_ */ __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ -- cgit v1.2.3-70-g09d2 From 1f5dbfbb64c92e1c22305ac2b3951d6e3cf7a9a7 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:21 -0700 Subject: ath10k: add support for qca99x0 Rx descriptors QCA99X0 chip has an extra 4 bytes in rx_msdu_start, 20 bytes in rx_msdu_end and 20 bytes in rx_ppdu_end structure which are used in htt_rx_desc and HTT Rx ring offset setup. This is necessary for correct Rx for QCA99X0 or Rx descriptors will be overwritten and corrupted. With this patch QCA988X and QCA6174 will have extra 44 bytes padding in Rx descriptor layout which is harmless. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 24 ++--- drivers/net/wireless/ath/ath10k/rx_desc.h | 163 +++++++++++++++++++++++++++++- 2 files changed, 172 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index d7d118328f31..61a26264728a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -368,7 +368,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_len_invalid = !!(__le32_to_cpu(rx_desc->attention.flags) & (RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR | RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR)); - msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), + msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.common.info0), RX_MSDU_START_INFO0_MSDU_LENGTH); msdu_chained = rx_desc->frag_info.ring2_more_count; @@ -394,7 +394,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_chaining = 1; } - last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & + last_msdu = __le32_to_cpu(rx_desc->msdu_end.common.info0) & RX_MSDU_END_INFO0_LAST_MSDU; trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, @@ -740,7 +740,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd) __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID)) return NULL; - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU))) return NULL; @@ -991,9 +991,9 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, bool is_last; rxd = (void *)msdu->data - sizeof(*rxd); - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); /* Delivered decapped frame: @@ -1104,9 +1104,9 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, rxd = (void *)msdu->data - sizeof(*rxd); hdr = (void *)rxd->rx_hdr_status; - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); is_amsdu = !(is_first && is_last); @@ -1214,7 +1214,7 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); switch (decap) { @@ -1244,7 +1244,7 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) rxd = (void *)skb->data - sizeof(*rxd); flags = __le32_to_cpu(rxd->attention.flags); - info = __le32_to_cpu(rxd->msdu_start.info1); + info = __le32_to_cpu(rxd->msdu_start.common.info1); is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO); is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO); @@ -1437,7 +1437,7 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, first = skb_peek(amsdu); rxd = (void *)first->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); if (!chained) @@ -1757,14 +1757,14 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, __skb_queue_tail(amsdu, msdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (rxd->msdu_end.info0 & + if (rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) break; } msdu = skb_peek_tail(amsdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { skb_queue_splice_init(amsdu, list); return -EAGAIN; diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 6cb078d6c3cc..ca8d16884af1 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -422,6 +422,12 @@ struct rx_mpdu_end { #define RX_MSDU_START_INFO1_IP_FRAG (1 << 14) #define RX_MSDU_START_INFO1_TCP_ONLY_ACK (1 << 15) +#define RX_MSDU_START_INFO2_DA_IDX_MASK 0x000007ff +#define RX_MSDU_START_INFO2_DA_IDX_LSB 0 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_MASK 0x00ff0000 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_LSB 16 +#define RX_MSDU_START_INFO2_DA_BCAST_MCAST BIT(11) + /* The decapped header (rx_hdr_status) contains the following: * a) 802.11 header * [padding to 4 bytes] @@ -449,12 +455,23 @@ enum rx_msdu_decap_format { RX_MSDU_DECAP_8023_SNAP_LLC = 3 }; -struct rx_msdu_start { +struct rx_msdu_start_common { __le32 info0; /* %RX_MSDU_START_INFO0_ */ __le32 flow_id_crc; __le32 info1; /* %RX_MSDU_START_INFO1_ */ } __packed; +struct rx_msdu_start_qca99x0 { + __le32 info2; /* %RX_MSDU_START_INFO2_ */ +} __packed; + +struct rx_msdu_start { + struct rx_msdu_start_common common; + union { + struct rx_msdu_start_qca99x0 qca99x0; + } __packed; +} __packed; + /* * msdu_length * MSDU length in bytes after decapsulation. This field is @@ -540,7 +557,7 @@ struct rx_msdu_start { #define RX_MSDU_END_INFO0_PRE_DELIM_ERR (1 << 30) #define RX_MSDU_END_INFO0_RESERVED_3B (1 << 31) -struct rx_msdu_end { +struct rx_msdu_end_common { __le16 ip_hdr_cksum; __le16 tcp_hdr_cksum; u8 key_id_octet; @@ -549,6 +566,36 @@ struct rx_msdu_end { __le32 info0; } __packed; +#define RX_MSDU_END_INFO1_TCP_FLAG_MASK 0x000001ff +#define RX_MSDU_END_INFO1_TCP_FLAG_LSB 0 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_MASK 0x00001c00 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_LSB 10 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_MASK 0xffff0000 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_LSB 16 +#define RX_MSDU_END_INFO1_IRO_ELIGIBLE BIT(9) + +#define RX_MSDU_END_INFO2_DA_OFFSET_MASK 0x0000003f +#define RX_MSDU_END_INFO2_DA_OFFSET_LSB 0 +#define RX_MSDU_END_INFO2_SA_OFFSET_MASK 0x00000fc0 +#define RX_MSDU_END_INFO2_SA_OFFSET_LSB 6 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_MASK 0x0003f000 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_LSB 12 + +struct rx_msdu_end_qca99x0 { + __le32 ipv6_crc; + __le32 tcp_seq_no; + __le32 tcp_ack_no; + __le32 info1; + __le32 info2; +} __packed; + +struct rx_msdu_end { + struct rx_msdu_end_common common; + union { + struct rx_msdu_end_qca99x0 qca99x0; + } __packed; +} __packed; + /* *ip_hdr_chksum * This can include the IP header checksum or the pseudo header @@ -870,7 +917,11 @@ struct rx_ppdu_start { #define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24) #define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25) -#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) +#define RX_PPDU_END_INFO1_PEER_IDX_MASK 0x1ffc +#define RX_PPDU_END_INFO1_PEER_IDX_LSB 2 +#define RX_PPDU_END_INFO1_BB_DATA BIT(0) +#define RX_PPDU_END_INFO1_PEER_IDX_VALID BIT(1) +#define RX_PPDU_END_INFO1_PPDU_DONE BIT(15) struct rx_ppdu_end_common { __le32 evm_p0; @@ -918,11 +969,117 @@ struct rx_ppdu_end_qca6174 { __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +#define RX_PKT_END_INFO0_RX_SUCCESS BIT(0) +#define RX_PKT_END_INFO0_ERR_TX_INTERRUPT_RX BIT(3) +#define RX_PKT_END_INFO0_ERR_OFDM_POWER_DROP BIT(4) +#define RX_PKT_END_INFO0_ERR_OFDM_RESTART BIT(5) +#define RX_PKT_END_INFO0_ERR_CCK_POWER_DROP BIT(6) +#define RX_PKT_END_INFO0_ERR_CCK_RESTART BIT(7) + +#define RX_LOCATION_INFO_RTT_CORR_VAL_MASK 0x0001ffff +#define RX_LOCATION_INFO_RTT_CORR_VAL_LSB 0 +#define RX_LOCATION_INFO_FAC_STATUS_MASK 0x000c0000 +#define RX_LOCATION_INFO_FAC_STATUS_LSB 18 +#define RX_LOCATION_INFO_PKT_BW_MASK 0x00700000 +#define RX_LOCATION_INFO_PKT_BW_LSB 20 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_MASK 0x01800000 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_LSB 23 +#define RX_LOCATION_INFO_CIR_STATUS BIT(17) +#define RX_LOCATION_INFO_RTT_MAC_PHY_PHASE BIT(25) +#define RX_LOCATION_INFO_RTT_TX_DATA_START_X BIT(26) +#define RX_LOCATION_INFO_HW_IFFT_MODE BIT(30) +#define RX_LOCATION_INFO_RX_LOCATION_VALID BIT(31) + +struct rx_pkt_end { + __le32 info0; /* %RX_PKT_END_INFO0_ */ + __le32 phy_timestamp_1; + __le32 phy_timestamp_2; + __le32 rx_location_info; /* %RX_LOCATION_INFO_ */ +} __packed; + +enum rx_phy_ppdu_end_info0 { + RX_PHY_PPDU_END_INFO0_ERR_RADAR = BIT(2), + RX_PHY_PPDU_END_INFO0_ERR_RX_ABORT = BIT(3), + RX_PHY_PPDU_END_INFO0_ERR_RX_NAP = BIT(4), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_TIMING = BIT(5), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_PARITY = BIT(6), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RATE = BIT(7), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_LENGTH = BIT(8), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RESTART = BIT(9), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_SERVICE = BIT(10), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_POWER_DROP = BIT(11), + RX_PHY_PPDU_END_INFO0_ERR_CCK_BLOCKER = BIT(12), + RX_PHY_PPDU_END_INFO0_ERR_CCK_TIMING = BIT(13), + RX_PHY_PPDU_END_INFO0_ERR_CCK_HEADER_CRC = BIT(14), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RATE = BIT(15), + RX_PHY_PPDU_END_INFO0_ERR_CCK_LENGTH = BIT(16), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RESTART = BIT(17), + RX_PHY_PPDU_END_INFO0_ERR_CCK_SERVICE = BIT(18), + RX_PHY_PPDU_END_INFO0_ERR_CCK_POWER_DROP = BIT(19), + RX_PHY_PPDU_END_INFO0_ERR_HT_CRC = BIT(20), + RX_PHY_PPDU_END_INFO0_ERR_HT_LENGTH = BIT(21), + RX_PHY_PPDU_END_INFO0_ERR_HT_RATE = BIT(22), + RX_PHY_PPDU_END_INFO0_ERR_HT_ZLF = BIT(23), + RX_PHY_PPDU_END_INFO0_ERR_FALSE_RADAR_EXT = BIT(24), + RX_PHY_PPDU_END_INFO0_ERR_GREEN_FIELD = BIT(25), + RX_PHY_PPDU_END_INFO0_ERR_SPECTRAL_SCAN = BIT(26), + RX_PHY_PPDU_END_INFO0_ERR_RX_DYN_BW = BIT(27), + RX_PHY_PPDU_END_INFO0_ERR_LEG_HT_MISMATCH = BIT(28), + RX_PHY_PPDU_END_INFO0_ERR_VHT_CRC = BIT(29), + RX_PHY_PPDU_END_INFO0_ERR_VHT_SIGA = BIT(30), + RX_PHY_PPDU_END_INFO0_ERR_VHT_LSIG = BIT(31), +}; + +enum rx_phy_ppdu_end_info1 { + RX_PHY_PPDU_END_INFO1_ERR_VHT_NDP = BIT(0), + RX_PHY_PPDU_END_INFO1_ERR_VHT_NSYM = BIT(1), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_EXT_SYM = BIT(2), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID0 = BIT(3), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID1_62 = BIT(4), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID63 = BIT(5), + RX_PHY_PPDU_END_INFO1_ERR_OFDM_LDPC_DECODER = BIT(6), + RX_PHY_PPDU_END_INFO1_ERR_DEFER_NAP = BIT(7), + RX_PHY_PPDU_END_INFO1_ERR_FDOMAIN_TIMEOUT = BIT(8), + RX_PHY_PPDU_END_INFO1_ERR_LSIG_REL_CHECK = BIT(9), + RX_PHY_PPDU_END_INFO1_ERR_BT_COLLISION = BIT(10), + RX_PHY_PPDU_END_INFO1_ERR_MU_FEEDBACK = BIT(11), + RX_PHY_PPDU_END_INFO1_ERR_TX_INTERRUPT_RX = BIT(12), + RX_PHY_PPDU_END_INFO1_ERR_RX_CBF = BIT(13), +}; + +struct rx_phy_ppdu_end { + __le32 info0; /* %RX_PHY_PPDU_END_INFO0_ */ + __le32 info1; /* %RX_PHY_PPDU_END_INFO1_ */ +} __packed; + +#define RX_PPDU_END_RX_TIMING_OFFSET_MASK 0x00000fff +#define RX_PPDU_END_RX_TIMING_OFFSET_LSB 0 + +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_MASK 0x00ffffff +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_LSB 0 +#define RX_PPDU_END_RX_INFO_TX_HT_VHT_ACK BIT(24) +#define RX_PPDU_END_RX_INFO_RX_PKT_END_VALID BIT(25) +#define RX_PPDU_END_RX_INFO_RX_PHY_PPDU_END_VALID BIT(26) +#define RX_PPDU_END_RX_INFO_RX_TIMING_OFFSET_VALID BIT(27) +#define RX_PPDU_END_RX_INFO_BB_CAPTURED_CHANNEL BIT(28) +#define RX_PPDU_END_RX_INFO_UNSUPPORTED_MU_NC BIT(29) +#define RX_PPDU_END_RX_INFO_OTP_TXBF_DISABLE BIT(30) + +struct rx_ppdu_end_qca99x0 { + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ + __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + struct rx_ppdu_end { struct rx_ppdu_end_common common; union { struct rx_ppdu_end_qca988x qca988x; struct rx_ppdu_end_qca6174 qca6174; + struct rx_ppdu_end_qca99x0 qca99x0; } __packed; } __packed; -- cgit v1.2.3-70-g09d2 From 19be9e9a7ac7e6050eab426283d2a87593cf6e82 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Thu, 16 Jul 2015 09:25:33 +0530 Subject: ath10k: fix wrong initialization of struct channel chandef is initialized with NULL and on the very next line, we are using it to get channel, which is not correct. Channel should be initialized after obtaining chandef. Found by cppcheck: ath/ath10k/mac.c:839]: (error) Possible null pointer dereference: chandef Signed-off-by: Maninder Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c9a7d5b5dffc..49a54a1f07a8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -836,7 +836,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; - struct ieee80211_channel *channel = chandef->chan; + struct ieee80211_channel *channel = NULL; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; -- cgit v1.2.3-70-g09d2 From b963519509644f52eaaddcc1fa484e28ac74c750 Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 20 Jul 2015 17:56:12 +0530 Subject: ath10k: add TCP/UDP Checksum offload support for QCA99x0 The patch adds support to offload TCP/UDP checksum calculations for QCA99x0. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 17 ++++++++++++++++- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index e31cd74dded6..551f64bf6457 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -97,10 +97,25 @@ struct htt_data_tx_desc_frag { } __packed; struct htt_msdu_ext_desc { - __le32 tso_flag[4]; + __le32 tso_flag[3]; + __le16 ip_identification; + u8 flags; + u8 reserved; struct htt_data_tx_desc_frag frags[6]; }; +#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE BIT(0) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE BIT(1) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE BIT(2) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE BIT(3) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE BIT(4) + +#define HTT_MSDU_CHECKSUM_ENABLE (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index c49ecffc2905..1b34c1350f63 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -496,6 +496,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) u16 msdu_id, flags1 = 0; dma_addr_t paddr = 0; u32 frags_paddr = 0; + struct htt_msdu_ext_desc *ext_desc = NULL; res = ath10k_htt_tx_inc_pending(htt); if (res) @@ -542,6 +543,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (ar->hw_params.continuous_frag_desc) { frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; + ext_desc = &htt->frag_desc.vaddr[msdu_id]; frags[0].tword_addr.paddr_lo = __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; @@ -603,6 +605,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (msdu->ip_summed == CHECKSUM_PARTIAL) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + if (ar->hw_params.continuous_frag_desc) + ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; } /* Prevent firmware from sending up tx inspection requests. There's -- cgit v1.2.3-70-g09d2 From 1d0088f8c1d8b9541ed01f2cc52606fbf8baf50c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Tue, 21 Jul 2015 10:52:00 +0530 Subject: ath10k: extend struct htt_mgmt_tx_dec for qca99x0 HTT_H2T_MSG_TYPE_MGMT_TX msg in 10.4 firmware carries additional 4 byte in htt_mgmt_tx_desc where it tells to firmware that at what rate mgmt frame has to go out in the air. It's an optional parameter, setting this field to zero will force firmware to choose auto rate and send the frame out. Those 4 byte info is missed out in the current code and 10.4 firmware ended up reading some junk in those 4 byte and sometime malfunctioning. Fix it by adding 4 byte in struct htt_mgmt_tx_desc. Non 10.4 firmware will not process those four byte. So, adding 4 byte at the end of struct htt_mgmt_tx_desc will not create any impact on other chipset. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 6 ++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 551f64bf6457..7583a126e879 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -284,6 +284,9 @@ struct htt_aggr_conf { } __packed; #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +struct htt_mgmt_tx_desc_qca99x0 { + __le32 rate; +} __packed; struct htt_mgmt_tx_desc { u8 pad[sizeof(u32) - sizeof(struct htt_cmd_hdr)]; @@ -292,6 +295,9 @@ struct htt_mgmt_tx_desc { __le32 len; __le32 vdev_id; u8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; + union { + struct htt_mgmt_tx_desc_qca99x0 qca99x0; + } __packed; } __packed; enum htt_mgmt_tx_status { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 1b34c1350f63..a97dd9d4295b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -450,6 +450,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; + memset(cmd, 0, len); + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX; cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); cmd->mgmt_tx.len = __cpu_to_le32(msdu->len); -- cgit v1.2.3-70-g09d2 From c9fdec9f3970eeaa1b176422f46167f5f5158804 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 20 Jul 2015 12:14:39 +0300 Subject: iwlwifi: pcie: fix prepare card flow When the card is not owned by the PCIe bus, we need to acquire ownership first. This flow is implemented in iwl_pcie_prepare_card_hw. Because of a hardware bug, we need to disable link power management before we can request ownership otherwise the other user of the device won't get notified that we are requesting the device which will prevent us from acquire ownership. Same holds for the down flow where we need to make sure that any other potential user is notified that the driver is going down. CC: [4.1] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 6203c4ad9bba..9e144e71da0b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_WAKE_ME); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE | CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(1); + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + } mdelay(5); } @@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) if (ret >= 0) return 0; + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + msleep(1); + for (iter = 0; iter < 10; iter++) { /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) do { ret = iwl_pcie_set_hw_ready(trans); - if (ret >= 0) - return 0; + if (ret >= 0) { + ret = 0; + goto out; + } usleep_range(200, 1000); t += 200; @@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) IWL_ERR(trans, "Couldn't prepare the card\n"); +out: + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + return ret; } -- cgit v1.2.3-70-g09d2 From dc9f69b907f3853952d3ffb7918d05a662146712 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 7 Jul 2015 16:53:42 +0300 Subject: iwlwifi: mvm: Fix regular scan priority The code checks the total number of iterations to differentiate between regular scan and scheduled scan. However, regular scan has a total of one iteration, not zero. As a result, regular scan will have lower priority than it should have, and in case scheduled scan is already running when regular scan is requested, regular scan will be delayed until scheduled scan is aborted. Fix that by checking for total iterations number of one as an identifier for regular scan. Fixes: 133c8259f885 ("iwlwifi: mvm: rename generic_scan_cmd functions to dwell") Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5000bfcded61..5514ad6d4e54 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1023,7 +1023,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->scan_priority = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); - if (iwl_mvm_scan_total_iterations(params) == 0) + if (iwl_mvm_scan_total_iterations(params) == 1) cmd->ooc_priority = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); else -- cgit v1.2.3-70-g09d2 From a0d61f5f61290ee70cd024c7573e2ac5562f7a78 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 13:30:37 -0400 Subject: ath6kl: spell "distribution" correctly in a comment. This fixes two misspellings of "distribution" in a comment. Signed-off-by: Nik Nyby Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 14cab1403dd6..112d8a9b8d43 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -427,7 +427,7 @@ struct htc_endpoint_credit_dist { }; /* - * credit distibution code that is passed into the distrbution function, + * credit distribution code that is passed into the distribution function, * there are mandatory and optional codes that must be handled */ enum htc_credit_dist_reason { -- cgit v1.2.3-70-g09d2 From 3413e97dbbae8561e01ac28ccb0d4bbe7ce933f4 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Tue, 21 Jul 2015 15:50:15 +0100 Subject: ath10k: suppress 'failed to process fft' warning messages When using DFS channels on Ath10k, kernel log has repeated warning message 'failed to process fft: -22' typically under medium/heavy traffic. This patch switches the warnings to driver debug (WMI events) mode only thus reducing log file noise. DFS and spectral scan share underlying HW mechanisms and enabling one (DFS) enables the other (spectral scan) as far as event reporting from firmware to driver is concerned. Spectral scan events take no part in processing of DFS radar pulses which are delivered as distinct events, so the fft (spectral event) warning is harmless and DFS interference detection/protection still occurs. Symptoms seen & fix tested in both debug & non-debug modes on TP-Link Archer C7 v2 platform. Signed-off-by: Kevin Darbyshire-Bryant Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0791a4336e80..1435614b0a55 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3498,7 +3498,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar, fftr, fftr_len, tsf); if (res < 0) { - ath10k_warn(ar, "failed to process fft report: %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n", res); return; } -- cgit v1.2.3-70-g09d2 From 005fb161310f72070ad5f4352d6b81ffaca8a11e Mon Sep 17 00:00:00 2001 From: Qi Zhou Date: Wed, 22 Jul 2015 16:38:24 -0400 Subject: ath10k: Improve performance by reducing tx_lock contention During tx completion, tx_lock is held for longer than required, preventing efficient refill of htt->pending_tx. Refactor the code so that only MSDU related operations are protected by the lock. Improves downstream performance on a dual-core ARM Freescale LS1024A (f.k.a. Mindspeed Comcerto 2000) AP with a 3x3 client from 495 to 580 Mbps. Other CPU bound multicore systems may also benefit. Signed-off-by: Denton Gentry Signed-off-by: Avery Pennarun [mfaltesek@google.com: removed conflicting code for tracking msdu_ids.] Signed-off-by: Marty Faltesek Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 12 ++---------- drivers/net/wireless/ath/ath10k/htt_tx.c | 8 ++------ drivers/net/wireless/ath/ath10k/txrx.c | 17 ++++++++--------- 3 files changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 61a26264728a..5e54c393767e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1631,8 +1631,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, __le16 msdu_id; int i; - lockdep_assert_held(&htt->tx_lock); - switch (status) { case HTT_DATA_TX_STATUS_NO_ACK: tx_done.no_ack = true; @@ -1998,15 +1996,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } - spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); - spin_unlock_bh(&htt->tx_lock); break; } case HTT_T2H_MSG_TYPE_TX_COMPL_IND: - spin_lock_bh(&htt->tx_lock); - __skb_queue_tail(&htt->tx_compl_q, skb); - spin_unlock_bh(&htt->tx_lock); + skb_queue_tail(&htt->tx_compl_q, skb); tasklet_schedule(&htt->txrx_compl_task); return; case HTT_T2H_MSG_TYPE_SEC_IND: { @@ -2095,12 +2089,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) struct htt_resp *resp; struct sk_buff *skb; - spin_lock_bh(&htt->tx_lock); - while ((skb = __skb_dequeue(&htt->tx_compl_q))) { + while ((skb = skb_dequeue(&htt->tx_compl_q))) { ath10k_htt_rx_frm_tx_compl(htt->ar, skb); dev_kfree_skb_any(skb); } - spin_unlock_bh(&htt->tx_lock); spin_lock_bh(&htt->rx_ring.lock); while ((skb = __skb_dequeue(&htt->rx_compl_q))) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a97dd9d4295b..2c0627b7141b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -134,9 +134,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) tx_done.discard = 1; tx_done.msdu_id = msdu_id; - spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); - spin_unlock_bh(&htt->tx_lock); return 0; } @@ -429,12 +427,11 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); + spin_unlock_bh(&htt->tx_lock); if (res < 0) { - spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - spin_unlock_bh(&htt->tx_lock); txdesc = ath10k_htc_alloc_skb(ar, len); if (!txdesc) { @@ -506,12 +503,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); + spin_unlock_bh(&htt->tx_lock); if (res < 0) { - spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 6cf289158840..e4a9c4c8d0cb 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; - lockdep_assert_held(&htt->tx_lock); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d success %d\n", tx_done->msdu_id, !!tx_done->discard, @@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, return; } + spin_lock_bh(&htt->tx_lock); msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); if (!msdu) { ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", tx_done->msdu_id); + spin_unlock_bh(&htt->tx_lock); return; } + ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); + __ath10k_htt_tx_dec_pending(htt); + if (htt->num_pending_tx == 0) + wake_up(&htt->empty_tx_wq); + spin_unlock_bh(&htt->tx_lock); skb_cb = ATH10K_SKB_CB(msdu); @@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, if (tx_done->discard) { ieee80211_free_txskb(htt->ar->hw, msdu); - goto exit; + return; } if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -104,12 +109,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ieee80211_tx_status(htt->ar->hw, msdu); /* we do not own the msdu anymore */ - -exit: - ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); - __ath10k_htt_tx_dec_pending(htt); - if (htt->num_pending_tx == 0) - wake_up(&htt->empty_tx_wq); } struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, -- cgit v1.2.3-70-g09d2 From ccec9038c7217e537f5ae5e3ac5af8293a21bbfd Mon Sep 17 00:00:00 2001 From: David Liu Date: Fri, 24 Jul 2015 20:25:32 +0300 Subject: ath10k: enable raw encap mode and software crypto engine This patch enables raw Rx/Tx encap mode to support software based crypto engine. This patch introduces a new module param 'cryptmode'. cryptmode: 0: Use hardware crypto engine globally with native Wi-Fi mode TX/RX encapsulation to the firmware. This is the default mode. 1: Use sofware crypto engine globally with raw mode TX/RX encapsulation to the firmware. Known limitation: A-MSDU must be disabled for RAW Tx encap mode to perform well when heavy traffic is applied. Testing: (by Michal Kazior ) a) Performance Testing cryptmode=1 ap=qca988x sta=killer1525 killer1525 -> qca988x 194.496 mbps [tcp1 ip4] killer1525 -> qca988x 238.309 mbps [tcp5 ip4] killer1525 -> qca988x 266.958 mbps [udp1 ip4] killer1525 -> qca988x 477.468 mbps [udp5 ip4] qca988x -> killer1525 301.378 mbps [tcp1 ip4] qca988x -> killer1525 297.949 mbps [tcp5 ip4] qca988x -> killer1525 331.351 mbps [udp1 ip4] qca988x -> killer1525 371.528 mbps [udp5 ip4] ap=killer1525 sta=qca988x qca988x -> killer1525 331.447 mbps [tcp1 ip4] qca988x -> killer1525 328.783 mbps [tcp5 ip4] qca988x -> killer1525 375.309 mbps [udp1 ip4] qca988x -> killer1525 403.379 mbps [udp5 ip4] killer1525 -> qca988x 203.689 mbps [tcp1 ip4] killer1525 -> qca988x 222.339 mbps [tcp5 ip4] killer1525 -> qca988x 264.199 mbps [udp1 ip4] killer1525 -> qca988x 479.371 mbps [udp5 ip4] Note: - only open network tested for RAW vs nwifi performance comparison - killer1525 (qca6174 hw2.2) is 2x2 device (hence max 866mbps) - used iperf - OTA, devices a few cm apart from each other, no shielding - tcpX/udpX, X - means number of threads used Overview: - relative Tx performance drop is seen but is within reasonable and expected threshold (A-MSDU must be disabled with RAW Tx) b) Connectivity Testing cryptmode=1 ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta2br1vlan OK Note: - each test takes all possible endpoint pairs and pings - each pair-ping flushes arp table - ip6 is used c) Testbed Topology: 1ap1sta: [ap] ---- [sta] endpoints: ap, sta 1ap1sta2br: [veth0] [ap] ---- [sta] [veth2] | | | | [veth1] | \ [veth3] \ / \ / [br0] [br1] endpoints: veth0, veth2, br0, br1 note: STA works in 4addr mode, AP has wds_sta=1 1ap1sta2br1vlan: [veth0] [ap] ---- [sta] [veth2] | | | | [veth1] | \ [veth3] \ / \ / [br0] [br1] | | [vlan0_id2] [vlan1_id2] endpoints: vlan0_id2, vlan1_id2 note: STA works in 4addr mode, AP has wds_sta=1 Credits: Thanks to Michal Kazior who helped find the amsdu issue, contributed a workaround (already squashed into this patch), and contributed the throughput and connectivity tests results. Signed-off-by: David Liu Signed-off-by: Michal Kazior Tested-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 43 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 31 +++++++++++--- drivers/net/wireless/ath/ath10k/debug.c | 19 ++++----- drivers/net/wireless/ath/ath10k/htt.c | 23 +++++++++- drivers/net/wireless/ath/ath10k/htt.h | 8 ++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 7 ++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 12 +++++- drivers/net/wireless/ath/ath10k/hw.h | 11 ++--- drivers/net/wireless/ath/ath10k/mac.c | 70 ++++++++++++++++++++++++------- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 8 ++-- 11 files changed, 183 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f79fa6c67ebc..29d2541d87dd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -31,16 +31,19 @@ #include "wmi-ops.h" unsigned int ath10k_debug_mask; +static unsigned int ath10k_cryptmode_param; static bool uart_print; static bool skip_otp; module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); +module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { @@ -1073,6 +1076,46 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) return -EINVAL; } + ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + switch (ath10k_cryptmode_param) { + case ATH10K_CRYPT_MODE_HW: + clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); + clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); + break; + case ATH10K_CRYPT_MODE_SW: + if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, + ar->fw_features)) { + ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware"); + return -EINVAL; + } + + set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); + set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); + break; + default: + ath10k_info(ar, "invalid cryptmode: %d\n", + ath10k_cryptmode_param); + return -EINVAL; + } + + ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; + ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; + + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW; + + /* Workaround: + * + * Firmware A-MSDU aggregation breaks with RAW Tx encap mode + * and causes enormous performance issues (malformed frames, + * etc). + * + * Disabling A-MSDU makes RAW mode stable with heavy traffic + * albeit a bit slower compared to regular operation. + */ + ar->htt.max_num_amsdu = 1; + } + /* Backwards compatibility for firmwares without * ATH10K_FW_IE_WMI_OP_VERSION. */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78e07051b897..35f40388b622 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -92,6 +92,7 @@ struct ath10k_skb_cb { u8 tid; u16 freq; bool is_offchan; + bool nohwcrypt; struct ath10k_htt_txbuf *txbuf; u32 txbuf_paddr; } __packed htt; @@ -152,6 +153,7 @@ struct ath10k_wmi { const struct wmi_ops *ops; u32 num_mem_chunks; + u32 rx_decap_mode; struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; }; @@ -341,6 +343,7 @@ struct ath10k_vif { } u; bool use_cts_prot; + bool nohwcrypt; int num_legacy_stations; int txpower; struct wmi_wmm_params_all_arg wmm_params; @@ -382,9 +385,6 @@ struct ath10k_debug { u32 reg_addr; u32 nf_cal_period; - u8 htt_max_amsdu; - u8 htt_max_ampdu; - struct ath10k_fw_crash_data *fw_crash_data; }; @@ -453,16 +453,21 @@ enum ath10k_fw_features { ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6, /* Don't trust error code from otp.bin */ - ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, + ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7, /* Some firmware revisions pad 4th hw address to 4 byte boundary making * it 8 bytes long in Native Wifi Rx decap. */ - ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, + ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8, /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, + /* Raw mode support. If supported, FW supports receiving and trasmitting + * frames in raw mode. + */ + ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -476,6 +481,15 @@ enum ath10k_dev_flags { * waiters should immediately cancel instead of waiting for a time out. */ ATH10K_FLAG_CRASH_FLUSH, + + /* Use Raw mode instead of native WiFi Tx/Rx encap mode. + * Raw mode supports both hardware and software crypto. Native WiFi only + * supports hardware crypto. + */ + ATH10K_FLAG_RAW_MODE, + + /* Disable HW crypto engine */ + ATH10K_FLAG_HW_CRYPTO_DISABLED, }; enum ath10k_cal_mode { @@ -484,6 +498,13 @@ enum ath10k_cal_mode { ATH10K_CAL_MODE_DT, }; +enum ath10k_crypt_mode { + /* Only use hardware crypto engine */ + ATH10K_CRYPT_MODE_HW, + /* Only use software crypto engine */ + ATH10K_CRYPT_MODE_SW, +}; + static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) { switch (mode) { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index edf6047997a7..1a33bf04b7b7 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -128,7 +128,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d features %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -144,6 +144,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations, + test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), + !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags), fw_features); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), @@ -1363,12 +1365,8 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, mutex_lock(&ar->conf_mutex); - if (ar->debug.htt_max_amsdu) - amsdu = ar->debug.htt_max_amsdu; - - if (ar->debug.htt_max_ampdu) - ampdu = ar->debug.htt_max_ampdu; - + amsdu = ar->htt.max_num_amsdu; + ampdu = ar->htt.max_num_ampdu; mutex_unlock(&ar->conf_mutex); len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); @@ -1402,8 +1400,8 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, goto out; res = count; - ar->debug.htt_max_amsdu = amsdu; - ar->debug.htt_max_ampdu = ampdu; + ar->htt.max_num_amsdu = amsdu; + ar->htt.max_num_ampdu = ampdu; out: mutex_unlock(&ar->conf_mutex); @@ -1905,9 +1903,6 @@ void ath10k_debug_stop(struct ath10k *ar) if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); - ar->debug.htt_max_amsdu = 0; - ar->debug.htt_max_ampdu = 0; - ath10k_wmi_pdev_pktlog_disable(ar); } diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 4474c3e839db..3e6ba63dfdff 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -246,12 +246,31 @@ int ath10k_htt_setup(struct ath10k_htt *htt) } status = ath10k_htt_verify_version(htt); - if (status) + if (status) { + ath10k_warn(ar, "failed to verify htt version: %d\n", + status); return status; + } status = ath10k_htt_send_frag_desc_bank_cfg(htt); if (status) return status; - return ath10k_htt_send_rx_ring_cfg_ll(htt); + status = ath10k_htt_send_rx_ring_cfg_ll(htt); + if (status) { + ath10k_warn(ar, "failed to setup rx ring: %d\n", + status); + return status; + } + + status = ath10k_htt_h2t_aggr_cfg_msg(htt, + htt->max_num_ampdu, + htt->max_num_amsdu); + if (status) { + ath10k_warn(ar, "failed to setup amsdu/ampdu limit: %d\n", + status); + return status; + } + + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7583a126e879..573187512895 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1396,6 +1396,8 @@ struct ath10k_htt { u8 target_version_minor; struct completion target_version_received; enum ath10k_fw_htt_op_version op_version; + u8 max_num_amsdu; + u8 max_num_ampdu; const enum htt_t2h_msg_type *t2h_msg_types; u32 t2h_msg_types_max; @@ -1558,6 +1560,12 @@ struct htt_rx_desc { #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) +/* These values are default in most firmware revisions and apparently are a + * sweet spot performance wise. + */ +#define ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT 3 +#define ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT 64 + int ath10k_htt_connect(struct ath10k_htt *htt); int ath10k_htt_init(struct ath10k *ar); int ath10k_htt_setup(struct ath10k_htt *htt); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 5e54c393767e..1b7a04366256 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1017,9 +1017,8 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, skb_trim(msdu, msdu->len - FCS_LEN); /* In most cases this will be true for sniffed frames. It makes sense - * to deliver them as-is without stripping the crypto param. This would - * also make sense for software based decryption (which is not - * implemented in ath10k). + * to deliver them as-is without stripping the crypto param. This is + * necessary for software based decryption. * * If there's no error then the frame is decrypted. At least that is * the case for frames that come in via fragmented rx indication. @@ -2066,6 +2065,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_CHAN_CHANGE: break; + case HTT_T2H_MSG_TYPE_AGGR_CONF: + break; case HTT_T2H_MSG_TYPE_EN_STATS: case HTT_T2H_MSG_TYPE_TX_FETCH_IND: case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 2c0627b7141b..81fd81f4df01 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -523,8 +523,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && - ieee80211_has_protected(hdr->frame_control)) + ieee80211_has_protected(hdr->frame_control)) { skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + } else if (!skb_cb->htt.nohwcrypt && + skb_cb->txmode == ATH10K_HW_TXRX_RAW) { + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + } skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); @@ -595,12 +599,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) prefetch_len); skb_cb->htt.txbuf->htc_hdr.flags = 0; + if (skb_cb->htt.nohwcrypt) + flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; + if (!skb_cb->is_protected) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); - if (msdu->ip_summed == CHECKSUM_PARTIAL) { + if (msdu->ip_summed == CHECKSUM_PARTIAL && + !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; if (ar->hw_params.continuous_frag_desc) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 917228517546..7bfb9e276d17 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -217,14 +217,16 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) /* Known pecularities: - * - current FW doesn't support raw rx mode (last tested v599) - * - current FW dumps upon raw tx mode (last tested v599) * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap * - raw have FCS, nwifi doesn't * - ethernet frames have 802.11 header decapped and parts (base hdr, cipher * param, llc/snap) are aligned to 4byte boundaries each */ enum ath10k_hw_txrx_mode { ATH10K_HW_TXRX_RAW = 0, + + /* Native Wifi decap mode is used to align IP frames to 4-byte + * boundaries and avoid a very expensive re-alignment in mac80211. + */ ATH10K_HW_TXRX_NATIVE_WIFI = 1, ATH10K_HW_TXRX_ETHERNET = 2, @@ -286,10 +288,6 @@ enum ath10k_hw_rate_cck { #define TARGET_RX_TIMEOUT_LO_PRI 100 #define TARGET_RX_TIMEOUT_HI_PRI 40 -/* Native Wifi decap mode is used to align IP frames to 4-byte boundaries and - * avoid a very expensive re-alignment in mac80211. */ -#define TARGET_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI - #define TARGET_SCAN_MAX_PENDING_REQS 4 #define TARGET_BMISS_OFFLOAD_MAX_VDEV 3 #define TARGET_ROAM_OFFLOAD_MAX_VDEV 3 @@ -324,7 +322,6 @@ enum ath10k_hw_rate_cck { #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 #define TARGET_10X_RX_TIMEOUT_HI_PRI 40 -#define TARGET_10X_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI #define TARGET_10X_SCAN_MAX_PENDING_REQS 4 #define TARGET_10X_BMISS_OFFLOAD_MAX_VDEV 2 #define TARGET_10X_ROAM_OFFLOAD_MAX_VDEV 2 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 49a54a1f07a8..acd222f3b899 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -197,6 +197,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif, return -EOPNOTSUPP; } + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + if (cmd == DISABLE_KEY) { arg.key_cipher = WMI_CIPHER_NONE; arg.key_data = NULL; @@ -218,6 +222,9 @@ static int ath10k_install_key(struct ath10k_vif *arvif, reinit_completion(&ar->install_key_done); + if (arvif->nohwcrypt) + return 1; + ret = ath10k_send_key(arvif, key, cmd, macaddr, flags); if (ret) return ret; @@ -256,7 +263,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, addr, flags); - if (ret) + if (ret < 0) return ret; flags = 0; @@ -264,7 +271,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, addr, flags); - if (ret) + if (ret < 0) return ret; spin_lock_bh(&ar->data_lock); @@ -322,10 +329,10 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, peer->keys[i], DISABLE_KEY, addr, flags); - if (ret && first_errno == 0) + if (ret < 0 && first_errno == 0) first_errno = ret; - if (ret) + if (ret < 0) ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", i, ret); @@ -398,7 +405,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, break; /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags); - if (ret && first_errno == 0) + if (ret < 0 && first_errno == 0) first_errno = ret; if (ret) @@ -3149,13 +3156,30 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif, * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for * NativeWifi txmode - it selects AP key instead of peer key. It seems * to work with Ethernet txmode so use it. + * + * FIXME: Check if raw mode works with TDLS. */ if (ieee80211_is_data_present(fc) && sta && sta->tdls) return ATH10K_HW_TXRX_ETHERNET; + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + return ATH10K_HW_TXRX_RAW; + return ATH10K_HW_TXRX_NATIVE_WIFI; } +static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif, + struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_INJECTED; + if ((info->flags & mask) == mask) + return false; + if (vif) + return !ath10k_vif_to_arvif(vif)->nohwcrypt; + return true; +} + /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS * Control in the header. */ @@ -3600,6 +3624,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, ATH10K_SKB_CB(skb)->htt.is_offchan = false; ATH10K_SKB_CB(skb)->htt.freq = 0; ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); + ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb); ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif); ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb); ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc); @@ -3615,12 +3640,11 @@ static void ath10k_tx(struct ieee80211_hw *hw, ath10k_tx_h_8023(skb); break; case ATH10K_HW_TXRX_RAW: - /* FIXME: Packet injection isn't implemented. It should be - * doable with firmware 10.2 on qca988x. - */ - WARN_ON_ONCE(1); - ieee80211_free_txskb(hw, skb); - return; + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + WARN_ON_ONCE(1); + ieee80211_free_txskb(hw, skb); + return; + } } if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { @@ -4139,6 +4163,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err; } } + if (test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)) + arvif->nohwcrypt = true; + + if (arvif->nohwcrypt && + !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + ath10k_warn(ar, "cryptmode module param needed for sw crypto\n"); + goto err; + } ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n", arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, @@ -4728,6 +4760,9 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) return 1; + if (arvif->nohwcrypt) + return 1; + if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; @@ -4797,6 +4832,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { + WARN_ON(ret > 0); ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); goto exit; @@ -4812,13 +4848,16 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2); if (ret) { + WARN_ON(ret > 0); ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); ret2 = ath10k_install_key(arvif, key, DISABLE_KEY, peer_addr, flags); - if (ret2) + if (ret2) { + WARN_ON(ret2 > 0); ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret2); + } goto exit; } } @@ -6892,7 +6931,6 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); ieee80211_hw_set(ar->hw, AP_LINK_PS); ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); - ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); @@ -6900,6 +6938,9 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); + ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; @@ -7003,7 +7044,8 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } - ar->hw->netdev_features = NETIF_F_HW_CSUM; + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + ar->hw->netdev_features = NETIF_F_HW_CSUM; if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { /* Init ath dfs pattern detector */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 4189d4a90ce0..34fbc8fddb72 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1373,7 +1373,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64); cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64); cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); - cfg->rx_decap_mode = __cpu_to_le32(1); + cfg->rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); cfg->scan_max_pending_reqs = __cpu_to_le32(4); cfg->bmiss_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); cfg->roam_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1435614b0a55..3d46813b9beb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4688,8 +4688,7 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_RX_DECAP_MODE); - + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_SCAN_MAX_PENDING_REQS); @@ -4757,8 +4756,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); - + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); @@ -4823,7 +4821,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); -- cgit v1.2.3-70-g09d2 From c8ecfc1c33979054fb631d2066745d03ce322b6f Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 29 Jul 2015 11:40:38 +0300 Subject: ath10k: fix memory alloc failure in qca99x0 during wmi svc rdy event Host memory required for firmware is allocated while handling wmi service ready event. Right now, wmi service ready is handled in tasklet context and it calls dma_alloc_coherent() with atomic flag (GFP_ATOMIC) to allocate memory in host needed for firmware. The problem is, dma_alloc_coherent() with GFP_ATOMIC fails in the platform (at least in AP platform) where it has less atomic pool memory (< 2mb). QCA99X0 requires around 2 MB of host memory for one card, having additional QCA99X0 card in the same platform will require similarly amount of memory. So, it's not guaranteed that all the platform will have enough atomic memory pool. Fix this issue, by handling wmi service ready event in workqueue context and calling dma_alloc_coherent() with GFP_KERNEL. mac80211 work queue will not be ready at the time of handling wmi service ready. So, it can't be used to handle wmi service ready. Also, register work gets scheduled during insmod in existing ath10k_wq and waits for wmi service ready to completed. Both workqueue can't be used for this purpose. New auxiliary workqueue is added to handle wmi service ready. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 11 +++++++++- drivers/net/wireless/ath/ath10k/core.h | 5 +++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 34 +++++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 29d2541d87dd..25510679fd2e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1649,6 +1649,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, if (!ar->workqueue) goto err_free_mac; + ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq"); + if (!ar->workqueue_aux) + goto err_free_wq; + mutex_init(&ar->conf_mutex); spin_lock_init(&ar->data_lock); @@ -1669,10 +1673,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ret = ath10k_debug_create(ar); if (ret) - goto err_free_wq; + goto err_free_aux_wq; return ar; +err_free_aux_wq: + destroy_workqueue(ar->workqueue_aux); err_free_wq: destroy_workqueue(ar->workqueue); @@ -1688,6 +1694,9 @@ void ath10k_core_destroy(struct ath10k *ar) flush_workqueue(ar->workqueue); destroy_workqueue(ar->workqueue); + flush_workqueue(ar->workqueue_aux); + destroy_workqueue(ar->workqueue_aux); + ath10k_debug_destroy(ar); ath10k_mac_destroy(ar); } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 35f40388b622..6a387bac27b0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -694,6 +694,8 @@ struct ath10k { struct completion vdev_setup_done; struct workqueue_struct *workqueue; + /* Auxiliary workqueue */ + struct workqueue_struct *workqueue_aux; /* prevents concurrent FW reconfiguration */ struct mutex conf_mutex; @@ -716,6 +718,9 @@ struct ath10k { int num_active_peers; int num_tids; + struct work_struct svc_rdy_work; + struct sk_buff *svc_rdy_skb; + struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; struct completion offchan_tx_completed; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 34fbc8fddb72..567b79720b69 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -519,7 +519,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_TLV_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_TLV_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3d46813b9beb..e6d6b420ecea 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3789,7 +3789,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, - GFP_ATOMIC); + GFP_KERNEL); if (!ar->wmi.mem_chunks[idx].vaddr) { ath10k_warn(ar, "failed to allocate memory chunk\n"); return -ENOMEM; @@ -3878,12 +3878,19 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_event_service_ready_work(struct work_struct *work) { + struct ath10k *ar = container_of(work, struct ath10k, svc_rdy_work); + struct sk_buff *skb = ar->svc_rdy_skb; struct wmi_svc_rdy_ev_arg arg = {}; u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; int ret; + if (!skb) { + ath10k_warn(ar, "invalid service ready event skb\n"); + return; + } + ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse service ready: %d\n", ret); @@ -4003,9 +4010,17 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(arg.eeprom_rd), __le32_to_cpu(arg.num_mem_reqs)); + dev_kfree_skb(skb); + ar->svc_rdy_skb = NULL; complete(&ar->wmi.service_ready); } +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +{ + ar->svc_rdy_skb = skb; + queue_work(ar->workqueue_aux, &ar->svc_rdy_work); +} + static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_rdy_ev_arg *arg) { @@ -4177,7 +4192,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4298,7 +4313,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10X_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10X_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4409,7 +4424,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10_2_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10_2_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4461,7 +4476,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10_4_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10_4_SCAN_EVENTID: ath10k_wmi_event_scan(ar, skb); break; @@ -6512,6 +6527,8 @@ int ath10k_wmi_attach(struct ath10k *ar) init_completion(&ar->wmi.service_ready); init_completion(&ar->wmi.unified_ready); + INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work); + return 0; } @@ -6519,6 +6536,11 @@ void ath10k_wmi_detach(struct ath10k *ar) { int i; + cancel_work_sync(&ar->svc_rdy_work); + + if (ar->svc_rdy_skb) + dev_kfree_skb(ar->svc_rdy_skb); + /* free the host memory chunks requested by firmware */ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { dma_free_coherent(ar->dev, -- cgit v1.2.3-70-g09d2 From 1201844e6ddc4e13dfc1a7ffbba0cfd180944679 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 29 Jul 2015 11:40:38 +0300 Subject: ath10k: increase max client to 512 in qca99x0 When max client was set to 512 in qca99x0, there was host memory alloc failure during wmi service ready event handling. This issue got resolved now, increasing max client limit from 256 to 512. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 7bfb9e276d17..d9de4a738470 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -360,10 +360,7 @@ enum ath10k_hw_rate_cck { (TARGET_10_4_NUM_VDEVS)) #define TARGET_10_4_ACTIVE_PEERS 0 -/* TODO: increase qcache max client limit to 512 after - * testing with 512 client. - */ -#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 256 +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512 #define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 -- cgit v1.2.3-70-g09d2 From 8a055a8adc875768223be2dfc33de5dc70212756 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2015 11:40:39 +0300 Subject: ath10k: add QCA99X0 to supported device list Add vendor/device id of QCA99X0 V2.0 to pci id table and QCA99X0_HW_2_0_CHIP_ID_REV to ath10k_pci_supp_chips[] for QCA99X0 to get detected by the driver. kvalo: now QCA99X0 family of chipsets is supported by ath10k. Tested client, AP and monitor mode with QCA9990. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a69bfa41c68b..f00b251ec9ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -64,6 +64,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ + { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ {0} }; @@ -78,6 +79,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, }; static void ath10k_pci_buffer_cleanup(struct ath10k *ar); -- cgit v1.2.3-70-g09d2 From ae7d3821a769a4ac64d4c244b5cd8b134768d452 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 29 Jul 2015 11:58:50 +0300 Subject: ath10k: initialize msdu ext. descriptor before use Initial QCA99X0 support has a known issue with TCP Tx throughput. All other path such as UDP Tx/Rx and TCP Rx meet their expectation (> 900Mbps), but TCP Tx marked as low as 5Mbps when single pair is used on iperf. The root cause is turned out because TSO flag is not initialized properly so that firmware configures TSO in wrong way. TSO flags in msdu extension descriptor is required to be reset to indicate firmware there is no TSO is enabled, otherwise it could act as TSO is enabled which causes huge throughput drop. In fact, it's enough by resetting TSO flags only to prevent the unexpected behavior, but initializing whole msdu ext. descriptor will help to clear uncertainty of firmware could bring on as it constantly updated. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 81fd81f4df01..704bb5e07193 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -543,6 +543,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) /* pass through */ case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { + memset(&htt->frag_desc.vaddr[msdu_id], 0, + sizeof(struct htt_msdu_ext_desc)); frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; ext_desc = &htt->frag_desc.vaddr[msdu_id]; @@ -550,8 +552,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); - frags[1].tword_addr.paddr_lo = 0; - frags[1].tword_addr.paddr_hi = 0; frags_paddr = htt->frag_desc.paddr + (sizeof(struct htt_msdu_ext_desc) * msdu_id); -- cgit v1.2.3-70-g09d2 From aecdc63d87891c75e60906973c7b7c9cd58403d6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 Jul 2015 23:06:41 +0300 Subject: iwlwifi: pcie: fix stuck queue detection for sleeping clients The stuck queue detection mechanism allows to detect queues that are stuck. For sleeping clients, a queue may rightfully be stuck: if a poor client implementation stays asleep for more than 10s, then we don't want to trigger recovery flows because of that client. In order to cope with this, I added a mechanism that monitors the state of the client: when a client goes to sleep, the timer of his queues is frozen. When he wakes up, the timer is reset to the right value so that if a client was awake for more than 10s and the queues are stuck, only then, the recovery flow will kick in. This is valid only on non-shared queues: A-MPDU queues. There was a bug in case we Tx to a sleeping client that has an empty A-MPDU queue: the timer was armed to now + 10s. This is bad, but pretty harmless. The problem is that when the client wakes up, the timer is modified to be now + remainder. But remainder is 0 since the queue was empty when that client went to sleep... Fix this by checking the state of the client before playing with the timer when we add a packet to an empty queue. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2b86c2135de3..607acb53c847 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1875,8 +1875,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr) { - if (txq->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); + if (txq->wd_timeout) { + /* + * If the TXQ is active, then set the timer, if not, + * set the timer in remainder so that the timer will + * be armed with the right value when the station will + * wake up. + */ + if (!txq->frozen) + mod_timer(&txq->stuck_timer, + jiffies + txq->wd_timeout); + else + txq->frozen_expiry_remainder = txq->wd_timeout; + } IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); iwl_trans_pcie_ref(trans); } -- cgit v1.2.3-70-g09d2 From 5d5cd85ff441534a52f23f821d0a7c644d3b6cce Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 28 Jul 2015 07:51:01 +0200 Subject: rsi: Fix failure to load firmware after memory leak fix and fix the leak Fixes commit eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()") which stopped the driver from functioning. Firmware data has been allocated using vmalloc(), resulting in memory that cannot be used for DMA. Hence the firmware was first copied to a buffer allocated with kmalloc() in the original code. This patch reverts the commit and only calls "kfree()" to release the buffer after sending the data. This fixes the memory leak without breaking the driver. Add a comment to the kmemdup() calls to explain why this is done, and abort if memory allocation fails. Tested on a Topic Miami-Florida board which contains the rsi SDIO chip. Also added the same kfree() call to the USB glue driver. This was not tested on actual hardware though, as I only have the SDIO version. Fixes: eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()") Signed-off-by: Mike Looijmans Cc: stable@vger.kernel.org Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 8 +++++++- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index b6cc9ff47fc2..1c6788aecc62 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 len; u32 num_blocks; + const u8 *fw; const struct firmware *fw_entry = NULL; u32 block_size = dev->tx_blk_size; int status = 0; @@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } + /* Copy firmware into DMA-accessible memory */ + fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!fw) + return -ENOMEM; len = fw_entry->size; if (len % 4) @@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks); + status = rsi_copy_to_card(common, fw, len, num_blocks); + kfree(fw); release_firmware(fw_entry); return status; } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 1106ce76707e..30c2cf7fa93b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } + /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!fw) + return -ENOMEM; len = fw_entry->size; if (len % 4) @@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); status = rsi_copy_to_card(common, fw, len, num_blocks); + kfree(fw); release_firmware(fw_entry); return status; } -- cgit v1.2.3-70-g09d2 From 098697dbad9070249eb07a0241c4001aa367bb89 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 29 Jul 2015 23:36:30 +0200 Subject: b43: fix extpa_gain check for 2GHz On the 2GHz and and on the 5GHZ band only the extpa_gain setting from the 5GHz band was checked. this patch makes it check the property from the correct band. Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/tables_nphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 25d1cbd34306..b2f0d245bcf3 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) switch (phy->rev) { case 6: case 5: - if (sprom->fem.ghz5.extpa_gain == 3) + if (sprom->fem.ghz2.extpa_gain == 3) return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g; /* fall through */ case 4: -- cgit v1.2.3-70-g09d2 From 7c62940165e9ae4004ce4e6b5117330bab94df68 Mon Sep 17 00:00:00 2001 From: Luis Felipe Dominguez Vega Date: Wed, 29 Jul 2015 21:11:20 -0500 Subject: rtlwifi: Fix NULL dereference when PCI driver used as an AP In commit 33511b157bbcebaef853cc1811992b664a2e5862 ("rtlwifi: add support to send beacon frame"), the mechanism for sending beacons was established. That patch works correctly for rtl8192cu, but there is a possibility of getting the following warnings in the PCI drivers: WARNING: CPU: 1 PID: 2439 at net/mac80211/driver-ops.h:12 ieee80211_bss_info_change_notify+0x179/0x1d0 [mac80211]() wlp5s0: Failed check-sdata-in-driver check, flags: 0x0 The warning is followed by a NULL pointer dereference as follows: BUG: unable to handle kernel NULL pointer dereference at 0000000000000006 IP: [] rtl_get_tcb_desc+0x5e/0x760 [rtlwifi] This problem was reported at http://thread.gmane.org/gmane.linux.kernel.wireless.general/138645, but no solution was found at that time. The problem was also reported at https://bugzilla.kernel.org/show_bug.cgi?id=9744 and this solution was developed and tested there. The USB driver works with a NULL final argument in the adapter_tx() callback; however, the PCI drivers need a struct rtl_tcb_desc in that position. Fixes: 33511b157bbc ("rtlwifi: add support to send beacon frame.") Signed-off-by: Luis Felipe Dominguez Vega Signed-off-by: Larry Finger Cc: Stable [3.19+] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 3b3a88b53b11..585d0883c7e5 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct rtl_tcb_desc tcb_desc; - if (skb) - rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL); + if (skb) { + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); + } } static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, -- cgit v1.2.3-70-g09d2 From 360d9bb5ee2db4d409448667de606c05b3914d53 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 31 Jul 2015 10:17:35 +0300 Subject: Revert "ath9k: export HW random number generator" This reverts commit 6301566e0b2dafa7d6779598621bca867962a0a2. Oleksij Rempel noticed that the randomness doesn't look to be good enough and Stephan Mueller commented: "I would say that the discussed RNG does not seem fit for hooking it up with the hwrandom framework." http://lkml.kernel.org/g/3945775.m5HblJPgiO@tauon.atsec.com So let's the revert the patch until we are sure that we can trust this random generator. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Kconfig | 7 --- drivers/net/wireless/ath/ath9k/Makefile | 1 - drivers/net/wireless/ath/ath9k/ath9k.h | 23 ---------- drivers/net/wireless/ath/ath9k/main.c | 4 -- drivers/net/wireless/ath/ath9k/rng.c | 75 --------------------------------- 5 files changed, 110 deletions(-) delete mode 100644 drivers/net/wireless/ath/ath9k/rng.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index bde62ec98bc7..fee0cadb0f5e 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,10 +176,3 @@ 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--- - Provides a hardware random number generator to the kernel. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 76f9dc37500b..ecda613c2d54 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,7 +15,6 @@ 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 45596e5ae4db..a7a81b3969ce 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,7 +23,6 @@ #include #include #include -#include #include "common.h" #include "debug.h" @@ -1042,12 +1041,6 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif - -#ifdef CONFIG_ATH9K_HWRNG - struct hwrng rng; - bool rng_initialized; - u32 rng_last; -#endif }; /********/ @@ -1070,22 +1063,6 @@ static inline int ath9k_tx99_send(struct ath_softc *sc, } #endif /* CONFIG_ATH9K_TX99 */ -/***************************/ -/* Random Number Generator */ -/***************************/ -#ifdef CONFIG_ATH9K_HWRNG -void ath9k_rng_register(struct ath_softc *sc); -void ath9k_rng_unregister(struct ath_softc *sc); -#else -static inline void ath9k_rng_register(struct ath_softc *sc) -{ -} - -static inline void ath9k_rng_unregister(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/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5916ab2f4a3d..cfd45cb8ccfc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -739,8 +739,6 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_restore(sc); - ath9k_rng_register(sc); - return 0; } @@ -830,8 +828,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); - ath9k_rng_unregister(sc); - mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c deleted file mode 100644 index d8fa7a535ab8..000000000000 --- a/drivers/net/wireless/ath/ath9k/rng.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 "ath9k.h" -#include "hw.h" -#include "ar9003_phy.h" - -static int ath9k_rng_data_read(struct hwrng *rng, u32 *data) -{ - u32 v1, v2; - struct ath_softc *sc = (struct ath_softc *)rng->priv; - struct ath_hw *ah = sc->sc_ah; - - ath9k_ps_wakeup(sc); - - REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 5); - 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); - - v1 = REG_READ(ah, AR_PHY_TST_ADC); - v2 = REG_READ(ah, AR_PHY_TST_ADC); - - ath9k_ps_restore(sc); - - /* wait for data ready */ - if (v1 && v2 && sc->rng_last != v1 && v1 != v2) { - *data = (v1 & 0xffff) | (v2 << 16); - sc->rng_last = v2; - - return sizeof(u32); - } - - sc->rng_last = v2; - - return 0; -} - -void ath9k_rng_register(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (WARN_ON(sc->rng_initialized)) - return; - - if (!AR_SREV_9300_20_OR_LATER(ah)) - return; - - sc->rng.name = "ath9k"; - sc->rng.data_read = ath9k_rng_data_read; - sc->rng.priv = (unsigned long)sc; - - if (!hwrng_register(&sc->rng)) - sc->rng_initialized = true; -} - -void ath9k_rng_unregister(struct ath_softc *sc) -{ - if (sc->rng_initialized) { - hwrng_unregister(&sc->rng); - sc->rng_initialized = false; - } -} -- cgit v1.2.3-70-g09d2 From 741e3b9902d11585e18bfc7f8d47e913616bb070 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 2 Aug 2015 13:24:13 -0500 Subject: rtlwifi: rtl8723be: Add module parameter for MSI interrupts The driver code allows for the disabling of MSI interrupts; however the module_parm line was missed and the option fails to show with modinfo. Signed-off-by: Larry Finger Cc: Stable [3.15+] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 1017f02d7bf7..7bf88d9dcdc3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444); module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444); module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); -- cgit v1.2.3-70-g09d2 From 94ce9e5e73c71b26a19b83844f9840859f3b035b Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Sun, 14 Jun 2015 11:17:07 +0300 Subject: iwlwifi: pcie: Set scheduler to work on auto mode During NIC initialization shared HW is reset and this disables the scheduler. Some HW platforms do not activate the scheduler after it. Consequently all HCMD sent by the driver stay at the queues which cause to queue stuck. Set the scheduler to work on auto active mode so it would be activated upon change over one of the queues' write pointer. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 5af1c776d2d4..a8469041af09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -253,6 +253,7 @@ #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) #define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) +#define SCD_GP_CTRL_AUTO_ACTIVE_MODE BIT(18) /* Context Data */ #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2b86c2135de3..d711f0b8b62f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -915,6 +915,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) } } + iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); if (trans->cfg->base_params->num_of_queues > 20) iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_ENABLE_31_QUEUES); -- cgit v1.2.3-70-g09d2 From 2dc2a15ebd12c44074d0ea2eef3e97956df4bb86 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 17:09:18 +0200 Subject: iwlwifi: mvm: LRU-assign key offsets The current key offset assignment algorithm always uses the lowest unused key offset, which will potentially lead to issues when the firmware will change to take the key material for TX from the key table rather than from the TX command. In order to avoid those issues (and avoid forgetting about them) change the key offset allocation algorithm now to avoid reusing key offsets quickly. The new algorithm always picks as the next offset the least recently freed offset, i.e. the offset that has been unused for the longest amount of time. This is implemented by having a generation counter for each key offset that is incremented every time a key is deleted, except for the one that's deleted, which is reset to zero. Thus the highest counter is the key that's been unused longest. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/sta.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825..40d1bd7a200f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -686,6 +686,7 @@ struct iwl_mvm { * can hold 16 keys at most. Reflect this fact. */ unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; + u8 fw_key_deleted[STA_KEY_MAX_NUM]; /* references taken by the driver and spinlock protecting them */ spinlock_t refs_lock; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d68dc697a4a0..806b2c29b4dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1148,18 +1148,31 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) { - int i; + int i, max = -1, max_offs = -1; lockdep_assert_held(&mvm->mutex); - i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM); + /* Pick the unused key offset with the highest 'deleted' + * counter. Every time a key is deleted, all the counters + * are incremented and the one that was just deleted is + * reset to zero. Thus, the highest counter is the one + * that was deleted longest ago. Pick that one. + */ + for (i = 0; i < STA_KEY_MAX_NUM; i++) { + if (test_bit(i, mvm->fw_key_table)) + continue; + if (mvm->fw_key_deleted[i] > max) { + max = mvm->fw_key_deleted[i]; + max_offs = i; + } + } - if (i == STA_KEY_MAX_NUM) + if (max_offs < 0) return STA_KEY_IDX_INVALID; - __set_bit(i, mvm->fw_key_table); + __set_bit(max_offs, mvm->fw_key_table); - return i; + return max_offs; } static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, @@ -1478,7 +1491,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); u8 sta_id; - int ret; + int ret, i; lockdep_assert_held(&mvm->mutex); @@ -1497,6 +1510,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, return -ENOENT; } + /* track which key was deleted last */ + for (i = 0; i < STA_KEY_MAX_NUM; i++) { + if (mvm->fw_key_deleted[i] < U8_MAX) + mvm->fw_key_deleted[i]++; + } + mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; + if (sta_id == IWL_MVM_STATION_COUNT) { IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); return 0; -- cgit v1.2.3-70-g09d2 From 4492bb6b10b1fbbc3fd4e8ea1b1bef51a1b2b31a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 20:56:45 +0200 Subject: iwlwifi: dvm: move ADD_STA response handling to sync command This driver currently has some very confusing ADD_STA response handling that runs asynchronously in the background for all of the commands, but is only really necessary for synchronous ones (the really asynchronous ones can only be done for already existing stations), and for the sync ones it actually waits for the RX handler to return a status code. Rework this to keep the debug printing in the handler, but do the code that's supposed to have an effect only for sync commands in the command sending function. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 6ec86adbe4a1..346077fad14a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -66,12 +66,11 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; u8 sta_id = addsta->sta.sta_id; - int ret = -EIO; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", pkt->hdr.flags); - return ret; + return 0; } IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", @@ -82,7 +81,6 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, switch (add_sta_resp->status) { case ADD_STA_SUCCESS_MSK: IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); - ret = iwl_sta_ucode_activate(priv, sta_id); break; case ADD_STA_NO_ROOM_IN_TABLE: IWL_ERR(priv, "Adding station %d failed, no room in table.\n", @@ -121,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, addsta->sta.addr); spin_unlock_bh(&priv->sta_lock); - return ret; + return 0; } int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, @@ -146,6 +144,8 @@ int iwl_send_add_sta(struct iwl_priv *priv, .len = { sizeof(*sta), }, }; u8 sta_id __maybe_unused = sta->sta.sta_id; + struct iwl_rx_packet *pkt; + struct iwl_add_sta_resp *add_sta_resp; IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); @@ -159,16 +159,23 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - /*else the command was successfully sent in SYNC mode, need to free - * the reply page */ - iwl_free_resp(&cmd); + pkt = cmd.resp_pkt; + add_sta_resp = (void *)pkt->data; - if (cmd.handler_status) - IWL_ERR(priv, "%s - error in the CMD response %d\n", __func__, - cmd.handler_status); + /* debug messages are printed in the handler */ + if (!(pkt->hdr.flags & IWL_CMD_FAILED_MSK) && + add_sta_resp->status == ADD_STA_SUCCESS_MSK) { + spin_lock_bh(&priv->sta_lock); + ret = iwl_sta_ucode_activate(priv, sta_id); + spin_unlock_bh(&priv->sta_lock); + } else { + ret = -EIO; + } + + iwl_free_resp(&cmd); - return cmd.handler_status; + return ret; } bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From 121b80091916a3fc401f515c8c6cbdfe9ece3576 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:01:44 +0200 Subject: iwlwifi: dvm: remove ADD_STA prints relying on station ID This makes the logging a little less useful, but as they're mostly synchronous commands it won't matter much. It gets rid of the dependency on the input command, which this is the only user of. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 346077fad14a..6e1e23eff0db 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -61,11 +61,9 @@ static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) } static int iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_addsta_cmd *addsta, struct iwl_rx_packet *pkt) { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; - u8 sta_id = addsta->sta.sta_id; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", @@ -73,8 +71,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, return 0; } - IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", - sta_id); + IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); spin_lock_bh(&priv->sta_lock); @@ -83,16 +80,14 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); break; case ADD_STA_NO_ROOM_IN_TABLE: - IWL_ERR(priv, "Adding station %d failed, no room in table.\n", - sta_id); + IWL_ERR(priv, "Adding station failed, no room in table.\n"); break; case ADD_STA_NO_BLOCK_ACK_RESOURCE: - IWL_ERR(priv, "Adding station %d failed, no block ack " - "resource.\n", sta_id); + IWL_ERR(priv, + "Adding station failed, no block ack resource.\n"); break; case ADD_STA_MODIFY_NON_EXIST_STA: - IWL_ERR(priv, "Attempting to modify non-existing station %d\n", - sta_id); + IWL_ERR(priv, "Attempting to modify non-existing station\n"); break; default: IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", @@ -100,23 +95,6 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, break; } - IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - sta_id, priv->stations[sta_id].sta.sta.addr); - - /* - * XXX: The MAC address in the command buffer is often changed from - * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC address - * read from the command buffer when the command returns. This - * issue has not yet been resolved and this debugging is left to - * observe the problem. - */ - IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - addsta->sta.addr); spin_unlock_bh(&priv->sta_lock); return 0; @@ -130,7 +108,7 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!cmd) return 0; - return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt); + return iwl_process_add_sta_resp(priv, pkt); } int iwl_send_add_sta(struct iwl_priv *priv, -- cgit v1.2.3-70-g09d2 From 73e686f399b3a11e4d26dc13b6f68380e31820dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:22:09 +0200 Subject: iwlwifi: dvm: remove command/return value from RX handlers After the previous patches, the command that's passed in nor the return value are used any more, so can be removed. While at it, make some functions static. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 14 ++--- drivers/net/wireless/iwlwifi/dvm/dev.h | 5 +- drivers/net/wireless/iwlwifi/dvm/lib.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/rx.c | 103 ++++++++++++-------------------- drivers/net/wireless/iwlwifi/dvm/scan.c | 25 +++----- drivers/net/wireless/iwlwifi/dvm/sta.c | 16 ++--- drivers/net/wireless/iwlwifi/dvm/tx.c | 18 ++---- 7 files changed, 65 insertions(+), 124 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index c160dad03037..f549dc3852a6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -216,11 +216,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb); +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); static inline u32 iwl_tx_status_to_mac80211(u32 status) { @@ -277,9 +275,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv); void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv); void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); @@ -332,8 +327,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_link_quality_cmd *lq, u8 flags, bool init); -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd..1f51757f4a93 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -678,9 +678,8 @@ struct iwl_priv { enum ieee80211_band band; u8 valid_contexts; - int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb); struct iwl_notif_wait_data notif_wait; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 1d2223df5cb0..ab45819c1fbb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -659,9 +659,8 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, return need_update; } -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data; @@ -669,7 +668,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { /* bt coex disabled */ - return 0; + return; } IWL_DEBUG_COEX(priv, "BT Coex notification:\n"); @@ -714,7 +713,6 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, /* FIXME: based on notification, adjust the prio_boost */ priv->bt_ci_compliance = coex->bt_ci_compliance; - return 0; } void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610..ca270a6234e7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -123,9 +123,8 @@ const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { * ******************************************************************************/ -static int iwlagn_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -136,11 +135,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv, err_resp->cmd_id, le16_to_cpu(err_resp->bad_cmd_seq_num), le32_to_cpu(err_resp->error_info)); - return 0; } -static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_csa_notification *csa = (void *)pkt->data; @@ -152,7 +149,7 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct iwl_rxon_cmd *rxon = (void *)&ctx->active; if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) - return 0; + return; if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { rxon->channel = csa->channel; @@ -165,13 +162,11 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, le16_to_cpu(csa->channel)); iwl_chswitch_done(priv, false); } - return 0; } -static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_spectrum_notification *report = (void *)pkt->data; @@ -179,17 +174,15 @@ static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, if (!report->state) { IWL_DEBUG_11H(priv, "Spectrum Measure Notification: Start\n"); - return 0; + return; } memcpy(&priv->measure_report, report, sizeof(*report)); priv->measurement_status |= MEASUREMENT_READY; - return 0; } -static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -197,24 +190,20 @@ static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif - return 0; } -static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 __maybe_unused len = iwl_rx_packet_len(pkt); IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); - return 0; } -static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwlagn_beacon_notif *beacon = (void *)pkt->data; @@ -232,8 +221,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, #endif priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - - return 0; } /** @@ -448,9 +435,8 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv, } #endif -static int iwlagn_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { unsigned long stamp = jiffies; const int reg_recalib_period = 60; @@ -505,7 +491,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, len, sizeof(struct iwl_bt_notif_statistics), sizeof(struct iwl_notif_statistics)); spin_unlock(&priv->statistics.lock); - return 0; + return; } change = common->temperature != priv->statistics.common.temperature || @@ -550,13 +536,10 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, priv->lib->temperature(priv); spin_unlock(&priv->statistics.lock); - - return 0; } -static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_notif_statistics *stats = (void *)pkt->data; @@ -572,15 +555,14 @@ static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } - iwlagn_rx_statistics(priv, rxb, cmd); - return 0; + + iwlagn_rx_statistics(priv, rxb); } /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -627,12 +609,10 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, test_bit(STATUS_RF_KILL_HW, &priv->status))) wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); - return 0; } -static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -649,14 +629,12 @@ static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, if (!test_bit(STATUS_SCANNING, &priv->status)) iwl_init_sensitivity(priv); } - return 0; } /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -664,7 +642,6 @@ static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, priv->ampdu_ref++; memcpy(&priv->last_phy_res, pkt->data, sizeof(struct iwl_rx_phy_res)); - return 0; } /* @@ -890,9 +867,8 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv, } /* Called for REPLY_RX_MPDU_CMD */ -static int iwlagn_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status = {}; @@ -906,7 +882,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, if (!priv->last_phy_res_valid) { IWL_ERR(priv, "MPDU frame without cached PHY data\n"); - return 0; + return; } phy_res = &priv->last_phy_res; amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; @@ -919,14 +895,14 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n", phy_res->cfg_phy_cnt); - return 0; + return; } if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); - return 0; + return; } /* This will be used in several places later */ @@ -998,12 +974,10 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, rxb, &rx_status); - return 0; } -static int iwlagn_rx_noa_notification(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_noa_notification(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_wipan_noa_data *new_data, *old_data; struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -1041,8 +1015,6 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv, if (old_data) kfree_rcu(old_data, rcu_head); - - return 0; } /** @@ -1053,8 +1025,7 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv, */ void iwl_setup_rx_handlers(struct iwl_priv *priv) { - int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); handlers = priv->rx_handlers; @@ -1107,7 +1078,6 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - int err = 0; /* * Do the notification wait before RX handlers so @@ -1121,12 +1091,13 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { priv->rx_handlers_stats[pkt->hdr.cmd]++; - err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); + priv->rx_handlers[pkt->hdr.cmd](priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", iwl_dvm_get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } - return err; + + return 0; } diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 43bef901e8f9..648159495bbc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -247,9 +247,8 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) } /* Service response to REPLY_SCAN_CMD (0x80) */ -static int iwl_rx_reply_scan(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -257,13 +256,11 @@ static int iwl_rx_reply_scan(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); #endif - return 0; } /* Service SCAN_START_NOTIFICATION (0x82) */ -static int iwl_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanstart_notification *notif = (void *)pkt->data; @@ -277,14 +274,11 @@ static int iwl_rx_scan_start_notif(struct iwl_priv *priv, le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); - - return 0; } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static int iwl_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -303,13 +297,11 @@ static int iwl_rx_scan_results_notif(struct iwl_priv *priv, le32_to_cpu(notif->statistics[0]), le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); #endif - return 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data; @@ -356,7 +348,6 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->bt_traffic_change_work); } - return 0; } void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 6e1e23eff0db..c18aa3e950d5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -60,15 +60,15 @@ static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) return 0; } -static int iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) +static void iwl_process_add_sta_resp(struct iwl_priv *priv, + struct iwl_rx_packet *pkt) { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", pkt->hdr.flags); - return 0; + return; } IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); @@ -96,19 +96,13 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, } spin_unlock_bh(&priv->sta_lock); - - return 0; } -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - if (!cmd) - return 0; - - return iwl_process_add_sta_resp(priv, pkt); + iwl_process_add_sta_resp(priv, pkt); } int iwl_send_add_sta(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 275df12a6045..bddd19769035 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1128,8 +1128,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv, } } -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1273,8 +1272,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, skb = __skb_dequeue(&skbs); ieee80211_tx_status(priv->hw, skb); } - - return 0; } /** @@ -1283,9 +1280,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, * Handles block-acknowledge notification from device, which reports success * of frames sent via aggregation. */ -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; @@ -1306,7 +1302,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, if (scd_flow >= priv->cfg->base_params->num_of_queues) { IWL_ERR(priv, "BUG_ON scd_flow is bigger than number of queues\n"); - return 0; + return; } sta_id = ba_resp->sta_id; @@ -1319,7 +1315,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, if (unlikely(ba_resp->bitmap)) IWL_ERR(priv, "Received BA when not expected\n"); spin_unlock_bh(&priv->sta_lock); - return 0; + return; } if (unlikely(scd_flow != agg->txq_id)) { @@ -1333,7 +1329,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", scd_flow, sta_id, tid, agg->txq_id); spin_unlock_bh(&priv->sta_lock); - return 0; + return; } __skb_queue_head_init(&reclaimed_skbs); @@ -1413,6 +1409,4 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, skb = __skb_dequeue(&reclaimed_skbs); ieee80211_tx_status(priv->hw, skb); } - - return 0; } -- cgit v1.2.3-70-g09d2 From 0416841d709e4d90913576cc43a397e450a745b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:22:09 +0200 Subject: iwlwifi: mvm: remove command/return value from RX handlers In the mvm driver, neither the old command nor the return value are used, so remove them. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 44 +++++----- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 31 +++---- drivers/net/wireless/iwlwifi/mvm/fw.c | 13 +-- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 13 +-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 107 ++++++++++--------------- drivers/net/wireless/iwlwifi/mvm/nvm.c | 11 +-- drivers/net/wireless/iwlwifi/mvm/ops.c | 22 ++--- drivers/net/wireless/iwlwifi/mvm/power.c | 7 +- drivers/net/wireless/iwlwifi/mvm/rx.c | 20 ++--- drivers/net/wireless/iwlwifi/mvm/scan.c | 35 +++----- drivers/net/wireless/iwlwifi/mvm/sta.c | 9 +-- drivers/net/wireless/iwlwifi/mvm/sta.h | 5 +- drivers/net/wireless/iwlwifi/mvm/tdls.c | 12 +-- drivers/net/wireless/iwlwifi/mvm/time-event.c | 7 +- drivers/net/wireless/iwlwifi/mvm/time-event.h | 5 +- drivers/net/wireless/iwlwifi/mvm/tt.c | 10 +-- drivers/net/wireless/iwlwifi/mvm/tx.c | 16 ++-- drivers/net/wireless/iwlwifi/mvm/utils.c | 4 +- 18 files changed, 139 insertions(+), 232 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index b4737e296c92..e290ac67d975 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -725,15 +725,17 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) } } -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; - if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) - return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_rx_bt_coex_notif_old(mvm, rxb); + return; + } IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); @@ -748,12 +750,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); iwl_mvm_bt_coex_notif_handle(mvm); - - /* - * This is an async handler for a notification, returning anything other - * than 0 doesn't make sense even if HCMD failed. - */ - return 0; } void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -947,9 +943,8 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) iwl_mvm_bt_coex_notif_handle(mvm); } -int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); @@ -957,20 +952,23 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, u8 __maybe_unused lower_bound, upper_bound; u8 lut; - if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) - return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb); + return; + } if (!iwl_mvm_bt_is_plcr_supported(mvm)) - return 0; + return; lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return 0; + return; if (ant_isolation == mvm->last_ant_isol) - return 0; + return; for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -989,7 +987,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, mvm->last_ant_isol = ant_isolation; if (mvm->last_corun_lut == lut) - return 0; + return; mvm->last_corun_lut = lut; @@ -1000,6 +998,8 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20, sizeof(cmd.corun_lut40)); - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, - sizeof(cmd), &cmd); + if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, + sizeof(cmd), &cmd)) + IWL_ERR(mvm, + "failed to send BT_COEX_UPDATE_CORUN_LUT command\n"); } diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 6ac6de2af977..61c07b05fcaa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -1058,9 +1058,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; @@ -1083,12 +1082,6 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old)); iwl_mvm_bt_coex_notif_handle(mvm); - - /* - * This is an async handler for a notification, returning anything other - * than 0 doesn't make sense even if HCMD failed. - */ - return 0; } static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, @@ -1250,14 +1243,12 @@ void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm) iwl_mvm_bt_coex_notif_handle(mvm); } -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); u8 __maybe_unused lower_bound, upper_bound; - int ret; u8 lut; struct iwl_bt_coex_cmd_old *bt_cmd; @@ -1268,16 +1259,16 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, }; if (!iwl_mvm_bt_is_plcr_supported(mvm)) - return 0; + return; lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return 0; + return; if (ant_isolation == mvm->last_ant_isol) - return 0; + return; for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -1296,13 +1287,13 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, mvm->last_ant_isol = ant_isolation; if (mvm->last_corun_lut == lut) - return 0; + return; mvm->last_corun_lut = lut; bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) - return 0; + return; cmd.data[0] = bt_cmd; bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); @@ -1317,8 +1308,8 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, sizeof(bt_cmd->bt4_corun_lut40)); - ret = iwl_mvm_send_cmd(mvm, &cmd); + if (iwl_mvm_send_cmd(mvm, &cmd)) + IWL_ERR(mvm, "failed to send BT_CONFIG command\n"); kfree(bt_cmd); - return ret; } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a482ce692f5f..a5dae09869fc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -814,9 +814,8 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) return ret; } -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -827,13 +826,10 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, (flags & SW_CARD_DISABLED) ? "Kill" : "On", (flags & CT_KILL_CARD_DISABLED) ? "Reached" : "Not reached"); - - return 0; } -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; @@ -844,5 +840,4 @@ int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, le32_to_cpu(mfuart_notif->external_ver), le32_to_cpu(mfuart_notif->status), le32_to_cpu(mfuart_notif->duration)); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 1812dd018af2..3424315dd876 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1312,9 +1312,8 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, } } -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; @@ -1365,8 +1364,6 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); } } - - return 0; } static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, @@ -1415,9 +1412,8 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); } -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_missed_beacons_notif *mb = (void *)pkt->data; @@ -1434,5 +1430,4 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_beacon_loss_iterator, mb); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 40d1bd7a200f..1397e3e0d669 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1012,9 +1012,8 @@ static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) /* Statistics */ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt); -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear); void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); @@ -1060,27 +1059,19 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, * FW notifications / CMD responses handlers * Convention: iwl_mvm_rx_ */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +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 iwl_rx_cmd_buffer *rxb); +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, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* MVM PHY */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, @@ -1107,12 +1098,10 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, @@ -1136,29 +1125,24 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm); void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); /* Scheduled scan */ -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies, int type); -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* UMAC scan */ int iwl_mvm_config_scan(struct iwl_mvm *mvm); -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* MVM debugfs */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1197,9 +1181,8 @@ int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, char *buf, int bufsz); void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); #ifdef CONFIG_IWLWIFI_LEDS int iwl_mvm_leds_init(struct iwl_mvm *mvm); @@ -1255,9 +1238,8 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ int iwl_send_bt_init_conf(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); @@ -1275,9 +1257,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, @@ -1286,9 +1267,8 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm, enum ieee80211_band band); -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* beacon filtering */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1377,9 +1357,8 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_tt_handler(struct iwl_mvm *mvm); void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); void iwl_mvm_tt_exit(struct iwl_mvm *mvm); @@ -1391,9 +1370,8 @@ struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, const char *alpha2, enum iwl_mcc_source src_id, @@ -1432,8 +1410,7 @@ void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_tdls_ch_switch_work(struct work_struct *work); struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2a6be350704a..6dcdee725ff8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -839,9 +839,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) return retval; } -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mcc_chub_notif *notif = (void *)pkt->data; @@ -852,7 +851,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) - return 0; + return; mcc[0] = notif->mcc >> 8; mcc[1] = notif->mcc & 0xff; @@ -864,10 +863,8 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, mcc, src); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL); if (IS_ERR_OR_NULL(regd)) - return 0; + return; regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); kfree(regd); - - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 8f896cd1c9cd..00ca24064c02 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -203,8 +203,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) struct iwl_rx_handlers { u8 cmd_id; bool async; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; #define RX_HANDLER(_cmd_id, _fn, _async) \ @@ -628,8 +627,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) struct iwl_async_handler_entry { struct list_head list; struct iwl_rx_cmd_buffer rxb; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) @@ -666,9 +664,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk) spin_unlock_bh(&mvm->async_handlers_lock); list_for_each_entry_safe(entry, tmp, &local_list, list) { - if (entry->fn(mvm, &entry->rxb, NULL)) - IWL_WARN(mvm, - "returned value from ASYNC handlers are ignored\n"); + entry->fn(mvm, &entry->rxb); iwl_free_rxb(&entry->rxb); list_del(&entry->list); kfree(entry); @@ -715,8 +711,10 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 i; - if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) - return iwl_mvm_rx_rx_mpdu(mvm, rxb, cmd); + if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { + iwl_mvm_rx_rx_mpdu(mvm, rxb); + return 0; + } iwl_mvm_rx_check_trigger(mvm, pkt); @@ -734,8 +732,10 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (rx_h->cmd_id != pkt->hdr.cmd) continue; - if (!rx_h->async) - return rx_h->fn(mvm, rxb, cmd); + if (!rx_h->async) { + rx_h->fn(mvm, rxb); + return 0; + } entry = kzalloc(sizeof(*entry), GFP_ATOMIC); /* we can't do much... */ diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d2c6ba9d326b..8e2490a1d743 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -509,9 +509,8 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, ETH_ALEN); } -int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data; @@ -520,8 +519,6 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id); - - return 0; } struct iwl_power_vifs { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13a..73054ddc5138 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -71,8 +71,7 @@ * Copies the phy information in mvm->last_phy_info, it will be used when the * actual data will come from the fw in the next packet. */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -86,8 +85,6 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, spin_unlock(&mvm->drv_stats_lock); } #endif - - return 0; } /* @@ -242,8 +239,7 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, * * Handles the actual data of the Rx packet from the fw */ -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; @@ -271,7 +267,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); - return 0; + return; } rx_status = IEEE80211_SKB_RXCB(skb); @@ -284,14 +280,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", rx_pkt_status); kfree_skb(skb); - return 0; + return; } if ((unlikely(phy_info->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", phy_info->cfg_phy_cnt); kfree_skb(skb); - return 0; + return; } /* @@ -431,7 +427,6 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, #endif iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, crypt_len, rxb); - return 0; } static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, @@ -623,10 +618,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, iwl_rx_packet_payload_len(pkt)); } -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb)); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5de144968723..9c70118841d7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -327,9 +327,8 @@ static u8 *iwl_mvm_dump_channel_list(struct iwl_scan_results_notif *res, return buf; } -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; @@ -341,17 +340,13 @@ int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); - return 0; } -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); ieee80211_sched_scan_results(mvm->hw); - - return 0; } static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) @@ -368,9 +363,8 @@ static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) } } -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data; @@ -426,8 +420,6 @@ int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS || scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE; - - return 0; } static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) @@ -1371,9 +1363,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_umac_scan_complete *notif = (void *)pkt->data; @@ -1381,7 +1372,7 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status))) - return 0; + return; /* if the scan is already stopping, we don't need to notify mac80211 */ if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { @@ -1405,13 +1396,10 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = false; mvm->scan_uid_status[uid] = 0; - - return 0; } -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; @@ -1423,7 +1411,6 @@ int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); - return 0; } static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 806b2c29b4dc..f7d3921b982f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1680,9 +1680,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } -int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; @@ -1690,15 +1689,13 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, u32 sta_id = le32_to_cpu(notif->sta_id); if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) - return 0; + return; rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (!IS_ERR_OR_NULL(sta)) ieee80211_sta_eosp(sta); rcu_read_unlock(); - - return 0; } void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 748f5dc3f9f4..eedb215eba3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -378,9 +378,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); -int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index a87b506c8c72..71802e7f7448 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -261,8 +261,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; } -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data; @@ -277,17 +276,17 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, /* can fail sometimes */ if (!le32_to_cpu(notif->status)) { iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); - goto out; + return; } if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT)) - goto out; + return; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); /* the station may not be here, but if it is, it must be a TDLS peer */ if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls)) - goto out; + return; mvmsta = iwl_mvm_sta_from_mac80211(sta); vif = mvmsta->vif; @@ -301,9 +300,6 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, msecs_to_jiffies(delay)); iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); - -out: - return 0; } static int diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index d24b6a83e68c..6c0566996441 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -410,9 +410,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, /* * The Rx handler for time event notifications */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_time_event_notif *notif = (void *)pkt->data; @@ -433,8 +432,6 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, } unlock: spin_unlock_bh(&mvm->time_event_lock); - - return 0; } static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait, diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index de4fbc6d57f1..cbdf8e52a5f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -157,9 +157,8 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, /* * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION. */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /** * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionality diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 80d07db6e7e8..7e88d3929119 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -154,24 +154,20 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, return true; } -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); int temp; /* the notification is handled synchronously in ctkill, so skip here */ if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return 0; + return; temp = iwl_mvm_temp_notif_parse(mvm, pkt); if (temp < 0) - return 0; + return; iwl_mvm_tt_temp_changed(mvm, temp); - - return 0; } static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 7ba7a118ff5c..abde484436a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -911,8 +911,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, rcu_read_unlock(); } -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; @@ -921,8 +920,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, iwl_mvm_rx_tx_cmd_single(mvm, pkt); else iwl_mvm_rx_tx_cmd_agg(mvm, pkt); - - return 0; } static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, @@ -942,8 +939,7 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, (void *)(uintptr_t)tid_data->rate_n_flags; } -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; @@ -965,7 +961,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT || tid >= IWL_MAX_TID_COUNT, "sta_id %d tid %d", sta_id, tid)) - return 0; + return; rcu_read_lock(); @@ -974,7 +970,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, /* Reclaiming frames for a station that has been deleted ? */ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { rcu_read_unlock(); - return 0; + return; } mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -985,7 +981,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, "invalid BA notification: Q %d, tid %d, flow %d\n", tid_data->txq_id, tid, scd_flow); rcu_read_unlock(); - return 0; + return; } spin_lock_bh(&mvmsta->lock); @@ -1072,8 +1068,6 @@ out: skb = __skb_dequeue(&reclaimed_skbs); ieee80211_tx_status(mvm->hw, skb); } - - return 0; } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 03f8e06dded7..3b016f95a8ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -243,8 +243,7 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx) return fw_rate_idx_to_plcp[rate_idx]; } -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -256,7 +255,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, le32_to_cpu(err_resp->error_service)); IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n", le64_to_cpu(err_resp->timestamp)); - return 0; } /* -- cgit v1.2.3-70-g09d2 From f7e6469fc90aa388ac5047e1ba914b31af9240ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:58:17 +0200 Subject: iwlwifi: remove command and return value from opmode RX With the previous patch series, no opmode continues using the command or handler_status (i.e. the return value from the RX) so it can be removed now. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 5 ++--- drivers/net/wireless/iwlwifi/dvm/rx.c | 5 +---- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 10 ++++------ drivers/net/wireless/iwlwifi/iwl-trans.h | 3 --- drivers/net/wireless/iwlwifi/mvm/ops.c | 13 +++++-------- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/iwlwifi/pcie/rx.c | 12 +++--------- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +---- 8 files changed, 17 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f549dc3852a6..101ef3109292 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -122,9 +122,8 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) void iwl_down(struct iwl_priv *priv); void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); -int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb); bool iwl_check_for_ct_kill(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index ca270a6234e7..c91374fe9a58 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -1073,8 +1073,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) iwlagn_bt_rx_handler_setup(priv); } -int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); @@ -1098,6 +1097,4 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, iwl_dvm_get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } - - return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index ce1cdd7604e8..71b450adbda0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -148,8 +148,7 @@ struct iwl_op_mode_ops { const struct iwl_fw *fw, struct dentry *dbgfs_dir); void (*stop)(struct iwl_op_mode *op_mode); - int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb); void (*napi_add)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct net_device *napi_dev, @@ -188,11 +187,10 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) op_mode->ops->stop(op_mode); } -static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static inline void iwl_op_mode_rx(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb) { - return op_mode->ops->rx(op_mode, rxb, cmd); + return op_mode->ops->rx(op_mode, rxb); } static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 87a230a7f4b6..7b6f095bac48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -261,8 +261,6 @@ enum iwl_hcmd_dataflag { * @resp_pkt: response packet, if %CMD_WANT_SKB was set * @_rx_page_order: (internally used to free response packet) * @_rx_page_addr: (internally used to free response packet) - * @handler_status: return value of the handler of the command - * (put in setup_rx_handlers) - valid for SYNC mode only * @flags: can be CMD_* * @len: array of the lengths of the chunks in data * @dataflags: IWL_HCMD_DFL_* @@ -273,7 +271,6 @@ struct iwl_host_cmd { struct iwl_rx_packet *resp_pkt; unsigned long _rx_page_addr; u32 _rx_page_order; - int handler_status; u32 flags; u16 len[IWL_MAX_CMD_TBS_PER_TFD]; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 00ca24064c02..51c2fd098c71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -703,9 +703,8 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, } } -static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -713,7 +712,7 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { iwl_mvm_rx_rx_mpdu(mvm, rxb); - return 0; + return; } iwl_mvm_rx_check_trigger(mvm, pkt); @@ -734,13 +733,13 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (!rx_h->async) { rx_h->fn(mvm, rxb); - return 0; + return; } entry = kzalloc(sizeof(*entry), GFP_ATOMIC); /* we can't do much... */ if (!entry) - return 0; + return; entry->rxb._page = rxb_steal_page(rxb); entry->rxb._offset = rxb->_offset; @@ -752,8 +751,6 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, schedule_work(&mvm->async_handlers_wk); break; } - - return 0; } static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 4f0640767d30..e27d5a3dcb86 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -423,7 +423,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); void iwl_pcie_hcmd_complete(struct iwl_trans *trans, - struct iwl_rx_cmd_buffer *rxb, int handler_status); + struct iwl_rx_cmd_buffer *rxb); void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 93062f2e8f56..32ec95bd4973 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -823,10 +823,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) { struct iwl_rx_packet *pkt; - struct iwl_device_cmd *cmd; u16 sequence; bool reclaim; - int index, cmd_index, err, len; + int index, cmd_index, len; struct iwl_rx_cmd_buffer rxcb = { ._offset = offset, ._rx_page_order = trans_pcie->rx_page_order, @@ -874,12 +873,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, index = SEQ_TO_INDEX(sequence); cmd_index = get_cmd_index(&txq->q, index); - if (reclaim) - cmd = txq->entries[cmd_index].cmd; - else - cmd = NULL; - - err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); + iwl_op_mode_rx(trans->op_mode, &rxcb); if (reclaim) { kzfree(txq->entries[cmd_index].free_buf); @@ -897,7 +891,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, * iwl_trans_send_cmd() * as we reclaim the driver command queue */ if (!rxcb._page_stolen) - iwl_pcie_hcmd_complete(trans, &rxcb, err); + iwl_pcie_hcmd_complete(trans, &rxcb); else IWL_WARN(trans, "Claim null rxb?\n"); } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index d711f0b8b62f..c6572ffb8ae2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1553,15 +1553,13 @@ 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 - * @handler_status: return value of the handler of the command - * (put in setup_rx_handlers) * * 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, int handler_status) + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1600,7 +1598,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, meta->source->resp_pkt = pkt; meta->source->_rx_page_addr = (unsigned long)page_address(p); meta->source->_rx_page_order = trans_pcie->rx_page_order; - meta->source->handler_status = handler_status; } iwl_pcie_cmdq_reclaim(trans, txq_id, index); -- cgit v1.2.3-70-g09d2 From 5bf12f6096ad615c90accc1f37935423ea1a3c26 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 24 Jun 2015 10:25:26 +0300 Subject: iwlwifi: mvm: Do not sample the device time for session protection Since the time-event is sent with the immediate flag set, there is no need to sample the device time. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 6c0566996441..8fe7ecd75b92 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -596,8 +596,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC); - time_cmd.apply_time = - cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); + time_cmd.apply_time = cpu_to_le32(0); time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.max_delay = cpu_to_le32(max_delay); -- cgit v1.2.3-70-g09d2 From 1103323ca1aafb0aa32064abec736ea9f2ce66a6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 24 Jun 2015 14:58:13 +0300 Subject: iwlwifi: pcie: cancel Tx timer upon firmware crash When the firmware crashes, we can't expect the Tx queues to progress. Cancel their timer. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/rx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 32ec95bd4973..5561dee7b62d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1014,6 +1014,7 @@ restart: static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (trans->cfg->internal_wimax_coex && @@ -1037,6 +1038,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) iwl_trans_fw_error(trans); local_bh_enable(); + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) + del_timer(&trans_pcie->txq[i].stuck_timer); + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); } -- cgit v1.2.3-70-g09d2 From 33b56af188ddbd1027b7eaff7abb1507b708f155 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 25 Jun 2015 12:55:45 +0300 Subject: iwlwifi: pcie: add missing calls to synchronize_irq() In a few places, we were disabling interrupts but didn't make sure that the interrupt handler has finished running. Add calls to synchronize_irq() to ensure we finish handling the interrupts before we free resources or other things that could lead to a crash if the interrupt were to be handled later. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 23f2824e8d56..4cdfb2fd992a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1178,6 +1178,8 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) 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); + iwl_disable_interrupts(trans); /* @@ -1189,6 +1191,8 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) iwl_pcie_disable_ict(trans); + synchronize_irq(trans_pcie->pci_dev->irq); + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); iwl_clear_bit(trans, CSR_GP_CNTRL, @@ -1326,7 +1330,10 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); + mutex_unlock(&trans_pcie->mutex); + + synchronize_irq(trans_pcie->pci_dev->irq); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) -- cgit v1.2.3-70-g09d2 From 31f920b63ae8ff5bf278a00dd8478e58ed89ff95 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 2 Jul 2015 14:53:02 +0300 Subject: iwlwifi: pcie: don't warn on long MPDUs when supported In iwlmvm firmwares, the Byte count written in the scheduler byte count table is in DWORDs and not in bytes. We should check that this value fits in the 12 bits and the value can be either in bits of in DWORD or bytes depending on the firmware. Check the value after the translation to DWORDs is done (if needed). Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index c6572ffb8ae2..90d02d5f4881 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -219,8 +219,6 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; - WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - sta_id = tx_cmd->sta_id; sec_ctl = tx_cmd->sec_ctl; @@ -239,6 +237,9 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, if (trans_pcie->bc_table_dword) len = DIV_ROUND_UP(len, 4); + if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) + return; + bc_ent = cpu_to_le16(len | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; -- cgit v1.2.3-70-g09d2 From 30f27df9ba44422b718d244a677b1cc6a5bd5ded Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Jun 2015 14:45:40 +0200 Subject: iwlwifi: remove command header flags field The 'flags' field really has been reserved in the firmware API for a very long time, probably since 4965. As a consequence, the field is always 0 and checking for a IWL_CMD_FAILED_MSK flag makes no sense. Rename the field to 'reserved', get rid of IWL_CMD_FAILED_MSK and all the code for it. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 44 ++++++++++++-------------------- drivers/net/wireless/iwlwifi/iwl-trans.h | 6 +---- drivers/net/wireless/iwlwifi/mvm/fw.c | 7 ----- drivers/net/wireless/iwlwifi/mvm/nvm.c | 12 --------- drivers/net/wireless/iwlwifi/mvm/tdls.c | 9 +------ drivers/net/wireless/iwlwifi/mvm/utils.c | 5 ---- drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +- 7 files changed, 19 insertions(+), 66 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index c18aa3e950d5..0fa67d3b7235 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -65,12 +65,6 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); - return; - } - IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); spin_lock_bh(&priv->sta_lock); @@ -136,8 +130,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, add_sta_resp = (void *)pkt->data; /* debug messages are printed in the handler */ - if (!(pkt->hdr.flags & IWL_CMD_FAILED_MSK) && - add_sta_resp->status == ADD_STA_SUCCESS_MSK) { + if (add_sta_resp->status == ADD_STA_SUCCESS_MSK) { spin_lock_bh(&priv->sta_lock); ret = iwl_sta_ucode_activate(priv, sta_id); spin_unlock_bh(&priv->sta_lock); @@ -431,6 +424,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, struct iwl_rx_packet *pkt; int ret; struct iwl_rem_sta_cmd rm_sta_cmd; + struct iwl_rem_sta_resp *rem_sta_resp; struct iwl_host_cmd cmd = { .id = REPLY_REMOVE_STA, @@ -450,29 +444,23 @@ static int iwl_send_remove_station(struct iwl_priv *priv, return ret; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - } + rem_sta_resp = (void *)pkt->data; - if (!ret) { - struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data; - switch (rem_sta_resp->status) { - case REM_STA_SUCCESS_MSK: - if (!temporary) { - spin_lock_bh(&priv->sta_lock); - iwl_sta_ucode_deactivate(priv, sta_id); - spin_unlock_bh(&priv->sta_lock); - } - IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); - break; - default: - ret = -EIO; - IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); - break; + switch (rem_sta_resp->status) { + case REM_STA_SUCCESS_MSK: + if (!temporary) { + spin_lock_bh(&priv->sta_lock); + iwl_sta_ucode_deactivate(priv, sta_id); + spin_unlock_bh(&priv->sta_lock); } + IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); + break; } + iwl_free_resp(&cmd); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7b6f095bac48..64769e44059e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -130,7 +130,7 @@ */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ + u8 reserved; /* * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver @@ -154,10 +154,6 @@ struct iwl_cmd_header { __le16 sequence; } __packed; -/* iwl_cmd_header flags value */ -#define IWL_CMD_FAILED_MSK 0x40 - - #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a5dae09869fc..e905c07127fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -444,12 +444,6 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) return; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n", - pkt->hdr.flags); - goto exit; - } - mem_cfg = (void *)pkt->data; mvm->shared_mem_cfg.shared_mem_addr = @@ -473,7 +467,6 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) le32_to_cpu(mem_cfg->page_buff_size); IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); -exit: iwl_free_resp(&cmd); } diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 6dcdee725ff8..328187da7541 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -139,12 +139,6 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, return ret; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - goto exit; - } /* Extract NVM response */ nvm_resp = (void *)pkt->data; @@ -652,12 +646,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, return ERR_PTR(ret); pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - goto exit; - } /* Extract MCC response */ mcc_resp = (void *)pkt->data; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index 71802e7f7448..d44d02d16fe2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -169,18 +169,11 @@ static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from TDLS_CONFIG_COMMAND (0x%08X)\n", - pkt->hdr.flags); - goto exit; - } - if (WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp))) - goto exit; + WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp)); /* we don't really care about the response at this point */ -exit: iwl_free_resp(&cmd); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 3b016f95a8ed..f50ef822d65e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -166,11 +166,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, goto out_free_resp; } - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - ret = -EIO; - goto out_free_resp; - } - resp_len = iwl_rx_packet_payload_len(pkt); if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { ret = -EIO; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 90d02d5f4881..553ae135464a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1420,7 +1420,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, /* set up the header */ out_cmd->hdr.cmd = cmd->id; - out_cmd->hdr.flags = 0; + out_cmd->hdr.reserved = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | INDEX_TO_SEQ(q->write_ptr)); -- cgit v1.2.3-70-g09d2 From 6bcb00f6183d1eb5d9f8548fe823be7e6d95b912 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jun 2015 10:36:23 +0300 Subject: iwlwifi: mvm: remove IWL_UCODE_TLV_API_BASIC_DWELL All the supported firmwares support this API. This includes removing dwell per band, as band is no longer a factor in calculating the dwell. Only basic dwell is used and FW will calculate the actual dwell time. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 4 -- drivers/net/wireless/iwlwifi/mvm/scan.c | 86 +++++++----------------------- 2 files changed, 20 insertions(+), 70 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index a9b5ae4ebec0..1c6f7b9588c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -247,9 +247,6 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. - * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, - * regardless of the band or the number of the probes. FW will calculate - * the actual dwell time. * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler * through the dedicated host command. * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. @@ -266,7 +263,6 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10, IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11, - IWL_UCODE_TLV_API_BASIC_DWELL = (__force iwl_ucode_tlv_api_t)13, IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16, IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 9c70118841d7..b891fa54fa4a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -90,11 +90,9 @@ struct iwl_mvm_scan_params { int n_match_sets; struct iwl_scan_probe_req preq; struct cfg80211_match_set *match_sets; - struct _dwell { - u16 passive; - u16 active; - u16 fragmented; - } dwell[IEEE80211_NUM_BANDS]; + u16 passive_dwell; + u16 active_dwell; + u16 fragmented_dwell; struct { u8 iterations; u8 full_scan_mul; /* not used for UMAC */ @@ -147,34 +145,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant); } -/* - * If req->n_ssids > 0, it means we should do an active scan. - * In case of active scan w/o directed scan, we receive a zero-length SSID - * just to notify that this scan is active and not passive. - * In order to notify the FW of the number of SSIDs we wish to scan (including - * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). If the first SSID is - * already included in the probe template, so we need to set only - * req->n_ssids - 1 bits in addition to the first bit. - */ -static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm, - enum ieee80211_band band, int n_ssids) -{ - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) - return 10; - if (band == IEEE80211_BAND_2GHZ) - return 20 + 3 * (n_ssids + 1); - return 10 + 2 * (n_ssids + 1); -} - -static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm, - enum ieee80211_band band) -{ - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) - return 110; - return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; -} - static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -191,7 +161,6 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params) { int global_cnt = 0; - enum ieee80211_band band; u8 frag_passive_dwell = 0; ieee80211_iterate_active_interfaces_atomic(mvm->hw, @@ -227,14 +196,10 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, /* * P2P device scan should not be fragmented to avoid negative * impact on P2P device discovery. Configure max_out_time to be - * equal to dwell time on passive channel. Take a longest - * possible value, one that corresponds to 2GHz band + * equal to dwell time on passive channel. */ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - u32 passive_dwell = - iwl_mvm_get_passive_dwell(mvm, - IEEE80211_BAND_2GHZ); - params->max_out_time = passive_dwell; + params->max_out_time = 120; } else { params->passive_fragmented = true; } @@ -246,30 +211,21 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, not_bound: - for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - if (params->passive_fragmented) - params->dwell[band].fragmented = frag_passive_dwell; + if (params->passive_fragmented) + params->fragmented_dwell = frag_passive_dwell; + + /* + * use only basic dwell time in scan command, regardless of the band or + * the number of the probes. FW will calculate the actual dwell time. + */ + params->passive_dwell = 110; + params->active_dwell = 10; - params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm, - band); - params->dwell[band].active = - iwl_mvm_get_active_dwell(mvm, band, params->n_ssids); - } IWL_DEBUG_SCAN(mvm, "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n", params->max_out_time, params->suspend_time, params->passive_fragmented); - IWL_DEBUG_SCAN(mvm, - "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n", - params->dwell[IEEE80211_BAND_2GHZ].passive, - params->dwell[IEEE80211_BAND_2GHZ].active, - params->dwell[IEEE80211_BAND_2GHZ].fragmented); - IWL_DEBUG_SCAN(mvm, - "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n", - params->dwell[IEEE80211_BAND_5GHZ].passive, - params->dwell[IEEE80211_BAND_5GHZ].active, - params->dwell[IEEE80211_BAND_5GHZ].fragmented); } static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) @@ -743,11 +699,10 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_lmac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; - cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; + cmd->active_dwell = params->active_dwell; + cmd->passive_dwell = params->passive_dwell; if (params->passive_fragmented) - cmd->fragmented_dwell = - params->dwell[IEEE80211_BAND_2GHZ].fragmented; + cmd->fragmented_dwell = params->fragmented_dwell; cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); @@ -1005,11 +960,10 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_umac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; - cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; + cmd->active_dwell = params->active_dwell; + cmd->passive_dwell = params->passive_dwell; if (params->passive_fragmented) - cmd->fragmented_dwell = - params->dwell[IEEE80211_BAND_2GHZ].fragmented; + cmd->fragmented_dwell = params->fragmented_dwell; cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); cmd->scan_priority = -- cgit v1.2.3-70-g09d2 From ce7929186a390b8630953be6d8225a9ae88030af Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 2 Jun 2015 18:06:16 +0300 Subject: iwlwifi: mvm: add basic Time of Flight (802.11mc FTM) support ToF is a time based method for measurement of the WiFi device location within a WiFi environment. The driver functionality provided by this patch is the interface for communication with FW and receiving location related updates from the FW. The interface provided by this patch is via debugfs. Signed-off-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/mvm/Makefile | 1 + drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 751 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h | 391 +++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 5 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/ops.c | 5 + drivers/net/wireless/iwlwifi/mvm/tof.c | 311 ++++++++++ drivers/net/wireless/iwlwifi/mvm/tof.h | 94 ++++ 10 files changed, 1563 insertions(+) create mode 100644 drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h create mode 100644 drivers/net/wireless/iwlwifi/mvm/tof.c create mode 100644 drivers/net/wireless/iwlwifi/mvm/tof.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 1c6f7b9588c4..c31cf828fb25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -280,6 +280,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer + * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report @@ -307,6 +308,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1, IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2, IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3, + IWL_UCODE_TLV_CAPA_TOF_SUPPORT = (__force iwl_ucode_tlv_capa_t)5, IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6, IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8, IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9, diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 2d7c3ea3c4f8..8c2c3d13b092 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -6,6 +6,7 @@ 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 iwlmvm-$(CONFIG_PM_SLEEP) += d3.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index beba375489f1..b8ee3121fbd2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -102,6 +102,7 @@ #define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_P2P_MIMO 0 +#define IWL_MVM_TOF_IS_RESPONDER 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/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 5c8a65de0e77..ddb1c844827b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -63,6 +63,7 @@ * *****************************************************************************/ #include "mvm.h" +#include "fw-api-tof.h" #include "debugfs.h" static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, @@ -497,6 +498,731 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static inline char *iwl_dbgfs_is_match(char *name, char *buf) +{ + int len = strlen(name); + + return !strncmp(name, buf, len) ? buf + len : NULL; +} + +static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif, + char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int value, ret = -EINVAL; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("tof_disabled=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.tof_disabled = value; + goto out; + } + + data = iwl_dbgfs_is_match("one_sided_disabled=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.one_sided_disabled = value; + goto out; + } + + data = iwl_dbgfs_is_match("is_debug_mode=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.is_debug_mode = value; + goto out; + } + + data = iwl_dbgfs_is_match("is_buf=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.is_buf_required = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_tof_cfg=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_config_cmd(mvm); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_enable_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_config_cmd *cmd; + + cmd = &mvm->tof_data.tof_cfg; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n", + cmd->tof_disabled); + pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n", + cmd->one_sided_disabled); + pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n", + cmd->is_debug_mode); + pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n", + cmd->is_buf_required); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif, + char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("burst_period=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (!ret) + mvm->tof_data.responder_cfg.burst_period = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("min_delta_ftm=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.min_delta_ftm = value; + goto out; + } + + data = iwl_dbgfs_is_match("burst_duration=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.burst_duration = value; + goto out; + } + + data = iwl_dbgfs_is_match("num_of_burst_exp=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.num_of_burst_exp = value; + goto out; + } + + data = iwl_dbgfs_is_match("abort_responder=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.abort_responder = value; + goto out; + } + + data = iwl_dbgfs_is_match("get_ch_est=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.get_ch_est = value; + goto out; + } + + data = iwl_dbgfs_is_match("recv_sta_req_params=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.recv_sta_req_params = value; + goto out; + } + + data = iwl_dbgfs_is_match("channel_num=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.channel_num = value; + goto out; + } + + data = iwl_dbgfs_is_match("bandwidth=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.bandwidth = value; + goto out; + } + + data = iwl_dbgfs_is_match("rate=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.rate = value; + goto out; + } + + data = iwl_dbgfs_is_match("bssid=", buf); + if (data) { + u8 *mac = mvm->tof_data.responder_cfg.bssid; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + } + + data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.tsf_timer_offset_msecs = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("toa_offset=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.toa_offset = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("ctrl_ch_position=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ctrl_ch_position = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_per_burst=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ftm_per_burst = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; + goto out; + } + + data = iwl_dbgfs_is_match("asap_mode=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.asap_mode = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_responder_cfg=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_responder_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_responder_config_cmd *cmd; + + cmd = &mvm->tof_data.responder_cfg; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", + le16_to_cpu(cmd->burst_period)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", + cmd->burst_duration); + pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", + cmd->bandwidth); + pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", + cmd->channel_num); + pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", + cmd->ctrl_ch_position); + pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", + cmd->bssid); + pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", + cmd->min_delta_ftm); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", + cmd->num_of_burst_exp); + pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); + pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", + cmd->abort_responder); + pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", + cmd->get_ch_est); + pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", + cmd->recv_sta_req_params); + pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", + cmd->ftm_per_burst); + pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", + cmd->ftm_resp_ts_avail); + pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", + cmd->asap_mode); + pos += scnprintf(buf + pos, bufsz - pos, + "tsf_timer_offset_msecs = %d\n", + le16_to_cpu(cmd->tsf_timer_offset_msecs)); + pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", + le16_to_cpu(cmd->toa_offset)); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("request_id=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.request_id = value; + goto out; + } + + data = iwl_dbgfs_is_match("initiator=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.initiator = value; + goto out; + } + + data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.one_sided_los_disable = value; + goto out; + } + + data = iwl_dbgfs_is_match("req_timeout=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.req_timeout = value; + goto out; + } + + data = iwl_dbgfs_is_match("report_policy=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.report_policy = value; + goto out; + } + + data = iwl_dbgfs_is_match("macaddr_random=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.macaddr_random = value; + goto out; + } + + data = iwl_dbgfs_is_match("num_of_ap=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.num_of_ap = value; + goto out; + } + + data = iwl_dbgfs_is_match("macaddr_template=", buf); + if (data) { + u8 mac[ETH_ALEN]; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); + } + + data = iwl_dbgfs_is_match("macaddr_mask=", buf); + if (data) { + u8 mac[ETH_ALEN]; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); + } + + data = iwl_dbgfs_is_match("ap=", buf); + if (data) { + struct iwl_tof_range_req_ap_entry ap; + int size = sizeof(struct iwl_tof_range_req_ap_entry); + u16 burst_period; + u8 *mac = ap.bssid; + int i; + + if (sscanf(data, "%d %hhd %hhx %hhx" + "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" + "%hhx %hhx %hx" + "%hhx %hhx %x" + "%hhx %hhx %hhx %hhx", + &i, &ap.channel_num, &ap.bandwidth, + &ap.ctrl_ch_position, + mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, + &ap.measure_type, &ap.num_of_bursts, + &burst_period, + &ap.samples_per_burst, &ap.retries_per_sample, + &ap.tsf_delta, &ap.location_req, &ap.asap_mode, + &ap.enable_dyn_ack, &ap.rssi) != 20) { + ret = -EINVAL; + goto out; + } + if (i > IWL_MVM_TOF_MAX_APS) { + IWL_ERR(mvm, "Invalid AP index %d\n", i); + ret = -EINVAL; + goto out; + } + + ap.burst_period = cpu_to_le16(burst_period); + + memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); + goto out; + } + + data = iwl_dbgfs_is_match("send_range_request=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_range_request_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[512]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_range_req_cmd *cmd; + int i; + + cmd = &mvm->tof_data.range_req; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", + cmd->request_id); + pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", + cmd->initiator); + pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", + cmd->one_sided_los_disable); + pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", + cmd->req_timeout); + pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", + cmd->report_policy); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", + cmd->macaddr_random); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", + cmd->macaddr_template); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", + cmd->macaddr_mask); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", + cmd->num_of_ap); + for (i = 0; i < cmd->num_of_ap; i++) { + struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; + + pos += scnprintf(buf + pos, bufsz - pos, + "ap %.2d: channel_num=%hhx bw=%hhx" + " control=%hhx bssid=%pM type=%hhx" + " num_of_bursts=%hhx burst_period=%hx ftm=%hhx" + " retries=%hhx tsf_delta=%x location_req=%hhx " + " asap=%hhx enable=%hhx rssi=%hhx\n", + i, ap->channel_num, ap->bandwidth, + ap->ctrl_ch_position, ap->bssid, + ap->measure_type, ap->num_of_bursts, + ap->burst_period, ap->samples_per_burst, + ap->retries_per_sample, ap->tsf_delta, + ap->location_req, ap->asap_mode, + ap->enable_dyn_ack, ap->rssi); + } + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif, + char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.tsf_timer_offset_msec = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("min_delta_ftm=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.min_delta_ftm = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw20M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw40M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw80M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("send_range_req_ext=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_range_req_ext_cmd *cmd; + + cmd = &mvm->tof_data.range_req_ext; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, + "tsf_timer_offset_msec = %hx\n", + cmd->tsf_timer_offset_msec); + pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhx\n", + cmd->min_delta_ftm); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw20M = %hhx\n", + cmd->ftm_format_and_bw20M); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw40M = %hhx\n", + cmd->ftm_format_and_bw40M); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw80M = %hhx\n", + cmd->ftm_format_and_bw80M); + + mutex_unlock(&mvm->mutex); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif, + char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int value, ret = 0; + int abort_id; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("abort_id=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.last_abort_id = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_range_abort=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + abort_id = mvm->tof_data.last_abort_id; + ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[32]; + int pos = 0; + const size_t bufsz = sizeof(buf); + int last_abort_id; + + mutex_lock(&mvm->mutex); + last_abort_id = mvm->tof_data.last_abort_id; + mutex_unlock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", + last_abort_id); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char *buf; + int pos = 0; + const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; + struct iwl_tof_range_rsp_ntfy *cmd; + int i, ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + cmd = &mvm->tof_data.range_resp; + + pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", + cmd->request_id); + pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", + cmd->request_status); + pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", + cmd->last_in_batch); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", + cmd->num_of_aps); + for (i = 0; i < cmd->num_of_aps; i++) { + struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; + + pos += scnprintf(buf + pos, bufsz - pos, + "ap %.2d: bssid=%pM status=%hhx bw=%hhx" + " rtt=%x rtt_var=%x rtt_spread=%x" + " rssi=%hhx rssi_spread=%hhx" + " range=%x range_var=%x" + " time_stamp=%x\n", + i, ap->bssid, ap->measure_status, + ap->measure_bw, + ap->rtt, ap->rtt_variance, ap->rtt_spread, + ap->rssi, ap->rssi_spread, ap->range, + ap->range_variance, ap->timestamp); + } + mutex_unlock(&mvm->mutex); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, size_t count, loff_t *ppos) { @@ -628,6 +1354,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); +MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -671,6 +1403,25 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && + !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { + if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) + MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, + mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, + S_IRUSR); + } + /* * Create symlink for convenience pointing to interface specific * debugfs entries for the driver. For example, under diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h new file mode 100644 index 000000000000..287c9ecb0fb1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h @@ -0,0 +1,391 @@ +/****************************************************************************** + * + * 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) 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * 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) 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. + * + *****************************************************************************/ +#ifndef __fw_api_tof_h__ +#define __fw_api_tof_h__ + +#include "fw-api.h" + +/* ToF sub-group command IDs */ +enum iwl_mvm_tof_sub_grp_ids { + TOF_RANGE_REQ_CMD = 0x1, + TOF_CONFIG_CMD = 0x2, + TOF_RANGE_ABORT_CMD = 0x3, + TOF_RANGE_REQ_EXT_CMD = 0x4, + TOF_RESPONDER_CONFIG_CMD = 0x5, + TOF_NW_INITIATED_RES_SEND_CMD = 0x6, + TOF_NEIGHBOR_REPORT_REQ_CMD = 0x7, + TOF_NEIGHBOR_REPORT_RSP_NOTIF = 0xFC, + TOF_NW_INITIATED_REQ_RCVD_NOTIF = 0xFD, + TOF_RANGE_RESPONSE_NOTIF = 0xFE, + TOF_MCSI_DEBUG_NOTIF = 0xFB, +}; + +/** + * struct iwl_tof_config_cmd - ToF configuration + * @tof_disabled: 0 enabled, 1 - disabled + * @one_sided_disabled: 0 enabled, 1 - disabled + * @is_debug_mode: 1 debug mode, 0 - otherwise + * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise + */ +struct iwl_tof_config_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 tof_disabled; + u8 one_sided_disabled; + u8 is_debug_mode; + u8 is_buf_required; +} __packed; + +/** + * struct iwl_tof_responder_config_cmd - ToF AP mode (for debug) + * @burst_period: future use: (currently hard coded in the LMAC) + * The interval between two sequential bursts. + * @min_delta_ftm: future use: (currently hard coded in the LMAC) + * The minimum delay between two sequential FTM Responses + * in the same burst. + * @burst_duration: future use: (currently hard coded in the LMAC) + * The total time for all FTMs handshake in the same burst. + * Affect the time events duration in the LMAC. + * @num_of_burst_exp: future use: (currently hard coded in the LMAC) + * The number of bursts for the current ToF request. Affect + * the number of events allocations in the current iteration. + * @get_ch_est: for xVT only, NA for driver + * @abort_responder: when set to '1' - Responder will terminate its activity + * (all other fields in the command are ignored) + * @recv_sta_req_params: 1 - Responder will ignore the other Responder's + * params and use the recomended Initiator params. + * 0 - otherwise + * @channel_num: current AP Channel + * @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rate: current AP rate + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency. + * 40MHz 0 below center, 1 above center + * 80MHz bits [0..1]: 0 the near 20MHz to the center, + * 1 the far 20MHz to the center + * bit[2] as above 40MHz + * @ftm_per_burst: FTMs per Burst + * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, + * '1' - we measure over the Initial FTM Response + * @asap_mode: ASAP / Non ASAP mode for the current WLS station + * @sta_id: index of the AP STA when in AP mode + * @tsf_timer_offset_msecs: The dictated time offset (mSec) from the AP's TSF + * @toa_offset: Artificial addition [0.1nsec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @bssid: Current AP BSSID + */ +struct iwl_tof_responder_config_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + __le16 burst_period; + u8 min_delta_ftm; + u8 burst_duration; + u8 num_of_burst_exp; + u8 get_ch_est; + u8 abort_responder; + u8 recv_sta_req_params; + u8 channel_num; + u8 bandwidth; + u8 rate; + u8 ctrl_ch_position; + u8 ftm_per_burst; + u8 ftm_resp_ts_avail; + u8 asap_mode; + u8 sta_id; + __le16 tsf_timer_offset_msecs; + __le16 toa_offset; + u8 bssid[ETH_ALEN]; +} __packed; + +/** + * struct iwl_tof_range_request_ext_cmd - extended range req for WLS + * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @min_delta_ftm: Minimal time between two consecutive measurements, + * in units of 100us. 0 means no preference by station + * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended + * value be sent to the AP + * @ftm_format_and_bw40M: FTM Channel Spacing/Format for 40MHz: recommended + * value to be sent to the AP + * @ftm_format_and_bw80M: FTM Channel Spacing/Format for 80MHz: recommended + * value to be sent to the AP + */ +struct iwl_tof_range_req_ext_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + __le16 tsf_timer_offset_msec; + __le16 reserved; + u8 min_delta_ftm; + u8 ftm_format_and_bw20M; + u8 ftm_format_and_bw40M; + u8 ftm_format_and_bw80M; +} __packed; + +#define IWL_MVM_TOF_MAX_APS 21 + +/** + * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * @channel_num: Current AP Channel + * @bandwidth: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @tsf_delta_direction: TSF relatively to the subject AP + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency. + * 40MHz 0 below center, 1 above center + * 80MHz bits [0..1]: 0 the near 20MHz to the center, + * 1 the far 20MHz to the center + * bit[2] as above 40MHz + * @bssid: AP's bss id + * @measure_type: Measurement type: 0 - two sided, 1 - One sided + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of the + * number of measurement iterations (min 2^0 = 1, max 2^14) + * @burst_period: Recommended value to be sent to the AP. Measurement + * periodicity In units of 100ms. ignored if num_of_bursts = 0 + * @samples_per_burst: 2-sided: the number of FTMs pairs in single Burst (1-31) + * 1-sided: how many rts/cts pairs should be used per burst. + * @retries_per_sample: Max number of retries that the LMAC should send + * in case of no replies by the AP. + * @tsf_delta: TSF Delta in units of microseconds. + * The difference between the AP TSF and the device local clock. + * @location_req: Location Request Bit[0] LCI should be sent in the FTMR + * Bit[1] Civic should be sent in the FTMR + * @asap_mode: 0 - non asap mode, 1 - asap mode (not relevant for one sided) + * @enable_dyn_ack: Enable Dynamic ACK BW. + * 0 Initiator interact with regular AP + * 1 Initiator interact with Responder machine: need to send the + * Initiator Acks with HT 40MHz / 80MHz, since the Responder should + * use it for its ch est measurement (this flag will be set when we + * configure the opposite machine to be Responder). + * @rssi: Last received value + * leagal values: -128-0 (0x7f). above 0x0 indicating an invalid value. + */ +struct iwl_tof_range_req_ap_entry { + u8 channel_num; + u8 bandwidth; + u8 tsf_delta_direction; + u8 ctrl_ch_position; + u8 bssid[ETH_ALEN]; + u8 measure_type; + u8 num_of_bursts; + __le16 burst_period; + u8 samples_per_burst; + u8 retries_per_sample; + __le32 tsf_delta; + u8 location_req; + u8 asap_mode; + u8 enable_dyn_ack; + s8 rssi; +} __packed; + +/** + * enum iwl_tof_response_mode + * @IWL_MVM_TOF_RESPOSE_ASAP: report each AP measurement separately as soon as + * possible (not supported for this release) + * @IWL_MVM_TOF_RESPOSE_TIMEOUT: report all AP measurements as a batch upon + * timeout expiration + * @IWL_MVM_TOF_RESPOSE_COMPLETE: report all AP measurements as a batch at the + * earlier of: measurements completion / timeout + * expiration. + */ +enum iwl_tof_response_mode { + IWL_MVM_TOF_RESPOSE_ASAP = 1, + IWL_MVM_TOF_RESPOSE_TIMEOUT, + IWL_MVM_TOF_RESPOSE_COMPLETE, +}; + +/** + * struct iwl_tof_range_req_cmd - start measurement cmd + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @initiator: 0- NW initiated, 1 - Client Initiated + * @one_sided_los_disable: '0'- run ML-Algo for both ToF/OneSided, + * '1' - run ML-Algo for ToF only + * @req_timeout: Requested timeout of the response in units of 100ms. + * This is equivalent to the session time configured to the + * LMAC in Initiator Request + * @report_policy: Supported partially for this release: For current release - + * the range report will be uploaded as a batch when ready or + * when the session is done (successfully / partially). + * one of iwl_tof_response_mode. + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @macaddr_random: '0' Use default source MAC address (i.e. p2_p), + * '1' Use MAC Address randomization according to the below + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + */ +struct iwl_tof_range_req_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 request_id; + u8 initiator; + u8 one_sided_los_disable; + u8 req_timeout; + u8 report_policy; + u8 los_det_disable; + u8 num_of_ap; + u8 macaddr_random; + u8 macaddr_template[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +/** + * struct iwl_tof_gen_resp_cmd - generic ToF response + */ +struct iwl_tof_gen_resp_cmd { + __le32 sub_grp_cmd_id; + u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) + * @measure_status: current APs measurement status + * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rtt: The Round Trip Time that took for the last measurement for + * current AP [nSec] + * @rtt_variance: The Variance of the RTT values measured for current AP + * @rtt_spread: The Difference between the maximum and the minimum RTT + * values measured for current AP in the current session [nsec] + * @rssi: RSSI as uploaded in the Channel Estimation notification + * @rssi_spread: The Difference between the maximum and the minimum RSSI values + * measured for current AP in the current session + * @range: Measured range [cm] + * @range_variance: Measured range variance [cm] + * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was + * uploaded by the LMAC + */ +struct iwl_tof_range_rsp_ap_entry_ntfy { + u8 bssid[ETH_ALEN]; + u8 measure_status; + u8 measure_bw; + __le32 rtt; + __le32 rtt_variance; + __le32 rtt_spread; + s8 rssi; + u8 rssi_spread; + __le16 reserved; + __le32 range; + __le32 range_variance; + __le32 timestamp; +} __packed; + +/** + * struct iwl_tof_range_rsp_ntfy - + * @request_id: A Token ID of the corresponding Range request + * @request_status: status of current measurement session + * @last_in_batch: reprot policy (when not all responses are uploaded at once) + * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + */ +struct iwl_tof_range_rsp_ntfy { + u8 request_id; + u8 request_status; + u8 last_in_batch; + u8 num_of_aps; + struct iwl_tof_range_rsp_ap_entry_ntfy ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +#define IWL_MVM_TOF_MCSI_BUF_SIZE (245) +/** + * struct iwl_tof_mcsi_notif - used for debug + * @token: token ID for the current session + * @role: '0' - initiator, '1' - responder + * @initiator_bssid: initiator machine + * @responder_bssid: responder machine + * @mcsi_buffer: debug data + */ +struct iwl_tof_mcsi_notif { + u8 token; + u8 role; + __le16 reserved; + u8 initiator_bssid[ETH_ALEN]; + u8 responder_bssid[ETH_ALEN]; + u8 mcsi_buffer[IWL_MVM_TOF_MCSI_BUF_SIZE * 4]; +} __packed; + +/** + * struct iwl_tof_neighbor_report_notif + * @bssid: BSSID of the AP which sent the report + * @request_token: same token as the corresponding request + * @status: + * @report_ie_len: the length of the response frame starting from the Element ID + * @data: the IEs + */ +struct iwl_tof_neighbor_report { + u8 bssid[ETH_ALEN]; + u8 request_token; + u8 status; + __le16 report_ie_len; + u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_abort_cmd + * @request_id: corresponds to a range request + */ +struct iwl_tof_range_abort_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 request_id; + u8 reserved[3]; +} __packed; + +#endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 16e9ef49397f..2bc33faae5b4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -75,6 +75,7 @@ #include "fw-api-coex.h" #include "fw-api-scan.h" #include "fw-api-stats.h" +#include "fw-api-tof.h" /* Tx queue numbers */ enum { @@ -163,6 +164,10 @@ enum { CALIB_RES_NOTIF_PHY_DB = 0x6b, /* PHY_DB_CMD = 0x6c, */ + /* ToF - 802.11mc FTM */ + TOF_CMD = 0x10, + TOF_NOTIFICATION = 0x11, + /* Power - legacy power table command */ POWER_TABLE_CMD = 0x77, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 1397e3e0d669..c980e8d9ac5a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,6 +80,7 @@ #include "sta.h" #include "fw-api.h" #include "constants.h" +#include "tof.h" #define IWL_INVALID_MAC80211_QUEUE 0xff #define IWL_MVM_MAX_ADDRESSES 5 @@ -823,6 +824,7 @@ struct iwl_mvm { struct iwl_mvm_shared_mem_cfg shared_mem_cfg; u32 ciphers[6]; + struct iwl_mvm_tof_data tof_data; }; /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 51c2fd098c71..76b5557c1dde 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -259,6 +259,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, true), RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), + RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true), }; #undef RX_HANDLER @@ -574,6 +575,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, /* rpm starts with a taken ref. only set the appropriate bit here. */ mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; + iwl_mvm_tof_init(mvm); + return op_mode; out_unregister: @@ -621,6 +624,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); + iwl_mvm_tof_clean(mvm); + ieee80211_free_hw(mvm->hw); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c new file mode 100644 index 000000000000..5a8e96f0293d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -0,0 +1,311 @@ +/****************************************************************************** + * + * 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) 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * 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) 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 "mvm.h" +#include "fw-api-tof.h" + +#define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256 + +void iwl_mvm_tof_init(struct iwl_mvm *mvm) +{ + struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return; + + memset(tof_data, 0, sizeof(*tof_data)); + + tof_data->tof_cfg.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_config_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (IWL_MVM_TOF_IS_RESPONDER) { + tof_data->responder_cfg.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_responder_config_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->responder_cfg.sub_grp_cmd_id = + cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); + tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; + } +#endif + + tof_data->range_req.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_range_req_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); + tof_data->range_req.req_timeout = 1; + tof_data->range_req.initiator = 1; + tof_data->range_req.report_policy = 3; + + tof_data->range_req_ext.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_range_req_ext_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->range_req_ext.sub_grp_cmd_id = + cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); + + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +void iwl_mvm_tof_clean(struct iwl_mvm *mvm) +{ + struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return; + + memset(tof_data, 0, sizeof(*tof_data)); + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +static void iwl_tof_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + bool *enabled = _data; + + /* non bss vif exists */ + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) + *enabled = false; +} + +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) +{ + struct iwl_tof_config_cmd *cmd = &mvm->tof_data.tof_cfg; + bool enabled; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_tof_iterator, &enabled); + if (!enabled) { + IWL_DEBUG_INFO(mvm, "ToF is not supported (non bss vif)\n"); + return -EINVAL; + } + + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); +} + +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) +{ + struct iwl_tof_range_abort_cmd cmd = { + .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), + .hdr.size = cpu_to_le16(sizeof(struct iwl_tof_range_abort_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)), + .request_id = id, + }; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (id != mvm->tof_data.active_range_request) { + IWL_ERR(mvm, "Invalid range request id %d (active %d)\n", + id, mvm->tof_data.active_range_request); + return -EINVAL; + } + + /* after abort is sent there's no active request anymore */ + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(cmd), &cmd); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_tof_responder_config_cmd *cmd = &mvm->tof_data.responder_cfg; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (vif->p2p || vif->type != NL80211_IFTYPE_AP) { + IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); + return -EIO; + } + + cmd->sta_id = mvmvif->bcast_sta.sta_id; + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); +} +#endif + +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_host_cmd cmd = { + .id = TOF_CMD, + .len = { sizeof(mvm->tof_data.range_req), }, + /* no copy because of the command size */ + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { + IWL_ERR(mvm, "Cannot send range request, not STA mode\n"); + return -EIO; + } + + /* nesting of range requests is not supported in FW */ + if (mvm->tof_data.active_range_request != + IWL_MVM_TOF_RANGE_REQ_MAX_ID) { + IWL_ERR(mvm, "Cannot send range req, already active req %d\n", + mvm->tof_data.active_range_request); + return -EIO; + } + + mvm->tof_data.active_range_request = mvm->tof_data.range_req.request_id; + + cmd.data[0] = &mvm->tof_data.range_req; + return iwl_mvm_send_cmd(mvm, &cmd); +} + +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { + IWL_ERR(mvm, "Cannot send ext range req, not in STA mode\n"); + return -EIO; + } + + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, + sizeof(mvm->tof_data.range_req_ext), + &mvm->tof_data.range_req_ext); +} + +static int iwl_mvm_tof_range_resp(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_range_rsp_ntfy *resp = (void *)data; + + if (resp->request_id != mvm->tof_data.active_range_request) { + IWL_ERR(mvm, "Request id mismatch, got %d, active %d\n", + resp->request_id, mvm->tof_data.active_range_request); + return -EIO; + } + + memcpy(&mvm->tof_data.range_resp, resp, + sizeof(struct iwl_tof_range_rsp_ntfy)); + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + + return 0; +} + +static int iwl_mvm_tof_mcsi_notif(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_mcsi_notif *resp = (struct iwl_tof_mcsi_notif *)data; + + IWL_DEBUG_INFO(mvm, "MCSI notification, token %d\n", resp->token); + return 0; +} + +static int iwl_mvm_tof_nb_report_notif(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_neighbor_report *report = + (struct iwl_tof_neighbor_report *)data; + + IWL_DEBUG_INFO(mvm, "NB report, bssid %pM, token %d, status 0x%x\n", + report->bssid, report->request_token, report->status); + return 0; +} + +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_tof_gen_resp_cmd *resp = (void *)pkt->data; + + lockdep_assert_held(&mvm->mutex); + + switch (le32_to_cpu(resp->sub_grp_cmd_id)) { + case TOF_RANGE_RESPONSE_NOTIF: + iwl_mvm_tof_range_resp(mvm, resp->data); + break; + case TOF_MCSI_DEBUG_NOTIF: + iwl_mvm_tof_mcsi_notif(mvm, resp->data); + break; + case TOF_NEIGHBOR_REPORT_RSP_NOTIF: + iwl_mvm_tof_nb_report_notif(mvm, resp->data); + break; + default: + IWL_ERR(mvm, "Unknown sub-group command 0x%x\n", + resp->sub_grp_cmd_id); + break; + } +} diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.h b/drivers/net/wireless/iwlwifi/mvm/tof.h new file mode 100644 index 000000000000..50ae8adaaa6e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * 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) 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * 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) 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. + * + *****************************************************************************/ +#ifndef __tof +#define __tof_h__ + +#include "fw-api-tof.h" + +struct iwl_mvm_tof_data { + struct iwl_tof_config_cmd tof_cfg; + struct iwl_tof_range_req_cmd range_req; + struct iwl_tof_range_req_ext_cmd range_req_ext; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct iwl_tof_responder_config_cmd responder_cfg; +#endif + struct iwl_tof_range_rsp_ntfy range_resp; + u8 last_abort_id; + u16 active_range_request; +}; + +void iwl_mvm_tof_init(struct iwl_mvm *mvm); +void iwl_mvm_tof_clean(struct iwl_mvm *mvm); +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm); +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id); +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +#endif +#endif /* __tof_h__ */ -- cgit v1.2.3-70-g09d2 From ab02165ccec4c78162501acedeef1a768acdb811 Mon Sep 17 00:00:00 2001 From: Aviya Erenfeld Date: Tue, 9 Jun 2015 16:45:52 +0300 Subject: iwlwifi: add wide firmware command infrastructure for TX As the firmware is slowly running out of command IDs and grouping of commands is desirable anyway, the firmware is extending the command header from 4 bytes to 8 bytes to introduce a group (in place of the former flags field, since that's always 0 on commands and thus can be easily used to distinguish between the two. In order to support this most easily in the driver widen the command command ID used in the command sending functions and encode the new values (group and version) in the ID. That way existing code doesn't have to be changed (since the higher bits are 0 automatically) and newer code can easily use the new ID generation function to create a value to use in place of just the command ID. Signed-off-by: Aviya Erenfeld Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- .../net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h | 14 +++-- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/iwl-trans.h | 66 ++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 + drivers/net/wireless/iwlwifi/mvm/utils.c | 4 +- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 + drivers/net/wireless/iwlwifi/pcie/trans.c | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 53 ++++++++++++----- 9 files changed, 121 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h index 948ce0802fa7..eb4b99a1c8cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h @@ -36,7 +36,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd, TP_PROTO(const struct device *dev, struct iwl_host_cmd *cmd, u16 total_size, - struct iwl_cmd_header *hdr), + struct iwl_cmd_header_wide *hdr), TP_ARGS(dev, cmd, total_size, hdr), TP_STRUCT__entry( DEV_ENTRY @@ -44,11 +44,14 @@ TRACE_EVENT(iwlwifi_dev_hcmd, __field(u32, flags) ), TP_fast_assign( - int i, offset = sizeof(*hdr); + int i, offset = sizeof(struct iwl_cmd_header); + + if (hdr->group_id) + offset = sizeof(struct iwl_cmd_header_wide); DEV_ASSIGN; __entry->flags = cmd->flags; - memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); + memcpy(__get_dynamic_array(hcmd), hdr, offset); for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { if (!cmd->len[i]) @@ -58,8 +61,9 @@ TRACE_EVENT(iwlwifi_dev_hcmd, offset += cmd->len[i]; } ), - TP_printk("[%s] hcmd %#.2x (%ssync)", - __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[0], + TP_printk("[%s] hcmd %#.2x.%#.2x (%ssync)", + __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[1], + ((u8 *)__get_dynamic_array(hcmd))[0], __entry->flags & CMD_ASYNC ? "a" : "") ); diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index c31cf828fb25..f99ec4e22052 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -247,6 +247,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. + * @IWL_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler * through the dedicated host command. * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. @@ -263,6 +264,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10, IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11, + IWL_UCODE_TLV_API_WIDE_CMD_HDR = (__force iwl_ucode_tlv_api_t)14, IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16, IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17, diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 64769e44059e..df71aa3e6401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -122,6 +122,32 @@ #define INDEX_TO_SEQ(i) ((i) & 0xff) #define SEQ_RX_FRAME cpu_to_le16(0x8000) +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ + return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ + return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ + return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ + return opcode + (groupid << 8) + (version << 16); +} + /** * struct iwl_cmd_header * @@ -130,7 +156,7 @@ */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 reserved; + u8 group_id; /* * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver @@ -154,6 +180,23 @@ struct iwl_cmd_header { __le16 sequence; } __packed; +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { + u8 cmd; + u8 group_id; + __le16 sequence; + __le16 length; + u8 reserved; + u8 version; +} __packed; + #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 @@ -218,8 +261,18 @@ enum CMD_MODE { * aren't fully copied and use other TFD space. */ struct iwl_device_cmd { - struct iwl_cmd_header hdr; /* uCode API */ - u8 payload[DEF_CMD_PAYLOAD_SIZE]; + union { + struct { + struct iwl_cmd_header hdr; /* uCode API */ + u8 payload[DEF_CMD_PAYLOAD_SIZE]; + }; + struct { + struct iwl_cmd_header_wide hdr_wide; + u8 payload_wide[DEF_CMD_PAYLOAD_SIZE - + sizeof(struct iwl_cmd_header_wide) + + sizeof(struct iwl_cmd_header)]; + }; + }; } __packed; #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) @@ -260,7 +313,8 @@ enum iwl_hcmd_dataflag { * @flags: can be CMD_* * @len: array of the lengths of the chunks in data * @dataflags: IWL_HCMD_DFL_* - * @id: id of the host command + * @id: command id of the host command, for wide commands encoding the + * version and group as well */ struct iwl_host_cmd { const void *data[IWL_MAX_CMD_TBS_PER_TFD]; @@ -269,9 +323,9 @@ struct iwl_host_cmd { u32 _rx_page_order; u32 flags; + u32 id; u16 len[IWL_MAX_CMD_TBS_PER_TFD]; u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD]; - u8 id; }; static inline void iwl_free_resp(struct iwl_host_cmd *cmd) @@ -372,6 +426,7 @@ enum iwl_trans_status { * @bc_table_dword: set to true if the BC table expects the byte count to be * 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 * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until @@ -389,6 +444,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; + bool wide_cmd_header; const char *const *command_names; u32 sdio_adma_addr; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c980e8d9ac5a..d78af9f0f81b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -977,12 +977,12 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); /* Tx / Host Commands */ int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd); -int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id, u32 flags, u16 len, const void *data); int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, u32 *status); -int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len, const void *data, u32 *status); int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 76b5557c1dde..c9b9c98c6ff8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -469,6 +469,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; + trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_WIDE_CMD_HDR); if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index f50ef822d65e..a7d434256423 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -108,7 +108,7 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) return ret; } -int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id, u32 flags, u16 len, const void *data) { struct iwl_host_cmd cmd = { @@ -182,7 +182,7 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, /* * We assume that the caller set the status to the sucess value */ -int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len, +int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len, const void *data, u32 *status) { struct iwl_host_cmd cmd = { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e27d5a3dcb86..17f65dc89472 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -299,6 +299,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @rx_buf_size_8k: 8 kB RX buffer size * @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 * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw @@ -352,6 +353,7 @@ struct iwl_trans_pcie { bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; + bool wide_cmd_header; u32 rx_page_order; const char *const *command_names; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 4cdfb2fd992a..88ab79fc6249 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1394,6 +1394,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, else trans_pcie->rx_page_order = get_order(4 * 1024); + 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; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 553ae135464a..3a5d54ed494f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1322,13 +1322,23 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, int idx; u16 copy_size, cmd_size, scratch_size; bool had_nocopy = false; + u8 group_id = iwl_cmd_groupid(cmd->id); int i, ret; u32 cmd_pos; const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; - copy_size = sizeof(out_cmd->hdr); - cmd_size = sizeof(out_cmd->hdr); + if (WARN(!trans_pcie->wide_cmd_header && group_id != 0, + "unsupported wide command %#x\n", cmd->id)) + return -EINVAL; + + if (group_id != 0) { + copy_size = sizeof(struct iwl_cmd_header_wide); + cmd_size = sizeof(struct iwl_cmd_header_wide); + } else { + copy_size = sizeof(struct iwl_cmd_header); + cmd_size = sizeof(struct iwl_cmd_header); + } /* need one for the header if the first is NOCOPY */ BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); @@ -1418,16 +1428,32 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_meta->source = cmd; /* set up the header */ - - out_cmd->hdr.cmd = cmd->id; - out_cmd->hdr.reserved = 0; - out_cmd->hdr.sequence = - cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | - INDEX_TO_SEQ(q->write_ptr)); + if (group_id != 0) { + out_cmd->hdr_wide.cmd = iwl_cmd_opcode(cmd->id); + out_cmd->hdr_wide.group_id = group_id; + out_cmd->hdr_wide.version = iwl_cmd_version(cmd->id); + out_cmd->hdr_wide.length = + cpu_to_le16(cmd_size - + sizeof(struct iwl_cmd_header_wide)); + out_cmd->hdr_wide.reserved = 0; + out_cmd->hdr_wide.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | + INDEX_TO_SEQ(q->write_ptr)); + + cmd_pos = sizeof(struct iwl_cmd_header_wide); + copy_size = sizeof(struct iwl_cmd_header_wide); + } else { + out_cmd->hdr.cmd = iwl_cmd_opcode(cmd->id); + out_cmd->hdr.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | + INDEX_TO_SEQ(q->write_ptr)); + out_cmd->hdr.group_id = 0; + + cmd_pos = sizeof(struct iwl_cmd_header); + copy_size = sizeof(struct iwl_cmd_header); + } /* and copy the data that needs to be copied */ - cmd_pos = offsetof(struct iwl_device_cmd, payload); - copy_size = sizeof(out_cmd->hdr); for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { int copy; @@ -1466,9 +1492,10 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } IWL_DEBUG_HC(trans, - "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", + "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", get_cmd_string(trans_pcie, out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + group_id, out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); /* start the TFD with the scratchbuf */ @@ -1523,7 +1550,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, kzfree(txq->entries[idx].free_buf); txq->entries[idx].free_buf = dup_buf; - trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); + trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr_wide); /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr && txq->wd_timeout) -- cgit v1.2.3-70-g09d2 From 88742c9e84f73eeea4abe967d751b0e6318c2c2e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Jun 2015 15:31:22 +0200 Subject: iwlwifi: mvm: move existing UMAC commands to group 1 Existing UMAC commands already use the long header, but are sent with group 0 and the long header inserted manually. Move them to the group 1 to take advantage of the header building in the low- level transport. Existing firmware ignores the group_id field (it's reserved) and the first firmware that really supports long command headers can parse all commands in both group 0 (with short header) and group 1 (with long header.) Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 5 +++++ drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 18 --------------- drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h | 5 ----- drivers/net/wireless/iwlwifi/mvm/scan.c | 22 ++++++++---------- drivers/net/wireless/iwlwifi/mvm/tof.c | 31 ++++++++++---------------- drivers/net/wireless/iwlwifi/pcie/tx.c | 3 ++- 6 files changed, 28 insertions(+), 56 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index df71aa3e6401..8f67004faf4d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -148,6 +148,11 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) return opcode + (groupid << 8) + (version << 16); } +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP 1 + /** * struct iwl_cmd_header * diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 5e4cbdb44c60..4787c32b3a61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -550,18 +550,6 @@ struct iwl_periodic_scan_complete { /* UMAC Scan API */ -/** - * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands - * @size: size of the command (not including header) - * @reserved0: for future use and alignment - * @ver: API version number - */ -struct iwl_mvm_umac_cmd_hdr { - __le16 size; - u8 reserved0; - u8 ver; -} __packed; - /* The maximum of either of these cannot exceed 8, because we use an * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h). */ @@ -621,7 +609,6 @@ enum iwl_channel_flags { /** * struct iwl_scan_config - * @hdr: umac command header * @flags: enum scan_config_flags * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions @@ -639,7 +626,6 @@ enum iwl_channel_flags { * @channel_array: default supported channels */ struct iwl_scan_config { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 flags; __le32 tx_chains; __le32 rx_chains; @@ -734,7 +720,6 @@ struct iwl_scan_req_umac_tail { /** * struct iwl_scan_req_umac - * @hdr: umac command header * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority @@ -753,7 +738,6 @@ struct iwl_scan_req_umac_tail { * &struct iwl_scan_req_umac_tail */ struct iwl_scan_req_umac { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 flags; __le32 uid; __le32 ooc_priority; @@ -775,12 +759,10 @@ struct iwl_scan_req_umac { /** * struct iwl_umac_scan_abort - * @hdr: umac command header * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @flags: reserved */ struct iwl_umac_scan_abort { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 uid; __le32 flags; } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h index 287c9ecb0fb1..eed6271d01a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h @@ -88,7 +88,6 @@ enum iwl_mvm_tof_sub_grp_ids { * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise */ struct iwl_tof_config_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 tof_disabled; u8 one_sided_disabled; @@ -136,7 +135,6 @@ struct iwl_tof_config_cmd { * @bssid: Current AP BSSID */ struct iwl_tof_responder_config_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; __le16 burst_period; u8 min_delta_ftm; @@ -171,7 +169,6 @@ struct iwl_tof_responder_config_cmd { * value to be sent to the AP */ struct iwl_tof_range_req_ext_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; __le16 tsf_timer_offset_msec; __le16 reserved; @@ -273,7 +270,6 @@ enum iwl_tof_response_mode { * Bits set to 1 shall be randomized by the UMAC */ struct iwl_tof_range_req_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 request_id; u8 initiator; @@ -382,7 +378,6 @@ struct iwl_tof_neighbor_report { * @request_id: corresponds to a range request */ struct iwl_tof_range_abort_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 request_id; u8 reserved[3]; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index b891fa54fa4a..d34b2e578358 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -884,9 +884,9 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) int num_channels = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; - int ret, i, j = 0, cmd_size, data_size; + int ret, i, j = 0, cmd_size; struct iwl_host_cmd cmd = { - .id = SCAN_CFG_CMD, + .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), }; if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) @@ -898,8 +898,6 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (!scan_config) return -ENOMEM; - data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); - scan_config->hdr.size = cpu_to_le16(data_size); scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | SCAN_CONFIG_FLAG_SET_TX_CHAINS | @@ -1045,8 +1043,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return uid; memset(cmd, 0, ksize(cmd)); - cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); iwl_mvm_scan_umac_dwell(mvm, cmd, params); @@ -1183,7 +1179,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = SCAN_REQ_UMAC; + hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_REGULAR); } else { @@ -1291,7 +1287,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = SCAN_REQ_UMAC; + hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_SCHED); } else { hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; @@ -1369,10 +1365,7 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) { - struct iwl_umac_scan_abort cmd = { - .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - - sizeof(struct iwl_mvm_umac_cmd_hdr)), - }; + struct iwl_umac_scan_abort cmd = {}; int uid, ret; lockdep_assert_held(&mvm->mutex); @@ -1389,7 +1382,10 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); - ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, + iwl_cmd_id(SCAN_ABORT_UMAC, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(cmd), &cmd); if (!ret) mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c index 5a8e96f0293d..d060e12c3239 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -74,33 +74,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm) memset(tof_data, 0, sizeof(*tof_data)); - tof_data->tof_cfg.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_config_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); #ifdef CONFIG_IWLWIFI_DEBUGFS if (IWL_MVM_TOF_IS_RESPONDER) { - tof_data->responder_cfg.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_responder_config_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->responder_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; } #endif - tof_data->range_req.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_range_req_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); tof_data->range_req.req_timeout = 1; tof_data->range_req.initiator = 1; tof_data->range_req.report_policy = 3; - tof_data->range_req_ext.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_range_req_ext_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->range_req_ext.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); @@ -147,15 +135,15 @@ int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) } mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(*cmd), cmd); } int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) { struct iwl_tof_range_abort_cmd cmd = { .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), - .hdr.size = cpu_to_le16(sizeof(struct iwl_tof_range_abort_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)), .request_id = id, }; @@ -173,7 +161,9 @@ int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) /* after abort is sent there's no active request anymore */ mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(cmd), &cmd); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -194,7 +184,9 @@ int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, } cmd->sta_id = mvmvif->bcast_sta.sta_id; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(*cmd), cmd); } #endif @@ -245,8 +237,9 @@ int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, return -EIO; } - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, - sizeof(mvm->tof_data.range_req_ext), + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(mvm->tof_data.range_req_ext), &mvm->tof_data.range_req_ext); } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 3a5d54ed494f..601eee1ad60b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1328,7 +1328,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; - if (WARN(!trans_pcie->wide_cmd_header && group_id != 0, + if (WARN(!trans_pcie->wide_cmd_header && + group_id > IWL_ALWAYS_LONG_GROUP, "unsupported wide command %#x\n", cmd->id)) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 2d42801bd62eb2018da914272fd505a6d32004a8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 17 Jun 2015 15:32:37 +0300 Subject: Revert "iwlwifi: mvm: move deferred d0i3 exit to resume_complete op" This reverts commit 088070a2f6575402d3dd82e1c5a4a8e1941805f6. When working in d0i3_on_idle mode, we explicitly go out of d0i3 on resume (so other potential commands could be sent). However, D0I3_DEFER_WAKEUP is currently cleared on resume complete (which happens only later on), causing d0i3 exit to timeout. Since mac80211 was modified to accept incoming frames once drv_resume was called, we can safely revert this patch, and handle the pending work on iwl_mvm_resume(). Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 58 +++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 ------- 2 files changed, 43 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 4165d104e4c3..246e60aa2905 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1935,28 +1935,56 @@ out: return 1; } -int iwl_mvm_resume(struct ieee80211_hw *hw) +static int iwl_mvm_resume_d3(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + iwl_trans_resume(mvm->trans); + + return __iwl_mvm_resume(mvm, false); +} + +static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) +{ + bool exit_now; + + /* + * make sure to clear D0I3_DEFER_WAKEUP before + * calling iwl_trans_resume(), which might wait + * for d0i3 exit completion. + */ + mutex_lock(&mvm->d0i3_suspend_mutex); + __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); + exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, + &mvm->d0i3_suspend_flags); + mutex_unlock(&mvm->d0i3_suspend_mutex); + if (exit_now) { + IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); + _iwl_mvm_exit_d0i3(mvm); + } iwl_trans_resume(mvm->trans); - if (mvm->hw->wiphy->wowlan_config->any) { - /* 'any' trigger means d0i3 usage */ - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { - int ret = iwl_mvm_exit_d0i3(hw->priv); + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_exit_d0i3(mvm->hw->priv); - if (ret) - return ret; - /* - * d0i3 exit will be deferred until reconfig_complete. - * make sure there we are out of d0i3. - */ - } - return 0; + if (ret) + return ret; + /* + * d0i3 exit will be deferred until reconfig_complete. + * make sure there we are out of d0i3. + */ } + return 0; +} - return __iwl_mvm_resume(mvm, false); +int iwl_mvm_resume(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + /* 'any' trigger means d0i3 was used */ + if (hw->wiphy->wowlan_config->any) + return iwl_mvm_resume_d0i3(mvm); + else + return iwl_mvm_resume_d3(mvm); } void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index dfdab38e2d4a..45e9913529b2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1433,22 +1433,9 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) { - bool exit_now; - if (!iwl_mvm_is_d0i3_supported(mvm)) return; - mutex_lock(&mvm->d0i3_suspend_mutex); - __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); - exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, - &mvm->d0i3_suspend_flags); - mutex_unlock(&mvm->d0i3_suspend_mutex); - - if (exit_now) { - IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); - _iwl_mvm_exit_d0i3(mvm); - } - 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, -- cgit v1.2.3-70-g09d2 From c43fe907fec2c1925d423777ba14e0baf30c672c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 4 Jun 2015 21:59:32 +0300 Subject: iwlwifi: return error if d0i3 was aborted Allow the transport layer to return an error upon suspend. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 10 ++++++---- drivers/net/wireless/iwlwifi/mvm/d3.c | 8 ++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8f67004faf4d..e698ed5e34cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -598,7 +598,7 @@ struct iwl_trans_ops { u32 value); void (*ref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans); - void (*suspend)(struct iwl_trans *trans); + int (*suspend)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans); struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); @@ -807,10 +807,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) trans->ops->unref(trans); } -static inline void iwl_trans_suspend(struct iwl_trans *trans) +static inline int iwl_trans_suspend(struct iwl_trans *trans) { - if (trans->ops->suspend) - trans->ops->suspend(trans); + if (!trans->ops->suspend) + return 0; + + return trans->ops->suspend(trans); } static inline void iwl_trans_resume(struct iwl_trans *trans) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 246e60aa2905..68d721823645 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1168,13 +1168,17 @@ remove_notif: int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + ret = iwl_trans_suspend(mvm->trans); + if (ret) + return ret; - iwl_trans_suspend(mvm->trans); 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) { - int ret = iwl_mvm_enter_d0i3_sync(mvm); + ret = iwl_mvm_enter_d0i3_sync(mvm); if (ret) return ret; -- cgit v1.2.3-70-g09d2 From d576cd9d599604b9b712939c2ddea0db90463126 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 28 Jun 2015 08:10:46 +0300 Subject: iwlwifi: mvm: update comment of power_scheme module parameter Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d78af9f0f81b..767880b86e23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -123,8 +123,7 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; * be up'ed after the INIT fw asserted. This is useful to be able to use * proprietary tools over testmode to debug the INIT fw. * @tfd_q_hang_detect: enabled the detection of hung transmit queues - * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power - * Save)-2(default), LP(Low Power)-3 + * @power_scheme: one of enum iwl_power_scheme */ struct iwl_mvm_mod_params { bool init_dbg; -- cgit v1.2.3-70-g09d2 From d0ab08d05e5ae84edda5bf86797cbc2daee75db2 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 24 Jun 2015 09:23:01 +0300 Subject: iwlwifi: mvm: Use the AP station for non_sta transmit In iwl_mvm_tx_skb_non_sta(), in case of managed interface, use the AP station for multicast frames instead of the auxiliary station as otherwise the frames can be sent to an absent P2P GO as the FW does not block transmissions for the auxiliary station since it is not associated with the station MAC context. Note that this is not possible for unicast frames, as a TDLS discovery response is sent without a station entry, and in this case the P2P GO NoA should not block transmission to the peer. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index abde484436a8..fa3eaf9a2fc6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -366,18 +366,29 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue; /* - * If the interface on which frame is sent is the P2P_DEVICE + * If the interface on which the frame is sent is the P2P_DEVICE * or an AP/GO interface use the broadcast station associated - * with it; otherwise use the AUX station. + * with it; otherwise if the interface is a managed interface + * use the AP station associated with it for multicast traffic + * (this is not possible for unicast packets as a TLDS discovery + * response are sent without a station entry); otherwise use the + * AUX station. */ - if (info->control.vif && - (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || - info->control.vif->type == NL80211_IFTYPE_AP)) { + sta_id = mvm->aux_sta.sta_id; + if (info->control.vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); - sta_id = mvmvif->bcast_sta.sta_id; - } else { - sta_id = mvm->aux_sta.sta_id; + + if (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || + info->control.vif->type == NL80211_IFTYPE_AP) + sta_id = mvmvif->bcast_sta.sta_id; + else if (info->control.vif->type == NL80211_IFTYPE_STATION && + is_multicast_ether_addr(hdr->addr1)) { + u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); + + if (ap_sta_id != IWL_MVM_STATION_COUNT) + sta_id = ap_sta_id; + } } IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); -- cgit v1.2.3-70-g09d2 From 869f3b15c9fba037956f642b2023fd16d9ee2f56 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 20 Jul 2015 14:16:21 +0300 Subject: iwlwifi: pcie: provide a way to stop configuration if it is forbidden The firmware debug infrastructure allows the user to provide a firmware that will toggle a few registers to configure the debugging capabilities. On certain devices, certain operations are forbidden. Executing a forbidden operation will cause the hardware to die in a way that only driver unload / load will bring it back to life. Fortunately, there is a way to know in advance if those operations will be accepted by the device. This is where the new PRPH_BLOCKBIT operation plays its role. If the bit X from PRPH register Y is set, then we should prevent any further register configuration. When that happens, drop a line in the kernel log since this is really an error state: the user won't have his device configured as he expected. Add operations that will be used in the future: INDIRECT_ASSIGN, INDIRECT_SETBIT, and INDIRECT_CLEARBIT. Other debugging configurations (such as destination configuration for the monitor) will take place in any case. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 6 ++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index f99ec4e22052..884825c70533 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -412,6 +412,12 @@ enum iwl_fw_dbg_reg_operator { PRPH_ASSIGN, PRPH_SETBIT, PRPH_CLEARBIT, + + INDIRECT_ASSIGN, + INDIRECT_SETBIT, + INDIRECT_CLEARBIT, + + PRPH_BLOCKBIT, }; /** diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 88ab79fc6249..46e900e860e8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -881,6 +881,14 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) case PRPH_CLEARBIT: iwl_clear_bits_prph(trans, addr, BIT(val)); break; + case PRPH_BLOCKBIT: + if (iwl_read_prph(trans, addr) & BIT(val)) { + IWL_ERR(trans, + "BIT(%u) in address 0x%x is 1, stopping FW configuration\n", + val, addr); + goto monitor; + } + break; default: IWL_ERR(trans, "FW debug - unknown OP %d\n", dest->reg_ops[i].op); @@ -888,6 +896,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) } } +monitor: if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), trans_pcie->fw_mon_phys >> dest->base_shift); -- cgit v1.2.3-70-g09d2 From 93190fb0589f97bd603bd545459122a8f5532080 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sat, 27 Dec 2014 09:09:47 +0200 Subject: iwlwifi: mvm: Enable Rx Checksum hw TCP software implementation on the host requires extensive computing power. Offloading even some of the TCP/IP stack to the NIC might save a significant overhead. In order to enable this feature on our hw, we need to configure it first. Once done, we mark this capability, to be advertised later to the OS via ieee80211_register_hw. The driver Rx indications for TCP Checksum is integrated within the standard Rx status. The driver responds to those indications as follows: If the frame was tested by hw and checksum ok report CHECKSUM_UNNECESSARY. Otherwise, report CHECKSUM_NONE. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 1 + drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-prph.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 31 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 ++++++++++ drivers/net/wireless/iwlwifi/mvm/rx.c | 17 ++++++++++++++++ 9 files changed, 74 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 0de575124fa2..7caea69570d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -154,6 +154,7 @@ static const struct iwl_tt_params iwl8000_tt_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ .d0i3 = true, \ + .features = NETIF_F_RXCSUM, \ .non_shared_ant = ANT_A, \ .dccm_offset = IWL8260_DCCM_OFFSET, \ .dccm_len = IWL8260_DCCM_LEN, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 08c14afeb148..939fa229c038 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff { * mode set * @d0i3: device uses d0i3 instead of d3 * @nvm_hw_section_num: the ID of the HW NVM section + * @features: hw features, any combination of feature_whitelist * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response @@ -348,6 +349,7 @@ struct iwl_cfg { bool no_power_up_nic_in_init; const char *default_nvm_file_B_step; const char *default_nvm_file_C_step; + netdev_features_t features; unsigned int max_rx_agg_size; bool disable_dummy_notification; unsigned int max_tx_agg_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 884825c70533..926e4568d36c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -297,6 +297,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command + * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different @@ -320,6 +321,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13, IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18, IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index a8469041af09..cd98b9f45415 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -292,6 +292,9 @@ /*********************** END TX SCHEDULER *************************************/ +/* tcp checksum offload */ +#define RX_EN_CSUM (0x00a00d88) + /* Oscillator clock */ #define OSC_CLK (0xa04068) #define OSC_CLK_FORCE_CONTROL (0x8) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 2bc33faae5b4..4e29c11cc969 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1085,10 +1085,33 @@ struct iwl_rx_phy_info { __le16 frame_time; } __packed; +/* + * TCP offload Rx assist info + * + * bits 0:3 - reserved + * bits 4:7 - MIC CRC length + * bits 8:12 - MAC header length + * bit 13 - Padding indication + * bit 14 - A-AMSDU indication + * bit 15 - Offload enabled + */ +enum iwl_csum_rx_assist_info { + CSUM_RXA_RESERVED_MASK = 0x000f, + CSUM_RXA_MICSIZE_MASK = 0x00f0, + CSUM_RXA_HEADERLEN_MASK = 0x1f00, + CSUM_RXA_PADD = BIT(13), + CSUM_RXA_AMSDU = BIT(14), + CSUM_RXA_ENA = BIT(15) +}; + +/** + * struct iwl_rx_mpdu_res_start - phy info + * @assist: see CSUM_RX_ASSIST_ above + */ struct iwl_rx_mpdu_res_start { __le16 byte_count; - __le16 reserved; -} __packed; + __le16 assist; +} __packed; /* _RX_MPDU_RES_START_API_S_VER_2 */ /** * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags @@ -1141,6 +1164,8 @@ enum iwl_rx_phy_flags { * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame + * @RX_MPDU_RES_STATUS_CSUM_DONE: checksum was done by the hw + * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: * @RX_MPDU_RES_STATUS_STA_ID_MSK: * @RX_MPDU_RES_STATUS_RRF_KILL: @@ -1170,6 +1195,8 @@ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), + RX_MPDU_RES_STATUS_CSUM_DONE = BIT(16), + RX_MPDU_RES_STATUS_CSUM_OK = BIT(17), RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000), RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e905c07127fb..ebda61bc66d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -752,6 +752,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + if (iwl_mvm_is_csum_supported(mvm) && + mvm->cfg->features & NETIF_F_RXCSUM) + iwl_trans_write_prph(mvm->trans, RX_EN_CSUM, 0x3); + /* allow FW/transport low power modes if not during restart */ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 45e9913529b2..4264c52aa127 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -649,6 +649,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; } + hw->netdev_features |= mvm->cfg->features; + if (!iwl_mvm_is_csum_supported(mvm)) + hw->netdev_features &= ~NETIF_F_RXCSUM; + ret = ieee80211_register_hw(mvm->hw); if (ret) iwl_mvm_leds_exit(mvm); @@ -1651,6 +1655,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; } + mvmvif->features |= hw->netdev_features; + ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_release; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 767880b86e23..c1f84ec93f40 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -357,6 +357,7 @@ struct iwl_mvm_vif_bf_data { * # of received beacons accumulated over FW restart, and the current * average signal of beacons retrieved from the firmware * @csa_failed: CSA failed to schedule time event, report an error later + * @features: hw features active for this vif */ struct iwl_mvm_vif { struct iwl_mvm *mvm; @@ -437,6 +438,9 @@ struct iwl_mvm_vif { /* Indicates that CSA countdown may be started */ bool csa_countdown; bool csa_failed; + + /* TCP Checksum Offload */ + netdev_features_t features; }; static inline struct iwl_mvm_vif * @@ -943,6 +947,12 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) IWL_MVM_BT_COEX_RRC; } +static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm) +{ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 73054ddc5138..65746145273e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -61,6 +61,7 @@ * (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 "iwl-trans.h" #include "mvm.h" #include "fw-api.h" @@ -234,6 +235,19 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, return 0; } +static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, + struct sk_buff *skb, + u32 status) +{ + 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 && + status & RX_MPDU_RES_STATUS_CSUM_DONE && + status & RX_MPDU_RES_STATUS_CSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + /* * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler * @@ -362,6 +376,9 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) } } + if (sta && ieee80211_is_data(hdr->frame_control)) + iwl_mvm_rx_csum(sta, skb, rx_pkt_status); + rcu_read_unlock(); /* set the preamble flag if appropriate */ -- cgit v1.2.3-70-g09d2 From f739c39ce630c97912a16639bd10231073aef6c8 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 22 Jul 2015 15:46:37 +0300 Subject: iwlwifi: mvm: fix beacon filtering temperature thresholds for D0i3 The slow filtering threshold should be higher in D0i3 case. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index b1baa33cc19b..b86b1697d56f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -413,7 +413,7 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_TEMP_FAST_FILTER_MIN 0 #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 -#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5 +#define IWL_BF_TEMP_SLOW_FILTER_D0I3 20 #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 -- cgit v1.2.3-70-g09d2 From cdc306b2f604d59bb7fb558fadade195f1eb289e Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 20 Jul 2015 12:55:34 +0300 Subject: iwlwifi: mvm: ignore CQM when setting beacon filtering in D0i3 enter flow CQM overwrites a few thresholds in the bf command. On the other hand, when entering D0i3 the thresholds are set to higher values on purpose, so ignore CQM in this case. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 8e2490a1d743..506294fc2f87 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -112,11 +112,12 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, static void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_beacon_filter_cmd *cmd) + struct iwl_beacon_filter_cmd *cmd, + bool d0i3) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (vif->bss_conf.cqm_rssi_thold) { + if (vif->bss_conf.cqm_rssi_thold && !d0i3) { cmd->bf_energy_delta = cpu_to_le32(vif->bss_conf.cqm_rssi_hyst); /* fw uses an absolute value for this */ @@ -807,7 +808,7 @@ static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); + iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd, d0i3); if (!d0i3) iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); -- cgit v1.2.3-70-g09d2 From 6dfb36c89dc21c2c77a4b8ea48679cbb15d158b4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 9 Jul 2015 14:17:24 +0300 Subject: iwlwifi: call d3_suspend/resume in d0i3 case as well Some CSR registers have to be configured also in case of suspend/resume with unified image (which doesn't includes reconfiguration flow). Reuse the existing d3_suspend/d3_resume trans ops, while making sure some configurations are a bit different, according to the wowlan type. After this change, we no longer need the special wowlan_d0i3 configurations done in iwl_pci_resume, as they are already being done in the d3_resume op. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 6 ++++++ drivers/net/wireless/iwlwifi/pcie/drv.c | 13 +++-------- drivers/net/wireless/iwlwifi/pcie/trans.c | 36 +++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 68d721823645..a85be4e9adcd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1187,6 +1187,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) mutex_lock(&mvm->d0i3_suspend_mutex); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); + + iwl_trans_d3_suspend(mvm->trans, false); + return 0; } @@ -1949,6 +1952,9 @@ static int iwl_mvm_resume_d3(struct iwl_mvm *mvm) static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) { bool exit_now; + enum iwl_d3_status d3_status; + + iwl_trans_d3_resume(mvm->trans, &d3_status, false); /* * make sure to clear D0I3_DEFER_WAKEUP before diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbd2a03a0f6d..cdf3a0c33902 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -631,17 +631,10 @@ static int iwl_pci_resume(struct device *device) return 0; /* - * On suspend, ict is disabled, and the interrupt mask - * gets cleared. Reconfigure them both in case of d0i3 - * image. Otherwise, only enable rfkill interrupt (in - * order to keep track of the rfkill status) + * Enable rfkill interrupt (in order to keep track of + * the rfkill status) */ - if (trans->wowlan_d0i3) { - iwl_pcie_reset_ict(trans); - iwl_enable_interrupts(trans); - } else { - iwl_enable_rfkill_int(trans); - } + iwl_enable_rfkill_int(trans); hw_rfkill = iwl_is_rfkill_set(trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 46e900e860e8..cbc29ccc6a00 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1189,6 +1189,12 @@ 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) { + /* Enable persistence mode to avoid reset */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PERSIST_MODE); + } + iwl_disable_interrupts(trans); /* @@ -1207,12 +1213,14 @@ 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); - /* - * reset TX queues -- some of their registers reset during S3 - * so if we don't reset everything here the D3 image would try - * to execute some invalid memory upon resume - */ - iwl_trans_pcie_tx_reset(trans); + if (!trans->wowlan_d0i3) { + /* + * reset TX queues -- some of their registers reset during S3 + * so if we don't reset everything here the D3 image would try + * to execute some invalid memory upon resume + */ + iwl_trans_pcie_tx_reset(trans); + } iwl_pcie_set_pwr(trans, true); } @@ -1254,12 +1262,18 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, false); - iwl_trans_pcie_tx_reset(trans); + if (trans->wowlan_d0i3) { + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + } else { + iwl_trans_pcie_tx_reset(trans); - ret = iwl_pcie_rx_init(trans); - if (ret) { - IWL_ERR(trans, "Failed to resume the device (RX reset)\n"); - return ret; + ret = iwl_pcie_rx_init(trans); + if (ret) { + IWL_ERR(trans, + "Failed to resume the device (RX reset)\n"); + return ret; + } } val = iwl_read32(trans, CSR_RESET); -- cgit v1.2.3-70-g09d2 From 18f5a374b3db33720dc8c66cb94947585904d6c6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 16 Jul 2015 20:17:42 +0300 Subject: iwlwifi: pcie: reset write pointer on ict reset Since the CSR_DRAM_INIT_TBL_WRITE_POINTER bit wasn't set on ict reset, in some flows (like disable ict followed by immediate reset ict) the driver and hardware went out of sync (the driver cleared the ict_index, while the hw kept it intact). Fix it by setting the flag when resetting ict. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/iwlwifi/pcie/rx.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index faa17f2e352a..fa716618735e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -422,6 +422,7 @@ enum { /* DRAM INT TABLE */ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) +#define CSR_DRAM_INIT_TBL_WRITE_POINTER (1 << 28) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) /* diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 5561dee7b62d..454ef1d9a76a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1443,8 +1443,9 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) val = trans_pcie->ict_tbl_dma >> ICT_SHIFT; - val |= CSR_DRAM_INT_TBL_ENABLE; - val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; + val |= CSR_DRAM_INT_TBL_ENABLE | + CSR_DRAM_INIT_TBL_WRAP_CHECK | + CSR_DRAM_INIT_TBL_WRITE_POINTER; IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); -- cgit v1.2.3-70-g09d2 From ca8c0f4bede6098f9d531365d2ad9d7a598327f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2015 17:54:54 +0200 Subject: iwlwifi: mvm: move TX PN assignment for CCMP to the driver Move the TX PN assignment (for CCMP only) to the driver. This prepares the driver for future DSO (driver segmentation offload) where it will split an SKB into multiple MPDUs by itself. For TDLS, split out the CCMP TX command handling so that it won't get a PN assigned, the firmware assigns the PN in that case. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 ++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 15 ++++++++--- drivers/net/wireless/iwlwifi/mvm/tdls.c | 12 ++++++--- drivers/net/wireless/iwlwifi/mvm/tx.c | 41 +++++++++++++++++++---------- 4 files changed, 50 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4264c52aa127..5a4bf84aa260 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2873,10 +2873,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - /* fall-through */ - case WLAN_CIPHER_SUITE_CCMP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; case WLAN_CIPHER_SUITE_AES_CMAC: WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE)); break; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c1f84ec93f40..95f326dc0b1f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1000,10 +1000,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct iwl_tx_cmd *tx_cmd, - struct sk_buff *skb_frag); void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc); @@ -1015,6 +1011,17 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); +static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, + struct iwl_tx_cmd *tx_cmd) +{ + struct ieee80211_key_conf *keyconf = info->control.hw_key; + + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); +} + static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) { flush_work(&mvm->async_handlers_wk); diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index d44d02d16fe2..fe2fa5650443 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -460,13 +460,19 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); info = IEEE80211_SKB_CB(skb); - if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, &cmd.frame.tx_cmd, skb); + hdr = (void *)skb->data; + if (info->control.hw_key) { + if (info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP) { + rcu_read_unlock(); + ret = -EINVAL; + goto out; + } + iwl_mvm_set_tx_cmd_ccmp(info, &cmd.frame.tx_cmd); + } iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info, mvmsta->sta_id); - hdr = (void *)skb->data; iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta, hdr->frame_control); rcu_read_unlock(); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index fa3eaf9a2fc6..eac511aebae0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -268,19 +268,29 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, /* * Sets the fields in the Tx cmd that are crypto related */ -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct iwl_tx_cmd *tx_cmd, - struct sk_buff *skb_frag) +static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info, + struct iwl_tx_cmd *tx_cmd, + struct sk_buff *skb_frag, + int hdrlen) { struct ieee80211_key_conf *keyconf = info->control.hw_key; + u8 *crypto_hdr = skb_frag->data + hdrlen; + u64 pn; switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); + case WLAN_CIPHER_SUITE_CCMP_256: + iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); + pn = atomic64_inc_return(&keyconf->tx_pn); + crypto_hdr[0] = pn; + crypto_hdr[2] = 0; + crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6); + crypto_hdr[1] = pn >> 8; + crypto_hdr[4] = pn >> 16; + crypto_hdr[5] = pn >> 24; + crypto_hdr[6] = pn >> 32; + crypto_hdr[7] = pn >> 40; break; case WLAN_CIPHER_SUITE_TKIP: @@ -308,7 +318,7 @@ void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, */ static struct iwl_device_cmd * iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 sta_id) + int hdrlen, struct ieee80211_sta *sta, u8 sta_id) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -325,7 +335,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb); + iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen); iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); @@ -346,6 +356,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) struct iwl_device_cmd *dev_cmd; struct iwl_tx_cmd *tx_cmd; u8 sta_id; + int hdrlen = ieee80211_hdrlen(hdr->frame_control); if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) return -1; @@ -393,7 +404,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, NULL, sta_id); if (!dev_cmd) return -1; @@ -401,7 +412,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); + memcpy(tx_cmd->hdr, hdr, hdrlen); if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); @@ -427,9 +438,11 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, u8 tid = IWL_MAX_TID_COUNT; u8 txq_id = info->hw_queue; bool is_data_qos = false, is_ampdu = false; + int hdrlen; mvmsta = iwl_mvm_sta_from_mac80211(sta); fc = hdr->frame_control; + hdrlen = ieee80211_hdrlen(fc); if (WARN_ON_ONCE(!mvmsta)) return -1; @@ -437,7 +450,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) return -1; - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, sta, mvmsta->sta_id); if (!dev_cmd) goto drop; @@ -469,7 +482,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, } /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); + memcpy(tx_cmd->hdr, hdr, hdrlen); WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); -- cgit v1.2.3-70-g09d2 From 48ed7040315636f825c989e0752125ea275da82f Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Wed, 8 Jul 2015 11:02:15 -0400 Subject: iwlwifi: make various functions void in the file rs.c This makes various functions in the file rs.c void due to these functions never returning a error code to signal to their callers if and how they have failed to complete their intended work. Signed-off-by: Nicholas Krause Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/rs.c | 51 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 3bd7c86e90d9..cef921c1a623 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -1416,11 +1416,11 @@ static int rs_switch_to_siso(struct iwl_priv *priv, /* * Try to switch to new modulation mode from legacy */ -static int rs_move_legacy_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, - int index) +static void rs_move_legacy_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, + int index) { struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = @@ -1575,7 +1575,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; @@ -1584,17 +1584,15 @@ out: tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - return 0; - } /* * Try to switch to new modulation mode from SISO */ -static int rs_move_siso_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_siso_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { u8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1747,7 +1745,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; @@ -1756,17 +1754,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - - return 0; } /* * Try to switch to new modulation mode from MIMO2 */ -static int rs_move_mimo2_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_mimo2_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1917,7 +1913,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; tbl->action++; @@ -1926,17 +1922,15 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, if (update_search_tbl_counter) search_tbl->action = tbl->action; - return 0; - } /* * Try to switch to new modulation mode from MIMO3 */ -static int rs_move_mimo3_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_mimo3_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -2093,7 +2087,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; tbl->action++; @@ -2101,9 +2095,6 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - - return 0; - } /* -- cgit v1.2.3-70-g09d2 From 6eb031d2fe2d9a3d7eaaba151c64e20bd0220fc9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Jul 2015 14:50:47 +0300 Subject: iwlwifi: add wide firmware command support for notifications Add support for extended command id in notification system. Extended command id header contains group id in addition to command id. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/dvm/rxon.c | 3 ++- drivers/net/wireless/iwlwifi/dvm/ucode.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-notif-wait.c | 8 +++++--- drivers/net/wireless/iwlwifi/iwl-notif-wait.h | 5 +++-- drivers/net/wireless/iwlwifi/iwl-trans.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 2 +- drivers/net/wireless/iwlwifi/mvm/time-event.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/tt.c | 3 ++- 12 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index f603fb3122f7..453f7c315ab5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -444,7 +444,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) u32 error_id; } err_info; struct iwl_notification_wait status_wait; - static const u8 status_cmd[] = { + static const u16 status_cmd[] = { REPLY_WOWLAN_GET_STATUS, }; struct iwlagn_wowlan_status status_data = {}; diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index ed50de6362ed..85ceceb34fcc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 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 @@ -123,7 +124,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, __le32 old_filter = send->filter_flags; u8 old_dev_type = send->dev_type; int ret; - static const u8 deactivate_cmd[] = { + static const u16 deactivate_cmd[] = { REPLY_WIPAN_DEACTIVATION_COMPLETE }; diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 5244e43bfafb..931a8e4269ef 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -3,6 +3,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 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 @@ -327,7 +328,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, const struct fw_img *fw; int ret; enum iwl_ucode_type old_type; - static const u8 alive_cmd[] = { REPLY_ALIVE }; + static const u16 alive_cmd[] = { REPLY_ALIVE }; fw = iwl_get_ucode_image(priv, ucode_type); if (WARN_ON(!fw)) @@ -406,7 +407,7 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait, int iwl_run_init_ucode(struct iwl_priv *priv) { struct iwl_notification_wait calib_wait; - static const u8 calib_complete[] = { + static const u16 calib_complete[] = { CALIBRATION_RES_NOTIFICATION, CALIBRATION_COMPLETE_NOTIFICATION }; diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index b5bc959b1dfe..6caf2affbbb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 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 @@ -98,7 +99,8 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, continue; for (i = 0; i < w->n_cmds; i++) { - if (w->cmds[i] == pkt->hdr.cmd) { + if (w->cmds[i] == + WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) { found = true; break; } @@ -136,7 +138,7 @@ IWL_EXPORT_SYMBOL(iwl_abort_notification_waits); void iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, struct iwl_notification_wait *wait_entry, - const u8 *cmds, int n_cmds, + const u16 *cmds, int n_cmds, bool (*fn)(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data), void *fn_data) @@ -147,7 +149,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, wait_entry->fn = fn; wait_entry->fn_data = fn_data; wait_entry->n_cmds = n_cmds; - memcpy(wait_entry->cmds, cmds, n_cmds); + memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16)); wait_entry->triggered = false; wait_entry->aborted = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 95af97a6c2cf..dbe8234521de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 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 @@ -105,7 +106,7 @@ struct iwl_notification_wait { struct iwl_rx_packet *pkt, void *data); void *fn_data; - u8 cmds[MAX_NOTIF_CMDS]; + u16 cmds[MAX_NOTIF_CMDS]; u8 n_cmds; bool triggered, aborted; }; @@ -121,7 +122,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); void __acquires(wait_entry) iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, struct iwl_notification_wait *wait_entry, - const u8 *cmds, int n_cmds, + const u16 *cmds, int n_cmds, bool (*fn)(struct iwl_notif_wait_data *notif_data, struct iwl_rx_packet *pkt, void *data), void *fn_data); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index e698ed5e34cc..2f79e54823c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -148,6 +148,9 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) return opcode + (groupid << 8) + (version << 16); } +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) ((grp << 8) | opcode) + /* due to the conversion, this group is special; new groups * should be defined in the appropriate fw-api header files */ diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a85be4e9adcd..04264e417c1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1145,7 +1145,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_d3; - static const u8 d3_notif[] = { D3_CONFIG_CMD }; + static const u16 d3_notif[] = { D3_CONFIG_CMD }; int ret; iwl_init_notification_wait(&mvm->notif_wait, &wait_d3, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index ebda61bc66d6..106edc78c8bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -213,7 +213,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, const struct fw_img *fw; int ret, i; enum iwl_ucode_type old_type = mvm->cur_ucode; - static const u8 alive_cmd[] = { MVM_ALIVE }; + static const u16 alive_cmd[] = { MVM_ALIVE }; struct iwl_sf_region st_fwrd_space; if (ucode_type == IWL_UCODE_REGULAR && @@ -314,7 +314,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) { struct iwl_notification_wait calib_wait; - static const u8 init_complete[] = { + static const u16 init_complete[] = { INIT_COMPLETE_NOTIF, CALIB_RES_NOTIF_PHY_DB }; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5a4bf84aa260..9e641847c047 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -3019,7 +3019,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, int res, time_reg = DEVICE_SYSTEM_TIME_REG; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; - static const u8 time_event_response[] = { HOT_SPOT_CMD }; + static const u16 time_event_response[] = { HOT_SPOT_CMD }; struct iwl_notification_wait wait_time_event; struct iwl_hs20_roc_req aux_roc_req = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index d34b2e578358..8d7fefe77ddd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1395,7 +1395,7 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) { struct iwl_notification_wait wait_scan_done; - static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, + static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC, SCAN_OFFLOAD_COMPLETE, }; int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 8fe7ecd75b92..c0d09af5b1f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -500,7 +500,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data, struct iwl_time_event_cmd *te_cmd) { - static const u8 time_event_response[] = { TIME_EVENT_CMD }; + static const u16 time_event_response[] = { TIME_EVENT_CMD }; struct iwl_notification_wait wait_time_event; int ret; @@ -563,7 +563,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; + const u16 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; struct iwl_notification_wait wait_te_notif; struct iwl_time_event_cmd time_cmd = {}; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 7e88d3929119..fe7145c2c98a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -33,6 +33,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 @@ -183,7 +184,7 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) int iwl_mvm_get_temp(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_temp_notif; - static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; + static const u16 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; int ret, temp; lockdep_assert_held(&mvm->mutex); -- cgit v1.2.3-70-g09d2 From 1230b16b448acfdfe7d0cac940311c9363861c03 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 9 Jul 2015 17:17:03 +0300 Subject: iwlwifi: mvm: add wide firmware command infrastructure for RX Add support for extended firmware event header that contains a group id as well as the command id. Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index c9b9c98c6ff8..a424d95a1965 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -201,13 +201,15 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) } struct iwl_rx_handlers { - u8 cmd_id; + u16 cmd_id; bool async; void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; #define RX_HANDLER(_cmd_id, _fn, _async) \ { .cmd_id = _cmd_id , .fn = _fn , .async = _async } +#define RX_HANDLER_GRP(_grp, _cmd, _fn, _async) \ + { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .async = _async } /* * Handlers for fw notifications @@ -263,6 +265,7 @@ 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] = { @@ -735,7 +738,7 @@ static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; struct iwl_async_handler_entry *entry; - if (rx_h->cmd_id != pkt->hdr.cmd) + if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue; if (!rx_h->async) { -- cgit v1.2.3-70-g09d2 From 0ab66e6d28f52677067a905ff2aac3367f8118ee Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Jul 2015 14:23:59 +0300 Subject: iwlwifi: mvm: add wide firmware command support for debug triggers Add support for extended command id in triggers handling. Extended command id header contains group id in addition to command id. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a424d95a1965..6957d026e4bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -703,12 +703,13 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, if (!cmds_trig->cmds[i].cmd_id) break; - if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd) + if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd || + cmds_trig->cmds[i].group_id != pkt->hdr.group_id) continue; iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "CMD 0x%02x received", - pkt->hdr.cmd); + "CMD 0x%02x.%02x received", + pkt->hdr.group_id, pkt->hdr.cmd); break; } } -- cgit v1.2.3-70-g09d2 From a6c4fb4441f4641609bbb3e40da438ed57629db0 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Wed, 15 Jul 2015 16:19:29 +0300 Subject: iwlwifi: mvm: Add FW paging mechanism for the UMAC on PCI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Family 8000 products has 2 embedded processors, the first known as LMAC (lower MAC) and implements the functionality from previous products, the second one is known as UMAC (upper MAC) and is used mainly for driver offloads as well as new features. The UMAC is typically “less” real-time than the LMAC and is used for higher level controls. The UMAC's code/data size is estimated to be in the mega-byte arena, taking into account the code it needs to replace in the driver and the set of new features. In order to allow the UMAC to execute code that is bigger than its code memory, we allow the UMAC embedded processor to page out code pages on DRAM. When the device is master on the bus(PCI) the driver saves the UMAC's image pages in blocks of 32K in the DRAM and sends the layout of the pages to the FW. The FW can load / unload the pages on its own. The driver can support up to 1 MB of pages. Add paging mechanism for the UMAC on PCI in order to allow the program to use a larger virtual space while using less physical memory on the device. Signed-off-by: Eran Harary Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 32 +++- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 4 +- drivers/net/wireless/iwlwifi/iwl-fw.h | 40 +++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 24 +++ drivers/net/wireless/iwlwifi/mvm/fw.c | 258 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 18 +- 8 files changed, 378 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6685259927f8..721d3cb94386 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -573,10 +573,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, size_t len = ucode_raw->size; const u8 *data; u32 tlv_len; + u32 usniffer_img; enum iwl_ucode_tlv_type tlv_type; const u8 *tlv_data; char buildstr[25]; - u32 build; + u32 build, paging_mem_size; int num_of_cpus; bool usniffer_images = false; bool usniffer_req = false; @@ -955,6 +956,35 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_UCODE_REGULAR_USNIFFER, tlv_len); break; + case IWL_UCODE_TLV_PAGING: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + paging_mem_size = le32_to_cpup((__le32 *)tlv_data); + + IWL_DEBUG_FW(drv, + "Paging: paging enabled (size = %u bytes)\n", + paging_mem_size); + + if (paging_mem_size > MAX_PAGING_IMAGE_SIZE) { + IWL_ERR(drv, + "Paging: driver supports up to %lu bytes for paging image\n", + MAX_PAGING_IMAGE_SIZE); + return -EINVAL; + } + + if (paging_mem_size & (FW_PAGING_SIZE - 1)) { + IWL_ERR(drv, + "Paging: image isn't multiple %lu\n", + FW_PAGING_SIZE); + return -EINVAL; + } + + drv->fw.img[IWL_UCODE_REGULAR].paging_mem_size = + paging_mem_size; + usniffer_img = IWL_UCODE_REGULAR_USNIFFER; + drv->fw.img[usniffer_img].paging_mem_size = + paging_mem_size; + break; case IWL_UCODE_TLV_SDIO_ADMA_ADDR: if (tlv_len != sizeof(u32)) goto invalid_tlv_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 926e4568d36c..5d7f2d9cf180 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_API_CHANGES_SET = 29, IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, + IWL_UCODE_TLV_PAGING = 32, IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, IWL_UCODE_TLV_FW_VERSION = 36, @@ -343,8 +344,9 @@ enum iwl_ucode_tlv_capa { * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ -#define IWL_UCODE_SECTION_MAX 12 +#define IWL_UCODE_SECTION_MAX 16 #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC +#define PAGING_SEPARATOR_SECTION 0xAAAABBBB /* uCode version contains 4 values: Major/Minor/API/Serial */ #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 3e3c9d8b3c37..224c7f45d2f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -133,6 +133,7 @@ struct fw_desc { struct fw_img { struct fw_desc sec[IWL_UCODE_SECTION_MAX]; bool is_dual_cpus; + u32 paging_mem_size; }; struct iwl_sf_region { @@ -140,6 +141,45 @@ struct iwl_sf_region { u32 size; }; +/* + * Block paging calculations + */ +#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ +#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */ +#define PAGE_PER_GROUP_2_EXP_SIZE 3 +/* 8 pages per group */ +#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE) +/* don't change, support only 32KB size */ +#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE) +/* 32K == 2^15 */ +#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE) + +/* + * Image paging calculations + */ +#define BLOCK_PER_IMAGE_2_EXP_SIZE 5 +/* 2^5 == 32 blocks per image */ +#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE) +/* maximum image size 1024KB */ +#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) + +#define PAGING_CMD_IS_SECURED BIT(9) +#define PAGING_CMD_IS_ENABLED BIT(8) +#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 +#define PAGING_TLV_SECURE_MASK 1 + +/** + * struct iwl_fw_paging + * @fw_paging_phys: page phy pointer + * @fw_paging_block: pointer to the allocated block + * @fw_paging_size: page size + */ +struct iwl_fw_paging { + dma_addr_t fw_paging_phys; + struct page *fw_paging_block; + u32 fw_paging_size; +}; + /** * struct iwl_fw_cscheme_list - a cipher scheme list * @size: a number of entries diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 4e29c11cc969..9c6b153f2e12 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -149,6 +149,9 @@ enum { LQ_CMD = 0x4e, + /* paging block to FW cpu2 */ + FW_PAGING_BLOCK_CMD = 0x4f, + /* Scan offload */ SCAN_OFFLOAD_REQUEST_CMD = 0x51, SCAN_OFFLOAD_ABORT_CMD = 0x52, @@ -370,6 +373,27 @@ struct iwl_nvm_access_cmd { u8 data[]; } __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ +#define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ + +/* + * struct iwl_fw_paging_cmd - paging layout + * + * (FW_PAGING_BLOCK_CMD = 0x4f) + * + * Send to FW the paging layout in the driver. + * + * @flags: various flags for the command + * @block_size: the block size in powers of 2 + * @block_num: number of blocks specified in the command. + * @device_phy_addr: virtual addresses from device side +*/ +struct iwl_fw_paging_cmd { + __le32 flags; + __le32 block_size; + __le32 block_num; + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ + /** * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD * @offset: offset in bytes into the section diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 106edc78c8bc..acb402b3e6ee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -106,6 +106,244 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) sizeof(tx_ant_cmd), &tx_ant_cmd); } +static void iwl_free_fw_paging(struct iwl_mvm *mvm) +{ + int i; + + if (!mvm->fw_paging_db[0].fw_paging_block) + return; + + for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { + if (!mvm->fw_paging_db[i].fw_paging_block) { + IWL_DEBUG_FW(mvm, + "Paging: block %d already freed, continue to next page\n", + i); + + continue; + } + + __free_pages(mvm->fw_paging_db[i].fw_paging_block, + get_order(mvm->fw_paging_db[i].fw_paging_size)); + } + memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); +} + +static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) +{ + int sec_idx, idx; + u32 offset = 0; + + /* + * find where is the paging image start point: + * if CPU2 exist and it's in paging format, then the image looks like: + * CPU1 sections (2 or more) + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 + * CPU2 sections (not paged) + * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 + * non paged to CPU2 paging sec + * CPU2 paging CSS + * CPU2 paging image (including instruction and data) + */ + for (sec_idx = 0; sec_idx < IWL_UCODE_SECTION_MAX; sec_idx++) { + if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) { + sec_idx++; + break; + } + } + + if (sec_idx >= IWL_UCODE_SECTION_MAX) { + IWL_ERR(mvm, "driver didn't find paging image\n"); + iwl_free_fw_paging(mvm); + return -EINVAL; + } + + /* copy the CSS block to the dram */ + IWL_DEBUG_FW(mvm, "Paging: load paging CSS to FW, sec = %d\n", + sec_idx); + + memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block), + image->sec[sec_idx].data, + mvm->fw_paging_db[0].fw_paging_size); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d CSS bytes to first block\n", + mvm->fw_paging_db[0].fw_paging_size); + + sec_idx++; + + /* + * copy the paging blocks to the dram + * loop index start from 1 since that CSS block already copied to dram + * and CSS index is 0. + * loop stop at num_of_paging_blk since that last block is not full. + */ + for (idx = 1; idx < mvm->num_of_paging_blk; idx++) { + memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), + image->sec[sec_idx].data + offset, + mvm->fw_paging_db[idx].fw_paging_size); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d paging bytes to block %d\n", + mvm->fw_paging_db[idx].fw_paging_size, + idx); + + offset += mvm->fw_paging_db[idx].fw_paging_size; + } + + /* copy the last paging block */ + if (mvm->num_of_pages_in_last_blk > 0) { + memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), + image->sec[sec_idx].data + offset, + FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d pages in the last block %d\n", + mvm->num_of_pages_in_last_blk, idx); + } + + return 0; +} + +static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, + const struct fw_img *image) +{ + struct page *block; + dma_addr_t phys = 0; + int blk_idx = 0; + int order, num_of_pages; + int dma_enabled; + + if (mvm->fw_paging_db[0].fw_paging_block) + return 0; + + dma_enabled = is_device_dma_capable(mvm->trans->dev); + + /* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */ + BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE); + + num_of_pages = image->paging_mem_size / FW_PAGING_SIZE; + mvm->num_of_paging_blk = ((num_of_pages - 1) / + NUM_OF_PAGE_PER_GROUP) + 1; + + mvm->num_of_pages_in_last_blk = + num_of_pages - + NUM_OF_PAGE_PER_GROUP * (mvm->num_of_paging_blk - 1); + + IWL_DEBUG_FW(mvm, + "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", + mvm->num_of_paging_blk, + mvm->num_of_pages_in_last_blk); + + /* allocate block of 4Kbytes for paging CSS */ + order = get_order(FW_PAGING_SIZE); + block = alloc_pages(GFP_KERNEL, order); + if (!block) { + /* free all the previous pages since we failed */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + + mvm->fw_paging_db[blk_idx].fw_paging_block = block; + mvm->fw_paging_db[blk_idx].fw_paging_size = FW_PAGING_SIZE; + + if (dma_enabled) { + phys = dma_map_page(mvm->trans->dev, block, 0, + PAGE_SIZE << order, DMA_BIDIRECTIONAL); + if (dma_mapping_error(mvm->trans->dev, phys)) { + /* + * free the previous pages and the current one since + * we failed to map_page. + */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } + + IWL_DEBUG_FW(mvm, + "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n", + order); + + /* + * allocate blocks in dram. + * since that CSS allocated in fw_paging_db[0] loop start from index 1 + */ + for (blk_idx = 1; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { + /* allocate block of PAGING_BLOCK_SIZE (32K) */ + order = get_order(PAGING_BLOCK_SIZE); + block = alloc_pages(GFP_KERNEL, order); + if (!block) { + /* free all the previous pages since we failed */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + + mvm->fw_paging_db[blk_idx].fw_paging_block = block; + mvm->fw_paging_db[blk_idx].fw_paging_size = PAGING_BLOCK_SIZE; + + if (dma_enabled) { + phys = dma_map_page(mvm->trans->dev, block, 0, + PAGE_SIZE << order, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(mvm->trans->dev, phys)) { + /* + * free the previous pages and the current one + * since we failed to map_page. + */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } + + IWL_DEBUG_FW(mvm, + "Paging: allocated 32K bytes (order %d) for firmware paging.\n", + order); + } + + return 0; +} + +static int iwl_save_fw_paging(struct iwl_mvm *mvm, + const struct fw_img *fw) +{ + int ret; + + ret = iwl_alloc_fw_paging_mem(mvm, fw); + if (ret) + return ret; + + return iwl_fill_paging_mem(mvm, fw); +} + +/* send paging cmd to FW in case CPU2 has paging image */ +static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) +{ + int blk_idx; + __le32 dev_phy_addr; + struct iwl_fw_paging_cmd fw_paging_cmd = { + .flags = + cpu_to_le32(PAGING_CMD_IS_SECURED | + PAGING_CMD_IS_ENABLED | + (mvm->num_of_pages_in_last_blk << + PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), + .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), + .block_num = cpu_to_le32(mvm->num_of_paging_blk), + }; + + /* loop for for all paging blocks + CSS block */ + for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { + dev_phy_addr = + cpu_to_le32(mvm->fw_paging_db[blk_idx].fw_paging_phys >> + PAGE_2_EXP_SIZE); + fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr; + } + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(fw_paging_cmd), &fw_paging_cmd); +} + static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -268,6 +506,26 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); + /* + * configure and operate fw paging mechanism. + * driver configures the paging flow only once, CPU2 paging image + * included in the IWL_UCODE_INIT image. + */ + if (fw->paging_mem_size) { + ret = iwl_save_fw_paging(mvm, fw); + if (ret) { + IWL_ERR(mvm, "failed to save the FW paging image\n"); + return ret; + } + + ret = iwl_send_paging_cmd(mvm, fw); + if (ret) { + IWL_ERR(mvm, "failed to send the paging cmd\n"); + iwl_free_fw_paging(mvm); + return ret; + } + } + /* * Note: all the queues are enabled as part of the interface * initialization, but in firmware restart scenarios they diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 95f326dc0b1f..fdf401b696a4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -610,6 +610,11 @@ struct iwl_mvm { /* NVM sections */ struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; + /* Paging section */ + struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS]; + u16 num_of_paging_blk; + u16 num_of_pages_in_last_blk; + /* EEPROM MAC addresses */ struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 6957d026e4bd..ef09a05b6ddb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -288,6 +288,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { 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(REMOVE_STA), diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index cbc29ccc6a00..8cc8f2b703a2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -764,8 +764,15 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { last_read_idx = i; + /* + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between + * CPU1 to CPU2. + * PAGING_SEPARATOR_SECTION delimiter - separate between + * CPU2 non paged to CPU2 paging sec. + */ if (!image->sec[i].data || - image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || + image->sec[i].offset == PAGING_SEPARATOR_SECTION) { IWL_DEBUG_FW(trans, "Break since Data not valid or Empty section, sec = %d\n", i); @@ -813,8 +820,15 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { last_read_idx = i; + /* + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between + * CPU1 to CPU2. + * PAGING_SEPARATOR_SECTION delimiter - separate between + * CPU2 non paged to CPU2 paging sec. + */ if (!image->sec[i].data || - image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || + image->sec[i].offset == PAGING_SEPARATOR_SECTION) { IWL_DEBUG_FW(trans, "Break since Data not valid or Empty section, sec = %d\n", i); -- cgit v1.2.3-70-g09d2 From 75118fdb63496e4611ab50380499ddd62b9de69f Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 24 Jun 2015 11:03:56 +0300 Subject: iwlwifi: mvm: clean up fw-api-scan.h Remove outdated and unused definitions Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 129 ------------------------- 1 file changed, 129 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 4787c32b3a61..be9b66560801 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -87,41 +87,6 @@ struct iwl_ssid_ie { u8 ssid[IEEE80211_MAX_SSID_LEN]; } __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ -/* How many statistics are gathered for each channel */ -#define SCAN_RESULTS_STATISTICS 1 - -/** - * enum iwl_scan_complete_status - status codes for scan complete notifications - * @SCAN_COMP_STATUS_OK: scan completed successfully - * @SCAN_COMP_STATUS_ABORT: scan was aborted by user - * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed - * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready - * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed - * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed - * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command - * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort - * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax - * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful - * (not an error!) - * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repetition the driver - * asked for - * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events -*/ -enum iwl_scan_complete_status { - SCAN_COMP_STATUS_OK = 0x1, - SCAN_COMP_STATUS_ABORT = 0x2, - SCAN_COMP_STATUS_ERR_SLEEP = 0x3, - SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, - SCAN_COMP_STATUS_ERR_PROBE = 0x5, - SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, - SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, - SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, - SCAN_COMP_STATUS_ERR_COEX = 0x9, - SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, - SCAN_COMP_STATUS_ITERATION_END = 0x0B, - SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, -}; - /* scan offload */ #define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 @@ -143,71 +108,6 @@ enum scan_framework_client { SCAN_CLIENT_ASSET_TRACKING = BIT(2), }; -/** - * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 - * @scan_flags: see enum iwl_scan_flags - * @channel_count: channels in channel list - * @quiet_time: dwell time, in milliseconds, on quiet channel - * @quiet_plcp_th: quiet channel num of packets threshold - * @good_CRC_th: passive to active promotion threshold - * @rx_chain: RXON rx chain. - * @max_out_time: max TUs to be out of associated channel - * @suspend_time: pause scan this TUs when returning to service channel - * @flags: RXON flags - * @filter_flags: RXONfilter - * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz. - * @direct_scan: list of SSIDs for directed active scan - * @scan_type: see enum iwl_scan_type. - * @rep_count: repetition count for each scheduled scan iteration. - */ -struct iwl_scan_offload_cmd { - __le16 len; - u8 scan_flags; - u8 channel_count; - __le16 quiet_time; - __le16 quiet_plcp_th; - __le16 good_CRC_th; - __le16 rx_chain; - __le32 max_out_time; - __le32 suspend_time; - /* RX_ON_FLAGS_API_S_VER_1 */ - __le32 flags; - __le32 filter_flags; - struct iwl_tx_cmd tx_cmd[2]; - /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; - __le32 scan_type; - __le32 rep_count; -} __packed; - -enum iwl_scan_offload_channel_flags { - IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE = BIT(0), - IWL_SCAN_OFFLOAD_CHANNEL_NARROW = BIT(22), - IWL_SCAN_OFFLOAD_CHANNEL_FULL = BIT(24), - IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), -}; - -/* channel configuration for struct iwl_scan_offload_cfg. Each channels needs: - * __le32 type: bitmap; bits 1-20 are for directed scan to i'th ssid and - * see enum iwl_scan_offload_channel_flags. - * __le16 channel_number: channel number 1-13 etc. - * __le16 iter_count: repetition count for the channel. - * __le32 iter_interval: interval between two iterations on one channel. - * u8 active_dwell. - * u8 passive_dwell. - */ -#define IWL_SCAN_CHAN_SIZE 14 - -/** - * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S - * @scan_cmd: scan command fixed part - * @data: scan channel configuration and probe request frames - */ -struct iwl_scan_offload_cfg { - struct iwl_scan_offload_cmd scan_cmd; - u8 data[0]; -} __packed; - /** * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out @@ -297,35 +197,6 @@ enum iwl_scan_ebs_status { IWL_SCAN_EBS_INACTIVE, }; -/** - * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 - * @last_schedule_line: last schedule line executed (fast or regular) - * @last_schedule_iteration: last scan iteration executed before scan abort - * @status: enum iwl_scan_offload_compleate_status - * @ebs_status: last EBS status, see IWL_SCAN_EBS_* - */ -struct iwl_scan_offload_complete { - u8 last_schedule_line; - u8 last_schedule_iteration; - u8 status; - u8 ebs_status; -} __packed; - -/** - * iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1 - * @ssid_bitmap: SSIDs indexes found in this iteration - * @client_bitmap: clients that are active and wait for this notification - */ -struct iwl_sched_scan_results { - __le16 ssid_bitmap; - u8 client_bitmap; - u8 reserved; -}; - -/* Unified LMAC scan API */ - -#define IWL_MVM_BASIC_PASSIVE_DWELL 110 - /** * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* -- cgit v1.2.3-70-g09d2 From 192de2b406ab5cab0b87be6d8015dcfbec936e37 Mon Sep 17 00:00:00 2001 From: Dor Shaish Date: Wed, 15 Jul 2015 11:41:21 +0300 Subject: iwlwifi: mvm: print secboot status registers on alive timeout Print the CPU1 and CPU2 secured boot status registers from the NIC to indicate a SYSASSERT during secured engine unlocking process on init/protocol image. Signed-off-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw.c | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index cd98b9f45415..c4e7a713af0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -383,6 +383,8 @@ enum aux_misc_master1_en { #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define RSA_ENABLE 0xA24B08 #define PREG_AUX_BUS_WPROT_0 0xA04CC0 +#define SB_CPU_1_STATUS 0xA01E30 +#define SB_CPU_2_STATUS 0xA01E34 /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index acb402b3e6ee..e65a65337792 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -482,6 +482,11 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, MVM_UCODE_ALIVE_TIMEOUT); if (ret) { + if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + IWL_ERR(mvm, + "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", + iwl_read_prph(mvm->trans, SB_CPU_1_STATUS), + iwl_read_prph(mvm->trans, SB_CPU_2_STATUS)); mvm->cur_ucode = old_type; return ret; } -- cgit v1.2.3-70-g09d2 From bd7fc617af118531e364d727ed02b0ded2bb4fc0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Jul 2015 23:15:08 +0300 Subject: iwlwifi: pcie: dump RBs when FW error occurs Add support for dumping all the RBs in the RX queue when FW error occurs. This will assist debugging. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 17 +++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 59 +++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index e57dbd0ef2e1..af5b3201492c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -84,6 +84,8 @@ * @IWL_FW_ERROR_DUMP_MEM: chunk of memory * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. * Structured as &struct iwl_fw_error_dump_trigger_desc. + * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as + * &struct iwl_fw_error_dump_rb */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -97,6 +99,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_FH_REGS = 8, IWL_FW_ERROR_DUMP_MEM = 9, IWL_FW_ERROR_DUMP_ERROR_INFO = 10, + IWL_FW_ERROR_DUMP_RB = 11, IWL_FW_ERROR_DUMP_MAX, }; @@ -222,6 +225,20 @@ struct iwl_fw_error_dump_mem { u8 data[]; }; +/** + * struct iwl_fw_error_dump_rb - content of an Receive Buffer + * @index: the index of the Receive Buffer in the Rx queue + * @rxq: the RB's Rx queue + * @reserved: + * @data: the content of the Receive Buffer + */ +struct iwl_fw_error_dump_rb { + __le32 index; + __le32 rxq; + __le32 reserved; + u8 data[]; +}; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 8cc8f2b703a2..9ebdd8009717 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2275,6 +2275,47 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, return prph_len; } +static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data, + int allocated_rb_nums) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int max_len = PAGE_SIZE << trans_pcie->rx_page_order; + struct iwl_rxq *rxq = &trans_pcie->rxq; + u32 i, r, j, rb_len = 0; + + spin_lock(&rxq->lock); + + r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; + + for (i = rxq->read, j = 0; + i != r && j < allocated_rb_nums; + i = (i + 1) & RX_QUEUE_MASK, j++) { + struct iwl_rx_mem_buffer *rxb = rxq->queue[i]; + struct iwl_fw_error_dump_rb *rb; + + dma_unmap_page(trans->dev, rxb->page_dma, max_len, + DMA_FROM_DEVICE); + + rb_len += sizeof(**data) + sizeof(*rb) + max_len; + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RB); + (*data)->len = cpu_to_le32(sizeof(*rb) + max_len); + rb = (void *)(*data)->data; + rb->index = cpu_to_le32(i); + memcpy(rb->data, page_address(rxb->page), max_len); + /* remap the page for the free benefit */ + rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, + max_len, + DMA_FROM_DEVICE); + + *data = iwl_fw_error_next_data(*data); + } + + spin_unlock(&rxq->lock); + + return rb_len; +} #define IWL_CSR_TO_DUMP (0x250) static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, @@ -2352,9 +2393,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_fw_error_dump_txcmd *txcmd; struct iwl_trans_dump_data *dump_data; - u32 len; + u32 len, num_rbs; u32 monitor_len; int i, ptr; + bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status); /* transport dump header */ len = sizeof(*dump_data); @@ -2379,6 +2421,17 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) /* FH registers */ len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + if (dump_rbs) { + /* RBs */ + num_rbs = le16_to_cpu(ACCESS_ONCE( + trans_pcie->rxq.rb_stts->closed_rb_num)) + & 0x0FFF; + num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; + len += num_rbs * (sizeof(*data) + + sizeof(struct iwl_fw_error_dump_rb) + + (PAGE_SIZE << trans_pcie->rx_page_order)); + } + /* FW monitor */ if (trans_pcie->fw_mon_page) { len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + @@ -2442,8 +2495,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) len += iwl_trans_pcie_dump_prph(trans, &data); len += iwl_trans_pcie_dump_csr(trans, &data); len += iwl_trans_pcie_fh_regs_dump(trans, &data); - /* data is already pointing to the next section */ + if (dump_rbs) + len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); + /* data is already pointing to the next section */ if ((trans_pcie->fw_mon_page && trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || trans->dbg_dest_tlv) { -- cgit v1.2.3-70-g09d2 From be681c7d103c4b3df5c51acaba5a578002a16488 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 18 Jun 2015 06:39:41 +0300 Subject: iwlwifi: mvm: revert to our old skip over dtim policy Our firmware scheduler used to suffer from false wake-up on 500 time units. We had to came up with a formula to address this buggy behavior. Now that our firmware is fixed, we can go back to our old policy. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 506294fc2f87..c4e08903366c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -288,27 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, return true; } -static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) -{ - int numerator; - int dtim_interval = dtimper * bi; - - if (WARN_ON(!dtim_interval)) - return 0; - - if (dtimper == 1) { - if (bi > 100) - numerator = 408; - else - numerator = 510; - } else if (dtimper < 10) { - numerator = 612; - } else { - return 0; - } - return max(1, (numerator / dtim_interval)); -} - static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) { struct ieee80211_chanctx_conf *chanctx_conf; @@ -378,11 +357,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, if (!radar_detect && (dtimper < 10) && (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || mvm->cur_ucode == IWL_UCODE_WOWLAN)) { - cmd->skip_dtim_periods = - iwl_mvm_power_get_skip_over_dtim(dtimper, bi); - if (cmd->skip_dtim_periods) - cmd->flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd->skip_dtim_periods = 3; } if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { -- cgit v1.2.3-70-g09d2 From 9d012d0dbee1dcc4f7491925de41b4249b2cfb31 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Thu, 4 Jun 2015 10:32:43 +0300 Subject: iwlwifi: Add max TX aggregation size for 8260 SDIO devices series Set max TX aggregation size for 8260 SDIO devices series to 40 frames. Fine tune max RX aggregation size - change it to 21. Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 7caea69570d4..92709ad5de44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -97,8 +97,9 @@ #define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B" #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" -/* Max SDIO RX aggregation size of the ADDBA request/response */ -#define MAX_RX_AGG_SIZE_8260_SDIO 28 +/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ +#define MAX_RX_AGG_SIZE_8260_SDIO 21 +#define MAX_TX_AGG_SIZE_8260_SDIO 40 /* Max A-MPDU exponent for HT and VHT */ #define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K @@ -204,6 +205,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, @@ -217,6 +219,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, .bt_shared_single_ant = true, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, -- cgit v1.2.3-70-g09d2 From 17564dde6024fcfe74cc0512e7837175aa5283d9 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Sun, 22 Mar 2015 13:11:01 +0200 Subject: iwlwifi: add new TLV capability flag for gscan support Gscan is a scan feature which is supported on certain devices only, hence the need for a TLV flag for it. For devices that support gscan store the gscan capabilities advertised by the FW so the driver can report it to upper layers. Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 40 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 27 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw.h | 25 +++++++++++++++++++ 3 files changed, 92 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 721d3cb94386..a86aa5bcee7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -372,6 +372,30 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) return 0; } +static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, + const u32 len) +{ + struct iwl_fw_gscan_capabilities *fw_capa = (void *)data; + struct iwl_gscan_capabilities *capa = &fw->gscan_capa; + + if (len < sizeof(*fw_capa)) + return -EINVAL; + + capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size); + capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets); + capa->max_ap_cache_per_scan = + le32_to_cpu(fw_capa->max_ap_cache_per_scan); + capa->max_rssi_sample_size = le32_to_cpu(fw_capa->max_rssi_sample_size); + capa->max_scan_reporting_threshold = + le32_to_cpu(fw_capa->max_scan_reporting_threshold); + capa->max_hotlist_aps = le32_to_cpu(fw_capa->max_hotlist_aps); + capa->max_significant_change_aps = + le32_to_cpu(fw_capa->max_significant_change_aps); + capa->max_bssid_history_entries = + le32_to_cpu(fw_capa->max_bssid_history_entries); + return 0; +} + /* * Gets uCode section from tlv. */ @@ -581,6 +605,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, int num_of_cpus; bool usniffer_images = false; bool usniffer_req = false; + bool gscan_capa = false; if (len < sizeof(*ucode)) { IWL_ERR(drv, "uCode has invalid length: %zd\n", len); @@ -991,6 +1016,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, drv->fw.sdio_adma_addr = le32_to_cpup((__le32 *)tlv_data); break; + case IWL_UCODE_TLV_FW_GSCAN_CAPA: + if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len)) + goto invalid_tlv_len; + gscan_capa = true; + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -1009,6 +1039,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -EINVAL; } + /* + * If ucode advertises that it supports GSCAN but GSCAN + * capabilities TLV is not present, warn and continue without GSCAN. + */ + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && + WARN(!gscan_capa, + "GSCAN is supported but capabilities TLV is unavailable\n")) + __clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT, + capa->_capa); + return 0; invalid_tlv_len: diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 5d7f2d9cf180..d1c5b90eb6b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -139,6 +139,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_DBG_DEST = 38, IWL_UCODE_TLV_FW_DBG_CONF = 39, IWL_UCODE_TLV_FW_DBG_TRIGGER = 40, + IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, }; struct iwl_ucode_tlv { @@ -306,6 +307,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR * is supported. * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC + * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan */ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, @@ -327,6 +329,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, + IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, }; /* The default calibrate table size if not specified by firmware file */ @@ -728,4 +731,28 @@ struct iwl_fw_dbg_conf_tlv { struct iwl_fw_dbg_conf_hcmd hcmd; } __packed; +/** + * struct iwl_fw_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + */ +struct iwl_fw_gscan_capabilities { + __le32 max_scan_cache_size; + __le32 max_scan_buckets; + __le32 max_ap_cache_per_scan; + __le32 max_rssi_sample_size; + __le32 max_scan_reporting_threshold; + __le32 max_hotlist_aps; + __le32 max_significant_change_aps; + __le32 max_bssid_history_entries; +} __packed; + #endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 224c7f45d2f1..0d9d6f51766e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -190,6 +190,30 @@ struct iwl_fw_cscheme_list { struct iwl_fw_cipher_scheme cs[]; } __packed; +/** + * struct iwl_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + */ +struct iwl_gscan_capabilities { + u32 max_scan_cache_size; + u32 max_scan_buckets; + u32 max_ap_cache_per_scan; + u32 max_rssi_sample_size; + u32 max_scan_reporting_threshold; + u32 max_hotlist_aps; + u32 max_significant_change_aps; + u32 max_bssid_history_entries; +}; + /** * struct iwl_fw - variables associated with the firmware * @@ -248,6 +272,7 @@ struct iwl_fw { struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; u8 dbg_dest_reg_num; + struct iwl_gscan_capabilities gscan_capa; }; static inline const char *get_fw_dbg_mode_string(int mode) -- cgit v1.2.3-70-g09d2 From 206eea7833859f9e39c8a7439196743a2d8dfc9b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Apr 2015 16:38:31 +0200 Subject: iwlwifi: pcie: support frag SKBs Allow frag SKBs in PCIe and advertise the maximum number of frags to the opmode. As a fallback. linearize the SKB if it exceeds the maximum number of fragments. This allows using the hardware better (filling more TBs) and should improve performance when used by the opmode. Also adjust tracing to be able to deal with this. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-devtrace-data.h | 7 ++- drivers/net/wireless/iwlwifi/iwl-trans.h | 7 +++ drivers/net/wireless/iwlwifi/pcie/internal.h | 6 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 2 + drivers/net/wireless/iwlwifi/pcie/tx.c | 70 ++++++++++++++++++++---- 5 files changed, 77 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h index 04e6649340b8..71a78cede9b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h @@ -35,8 +35,8 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_PROTO(const struct device *dev, struct sk_buff *skb, - void *data, size_t data_len), - TP_ARGS(dev, skb, data, data_len), + u8 hdr_len, size_t data_len), + TP_ARGS(dev, skb, hdr_len, data_len), TP_STRUCT__entry( DEV_ENTRY @@ -45,7 +45,8 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_fast_assign( DEV_ASSIGN; if (iwl_trace_data(skb)) - memcpy(__get_dynamic_array(data), data, data_len); + skb_copy_bits(skb, hdr_len, + __get_dynamic_array(data), data_len); ), TP_printk("[%s] TX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 2f79e54823c4..e68497acf9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -248,6 +248,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_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. */ enum CMD_MODE { CMD_ASYNC = BIT(0), @@ -257,6 +259,8 @@ enum CMD_MODE { CMD_SEND_IN_IDLE = BIT(4), CMD_MAKE_TRANS_IDLE = BIT(5), CMD_WAKE_UP_TRANS = BIT(6), + + CMD_TB_BITMAP_POS = 11, }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -641,6 +645,8 @@ enum iwl_d0i3_mode { * @cfg - pointer to the configuration * @status: a bit-mask of transport status flags * @dev - pointer to struct device * that represents the device + * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. + * 0 indicates that frag SKBs (NETIF_F_SG) aren't supported. * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. @@ -669,6 +675,7 @@ struct iwl_trans { unsigned long status; struct device *dev; + u32 max_skb_frags; u32 hw_rev; u32 hw_id; char hw_id_str[52]; diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 17f65dc89472..feb2f7e81134 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -44,6 +44,12 @@ #include "iwl-io.h" #include "iwl-op-mode.h" +/* We need 2 entries for the TX command and header, and another one might + * be needed for potential data in the SKB's head. The remaining ones can + * be used for frags. + */ +#define IWL_PCIE_MAX_FRAGS (IWL_NUM_OF_TBS - 3) + /* * RX related structures and functions */ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9ebdd8009717..fb55810f5aae 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2627,6 +2627,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, if (!trans) return ERR_PTR(-ENOMEM); + trans->max_skb_frags = IWL_PCIE_MAX_FRAGS; + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->trans = trans; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 601eee1ad60b..b7d1268bf969 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -388,11 +388,18 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, /* first TB is never freed - it's the scratchbuf data */ - for (i = 1; i < num_tbs; i++) - dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), - iwl_pcie_tfd_tb_get_len(tfd, i), - DMA_TO_DEVICE); - + for (i = 1; i < num_tbs; i++) { + if (meta->flags & BIT(i + CMD_TB_BITMAP_POS)) + dma_unmap_page(trans->dev, + iwl_pcie_tfd_tb_get_addr(tfd, i), + iwl_pcie_tfd_tb_get_len(tfd, i), + DMA_TO_DEVICE); + else + dma_unmap_single(trans->dev, + iwl_pcie_tfd_tb_get_addr(tfd, i), + iwl_pcie_tfd_tb_get_len(tfd, i), + DMA_TO_DEVICE); + } tfd->num_tbs = 0; } @@ -468,7 +475,7 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); - return 0; + return num_tbs; } static int iwl_pcie_txq_alloc(struct iwl_trans *trans, @@ -1546,6 +1553,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], false); } + BUILD_BUG_ON(IWL_NUM_OF_TBS + CMD_TB_BITMAP_POS > + sizeof(out_meta->flags) * BITS_PER_BYTE); out_meta->flags = cmd->flags; if (WARN_ON_ONCE(txq->entries[idx].free_buf)) kzfree(txq->entries[idx].free_buf); @@ -1789,7 +1798,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr; struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_txq *txq; @@ -1798,9 +1807,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, void *tb1_addr; u16 len, tb1_len, tb2_len; bool wait_write_ptr; - __le16 fc = hdr->frame_control; - u8 hdr_len = ieee80211_hdrlen(fc); + __le16 fc; + u8 hdr_len; u16 wifi_seq; + int i; txq = &trans_pcie->txq[txq_id]; q = &txq->q; @@ -1809,6 +1819,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, "TX on unused queue %d\n", txq_id)) return -EINVAL; + if (skb_is_nonlinear(skb) && + skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS && + __skb_linearize(skb)) + return -ENOMEM; + + /* mac80211 always puts the full header into the SKB's head, + * so there's no need to check if it's readable there + */ + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + hdr_len = ieee80211_hdrlen(fc); + spin_lock(&txq->lock); /* In AGG mode, the index in the ring must correspond to the WiFi @@ -1839,6 +1861,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[q->write_ptr].meta; + out_meta->flags = 0; /* * The second TB (tb1) points to the remainder of the TX command @@ -1872,9 +1895,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* * Set up TFD's third entry to point directly to remainder - * of skb, if any (802.11 null frames have no payload). + * of skb's head, if any */ - tb2_len = skb->len - hdr_len; + 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, @@ -1887,6 +1910,29 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, 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); + } + /* 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)); @@ -1896,7 +1942,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, skb->data + hdr_len, tb2_len); trace_iwlwifi_dev_tx_data(trans->dev, skb, - skb->data + hdr_len, tb2_len); + hdr_len, skb->len - hdr_len); wait_write_ptr = ieee80211_has_morefrags(fc); -- cgit v1.2.3-70-g09d2 From 36fb90172688c8eeac67e1ef01d232549c9a6131 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 15 Jul 2015 15:47:28 +0300 Subject: iwlwifi: mvm: add the ability to trigger only monitor dumps Change the FW debug trigger tlv to include a monitor only option. Setting this option to true will cause fw dump triggers to only collect monitor data and skip other dumps such as SMEM, SRAM, CSR, PRPH, etc. This option is used when accessing the different parts of the firmware memory is not wanted and can cause unwanted behavior like when debugging TX latency. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 3 + drivers/net/wireless/iwlwifi/iwl-trans.h | 9 +- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 19 ++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 36 +++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 217 ++++++++++++++++------------ 8 files changed, 177 insertions(+), 118 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index d1c5b90eb6b4..75809abee759 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -498,10 +498,13 @@ struct iwl_fw_dbg_conf_hcmd { * * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data + * @IWL_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to + * collect only monitor data */ enum iwl_fw_dbg_trigger_mode { IWL_FW_DBG_TRIGGER_START = BIT(0), IWL_FW_DBG_TRIGGER_STOP = BIT(1), + IWL_FW_DBG_TRIGGER_MONITOR_ONLY = BIT(2), }; /** diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index e68497acf9b3..151e3de2247f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -608,7 +608,9 @@ struct iwl_trans_ops { int (*suspend)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans); - struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); + struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv + *trigger); }; /** @@ -832,11 +834,12 @@ static inline void iwl_trans_resume(struct iwl_trans *trans) } static inline struct iwl_trans_dump_data * -iwl_trans_dump_data(struct iwl_trans *trans) +iwl_trans_dump_data(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv *trigger) { if (!trans->ops->dump_data) return NULL; - return trans->ops->dump_data(trans); + return trans->ops->dump_data(trans, trigger); } static inline int iwl_trans_send_cmd(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ffb4b5cef275..17d7a05006fa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -974,7 +974,7 @@ 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, 0); + iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, NULL); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e65a65337792..aff5bbf3f141 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -735,8 +735,13 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, struct iwl_mvm_dump_desc *desc, - unsigned int delay) + struct iwl_fw_dbg_trigger_tlv *trigger) { + unsigned int delay = 0; + + if (trigger) + delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); + if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) return -EBUSY; @@ -747,6 +752,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, le32_to_cpu(desc->trig_desc.type)); mvm->fw_dump_desc = desc; + mvm->fw_dump_trig = trigger; queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); @@ -754,7 +760,8 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, } int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, unsigned int delay) + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_mvm_dump_desc *desc; @@ -766,14 +773,13 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay); + return iwl_mvm_fw_dbg_collect_desc(mvm, desc, trigger); } int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) { - unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); u16 occurrences = le16_to_cpu(trigger->occurrences); int ret, len = 0; char buf[64]; @@ -797,8 +803,9 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, len = strlen(buf) + 1; } - ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, - len, delay); + ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, len, + trigger); + if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9e641847c047..08dd67435189 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1124,9 +1124,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) u32 file_len, fifo_data_len = 0; u32 smem_len = mvm->cfg->smem_len; u32 sram2_len = mvm->cfg->dccm2_len; + bool monitor_dump_only = false; lockdep_assert_held(&mvm->mutex); + if (mvm->fw_dump_trig && + mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) + monitor_dump_only = true; + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; @@ -1178,6 +1183,20 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) fifo_data_len + sizeof(*dump_info); + /* Make room for the SMEM, if it exists */ + if (smem_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; + + /* Make room for the secondary SRAM, if it exists */ + if (sram2_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; + + /* If we only want a monitor dump, reset the file length */ + if (monitor_dump_only) { + file_len = sizeof(*dump_file) + sizeof(*dump_data) + + sizeof(*dump_info); + } + /* * In 8000 HW family B-step include the ICCM (which resides separately) */ @@ -1190,14 +1209,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; - /* Make room for the SMEM, if it exists */ - if (smem_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; - - /* Make room for the secondary SRAM, if it exists */ - if (sram2_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; - dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -1243,6 +1254,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data = iwl_fw_error_next_data(dump_data); } + /* In case we only want monitor dump, skip to dump trasport data */ + if (monitor_dump_only) + goto dump_trans_data; + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; @@ -1286,7 +1301,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_mem->data, IWL8260_ICCM_LEN); } - fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); +dump_trans_data: + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, + mvm->fw_dump_trig); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) file_len += fw_error_dump->trans_ptr->len; @@ -1295,6 +1312,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); + mvm->fw_dump_trig = NULL; clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fdf401b696a4..2b2e2996ccb9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -708,6 +708,7 @@ struct iwl_mvm { u8 fw_dbg_conf; struct delayed_work fw_dump_wk; struct iwl_mvm_dump_desc *fw_dump_desc; + struct iwl_fw_dbg_trigger_tlv *fw_dump_trig; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -1443,10 +1444,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id); int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, unsigned int delay); + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger); int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, struct iwl_mvm_dump_desc *desc, - unsigned int delay); + struct iwl_fw_dbg_trigger_tlv *trigger); void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index ef09a05b6ddb..48731124afe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -914,7 +914,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * can't recover this since we're already half suspended. */ if (!mvm->restart_fw && fw_error) { - iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, 0); + iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, + NULL); } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index fb55810f5aae..6a3ee04c5222 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2385,8 +2385,87 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans, return monitor_len; } -static -struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) +static u32 +iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data, + u32 monitor_len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 len = 0; + + if ((trans_pcie->fw_mon_page && + trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || + trans->dbg_dest_tlv) { + struct iwl_fw_error_dump_fw_mon *fw_mon_data; + u32 base, write_ptr, wrap_cnt; + + /* If there was a dest TLV - use the values from there */ + if (trans->dbg_dest_tlv) { + write_ptr = + le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); + wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); + base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); + } else { + base = MON_BUFF_BASE_ADDR; + write_ptr = MON_BUFF_WRPTR; + wrap_cnt = MON_BUFF_CYCLE_CNT; + } + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); + fw_mon_data = (void *)(*data)->data; + fw_mon_data->fw_mon_wr_ptr = + cpu_to_le32(iwl_read_prph(trans, write_ptr)); + fw_mon_data->fw_mon_cycle_cnt = + cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); + fw_mon_data->fw_mon_base_ptr = + cpu_to_le32(iwl_read_prph(trans, base)); + + len += sizeof(**data) + sizeof(*fw_mon_data); + if (trans_pcie->fw_mon_page) { + /* + * The firmware is now asserted, it won't write anything + * to the buffer. CPU can take ownership to fetch the + * data. The buffer will be handed back to the device + * before the firmware will be restarted. + */ + dma_sync_single_for_cpu(trans->dev, + trans_pcie->fw_mon_phys, + trans_pcie->fw_mon_size, + DMA_FROM_DEVICE); + memcpy(fw_mon_data->data, + page_address(trans_pcie->fw_mon_page), + trans_pcie->fw_mon_size); + + monitor_len = trans_pcie->fw_mon_size; + } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { + /* + * Update pointers to reflect actual values after + * shifting + */ + base = iwl_read_prph(trans, base) << + trans->dbg_dest_tlv->base_shift; + iwl_trans_read_mem(trans, base, fw_mon_data->data, + monitor_len / sizeof(u32)); + } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { + monitor_len = + iwl_trans_pci_dump_marbh_monitor(trans, + fw_mon_data, + monitor_len); + } else { + /* Didn't match anything - output no monitor data */ + monitor_len = 0; + } + + len += monitor_len; + (*data)->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); + } + + return len; +} + +static struct iwl_trans_dump_data +*iwl_trans_pcie_dump_data(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_fw_error_dump_data *data; @@ -2405,33 +2484,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) len += sizeof(*data) + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); - /* CSR registers */ - len += sizeof(*data) + IWL_CSR_TO_DUMP; - - /* 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; - - len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; - } - - /* FH registers */ - len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); - - if (dump_rbs) { - /* RBs */ - num_rbs = le16_to_cpu(ACCESS_ONCE( - trans_pcie->rxq.rb_stts->closed_rb_num)) - & 0x0FFF; - num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; - len += num_rbs * (sizeof(*data) + - sizeof(struct iwl_fw_error_dump_rb) + - (PAGE_SIZE << trans_pcie->rx_page_order)); - } - /* FW monitor */ if (trans_pcie->fw_mon_page) { len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + @@ -2459,6 +2511,45 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) monitor_len = 0; } + if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) { + dump_data = vzalloc(len); + if (!dump_data) + return NULL; + + data = (void *)dump_data->data; + len = iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); + dump_data->len = len; + + return dump_data; + } + + /* CSR registers */ + len += sizeof(*data) + IWL_CSR_TO_DUMP; + + /* 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; + + len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } + + /* FH registers */ + len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + + if (dump_rbs) { + /* RBs */ + num_rbs = le16_to_cpu(ACCESS_ONCE( + trans_pcie->rxq.rb_stts->closed_rb_num)) + & 0x0FFF; + num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; + len += num_rbs * (sizeof(*data) + + sizeof(struct iwl_fw_error_dump_rb) + + (PAGE_SIZE << trans_pcie->rx_page_order)); + } + dump_data = vzalloc(len); if (!dump_data) return NULL; @@ -2498,73 +2589,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) if (dump_rbs) len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); - /* data is already pointing to the next section */ - if ((trans_pcie->fw_mon_page && - trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || - trans->dbg_dest_tlv) { - struct iwl_fw_error_dump_fw_mon *fw_mon_data; - u32 base, write_ptr, wrap_cnt; - - /* If there was a dest TLV - use the values from there */ - if (trans->dbg_dest_tlv) { - write_ptr = - le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); - wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); - base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); - } else { - base = MON_BUFF_BASE_ADDR; - write_ptr = MON_BUFF_WRPTR; - wrap_cnt = MON_BUFF_CYCLE_CNT; - } - - data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); - fw_mon_data = (void *)data->data; - fw_mon_data->fw_mon_wr_ptr = - cpu_to_le32(iwl_read_prph(trans, write_ptr)); - fw_mon_data->fw_mon_cycle_cnt = - cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); - fw_mon_data->fw_mon_base_ptr = - cpu_to_le32(iwl_read_prph(trans, base)); - - len += sizeof(*data) + sizeof(*fw_mon_data); - if (trans_pcie->fw_mon_page) { - /* - * The firmware is now asserted, it won't write anything - * to the buffer. CPU can take ownership to fetch the - * data. The buffer will be handed back to the device - * before the firmware will be restarted. - */ - dma_sync_single_for_cpu(trans->dev, - trans_pcie->fw_mon_phys, - trans_pcie->fw_mon_size, - DMA_FROM_DEVICE); - memcpy(fw_mon_data->data, - page_address(trans_pcie->fw_mon_page), - trans_pcie->fw_mon_size); - - monitor_len = trans_pcie->fw_mon_size; - } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { - /* - * Update pointers to reflect actual values after - * shifting - */ - base = iwl_read_prph(trans, base) << - trans->dbg_dest_tlv->base_shift; - iwl_trans_read_mem(trans, base, fw_mon_data->data, - monitor_len / sizeof(u32)); - } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { - monitor_len = - iwl_trans_pci_dump_marbh_monitor(trans, - fw_mon_data, - monitor_len); - } else { - /* Didn't match anything - output no monitor data */ - monitor_len = 0; - } - - len += monitor_len; - data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); - } + len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); dump_data->len = len; -- cgit v1.2.3-70-g09d2 From 26d535aedc0e9fcf2c8bee65b33cecb58ee8e8ed Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 28 Apr 2015 12:56:54 +0300 Subject: iwlwifi: pcie: New RBD allocation model As a preperation for multiple RX queues change the RBD allocation model. The new model includes a background allocator. The allocator is called by the interrupt handler when there are two released buffers by the queue, and the allocator starts allocating eight pages per request. When the queue has released 8 pages it tries claiming the request. If the pages are not ready - it keeps claiming. This new model should make sure that RBDs are always available across the multiple queues. The RBDs are transferred between the allocator and the queue. The queue moves the free RBDs upon freeing them to the allocator. The allocator moves them back to the queue's possession when the request is claimed. The allocator has an initial pool to make sure there are always RBDs available for the request completion. Release of the buffers at exit is done per pools - the allocator frees its own initial pool and the queue frees its own pool. Existing code refactor - -Queue's initial pool is the size of the queue only as the allocation of the new buffers no longer uses this pool. -Removal of replenish background work, and replenish calls in the interrupt handler and restock(). -The replenish() and the rxq used_list are used only during initialization. -Moved page allocation to a new function for code reuse. New code - Allocator code - new structure and functions. Interrupt handler uses the allocator functions for replenishing buffers. Reuse of the restock() method. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fh.h | 6 - drivers/net/wireless/iwlwifi/pcie/internal.h | 51 ++- drivers/net/wireless/iwlwifi/pcie/rx.c | 473 ++++++++++++++++++++++----- 3 files changed, 435 insertions(+), 95 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index d45dc021cda2..d56064861a9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -438,12 +438,6 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RX_QUEUE_MASK 255 #define RX_QUEUE_SIZE_LOG 8 -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 2de3d9a4fa7c..feb2f7e81134 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -50,6 +50,15 @@ */ #define IWL_PCIE_MAX_FRAGS (IWL_NUM_OF_TBS - 3) +/* + * RX related structures and functions + */ +#define RX_NUM_QUEUES 1 +#define RX_POST_REQ_ALLOC 2 +#define RX_CLAIM_REQ_ALLOC 8 +#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES) +#define RX_LOW_WATERMARK 8 + struct iwl_host_cmd; /*This file includes the declaration that are internal to the @@ -83,29 +92,29 @@ struct isr_statistics { * struct iwl_rxq - Rx queue * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) - * @pool: - * @queue: * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free + * @used_count: Number of RBDs handled to allocator to use for allocation * @write_actual: - * @rx_free: list of free SKBs for use - * @rx_used: List of Rx buffers with no SKB + * @rx_free: list of RBDs with allocated RB ready for use + * @rx_used: list of RBDs with no RB attached * @need_update: flag to indicate we need to update read/write index * @rb_stts: driver's pointer to receive buffer status * @rb_stts_dma: bus address of receive buffer status * @lock: + * @pool: initial pool of iwl_rx_mem_buffer for the queue + * @queue: actual rx queue * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ struct iwl_rxq { __le32 *bd; dma_addr_t bd_dma; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; u32 read; u32 write; u32 free_count; + u32 used_count; u32 write_actual; struct list_head rx_free; struct list_head rx_used; @@ -113,6 +122,32 @@ struct iwl_rxq { struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; +}; + +/** + * struct iwl_rb_allocator - Rx allocator + * @pool: initial pool of allocator + * @req_pending: number of requests the allcator had not processed yet + * @req_ready: number of requests honored and ready for claiming + * @rbd_allocated: RBDs with pages allocated and ready to be handled to + * the queue. This is a list of &struct iwl_rx_mem_buffer + * @rbd_empty: RBDs with no page attached for allocator use. This is a list + * of &struct iwl_rx_mem_buffer + * @lock: protects the rbd_allocated and rbd_empty lists + * @alloc_wq: work queue for background calls + * @rx_alloc: work struct for background calls + */ +struct iwl_rb_allocator { + struct iwl_rx_mem_buffer pool[RX_POOL_SIZE]; + atomic_t req_pending; + atomic_t req_ready; + struct list_head rbd_allocated; + struct list_head rbd_empty; + spinlock_t lock; + struct workqueue_struct *alloc_wq; + struct work_struct rx_alloc; }; struct iwl_dma_ptr { @@ -256,7 +291,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data - * @rx_replenish: work that will be called when buffers need to be allocated + * @rba: allocator for RX replenishing * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM @@ -281,7 +316,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) */ struct iwl_trans_pcie { struct iwl_rxq rxq; - struct work_struct rx_replenish; + struct iwl_rb_allocator rba; struct iwl_trans *trans; struct iwl_drv *drv; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index e1af0fffedd8..5643ace7b15a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -74,16 +74,29 @@ * resets the Rx queue buffers with new memory. * * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) + * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free. + * When the interrupt handler is called, the request is processed. + * The page is either stolen - transferred to the upper layer + * or reused - added immediately to the iwl->rxq->rx_free list. + * + When the page is stolen - the driver updates the matching queue's used + * count, detaches the RBD and transfers it to the queue used list. + * When there are two used RBDs - they are transferred to the allocator empty + * list. Work is then scheduled for the allocator to start allocating + * eight buffers. + * When there are another 6 used RBDs - they are transferred to the allocator + * empty list and the driver tries to claim the pre-allocated buffers and + * add them to iwl->rxq->rx_free. If it fails - it continues to claim them + * until ready. + * When there are 8+ buffers in the free list - either from allocation or from + * 8 reused unstolen pages - restock is called to update the FW and indexes. + * + In order to make sure the allocator always has RBDs to use for allocation + * the allocator has initial pool in the size of num_queues*(8-2) - the + * maximum missing RBDs per allocation request (request posted with 2 + * empty RBDs, there is no guarantee when the other 6 RBDs are supplied). + * The queues supplies the recycle of the rest of the RBDs. * + A received packet is processed and handed to the kernel network stack, * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at irq thread time from the - * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, + * + If there are no allocated buffers in iwl->rxq->rx_free, * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. * If there were enough free buffers and RX_STALLED is set it is cleared. * @@ -92,18 +105,32 @@ * * iwl_rxq_alloc() Allocates rx_free * iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_pcie_rxq_restock + * iwl_pcie_rxq_restock. + * Used only during initialization. * iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_pcie_rx_replenish + * the WRITE index. + * iwl_pcie_rx_allocator() Background work for allocating pages. * * -- enable interrupts -- * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. + * Posts and claims requests to the allocator. * Calls iwl_pcie_rxq_restock to refill any empty * slots. + * + * RBD life-cycle: + * + * Init: + * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue + * + * Regular Receive interrupt: + * Page Stolen: + * rxq.queue -> rxq.rx_used -> allocator.rbd_empty -> + * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue + * Page not Stolen: + * rxq.queue -> rxq.rx_free -> rxq.queue * ... * */ @@ -240,10 +267,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) rxq->free_count--; } spin_unlock(&rxq->lock); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ @@ -254,6 +277,45 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) } } +/* + * iwl_pcie_rx_alloc_page - allocates and returns a page. + * + */ +static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, + gfp_t priority) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + struct page *page; + gfp_t gfp_mask = priority; + + if (rxq->free_count > RX_LOW_WATERMARK) + gfp_mask |= __GFP_NOWARN; + + if (trans_pcie->rx_page_order > 0) + gfp_mask |= __GFP_COMP; + + /* Alloc a new receive buffer */ + page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); + if (!page) { + if (net_ratelimit()) + IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n", + trans_pcie->rx_page_order); + /* Issue an error if the hardware has consumed more than half + * of its free buffer list and we don't have enough + * pre-allocated buffers. +` */ + if (rxq->free_count <= RX_LOW_WATERMARK && + iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) && + net_ratelimit()) + IWL_CRIT(trans, + "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n", + rxq->free_count); + return NULL; + } + return page; +} + /* * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD * @@ -269,7 +331,6 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; - gfp_t gfp_mask = priority; while (1) { spin_lock(&rxq->lock); @@ -279,32 +340,10 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) } spin_unlock(&rxq->lock); - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - - if (trans_pcie->rx_page_order > 0) - gfp_mask |= __GFP_COMP; - /* Alloc a new receive buffer */ - page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); - if (!page) { - if (net_ratelimit()) - IWL_DEBUG_INFO(trans, "alloc_pages failed, " - "order: %d\n", - trans_pcie->rx_page_order); - - if ((rxq->free_count <= RX_LOW_WATERMARK) && - net_ratelimit()) - IWL_CRIT(trans, "Failed to alloc_pages with %s." - "Only %u free buffers remaining.\n", - priority == GFP_ATOMIC ? - "GFP_ATOMIC" : "GFP_KERNEL", - rxq->free_count); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ + page = iwl_pcie_rx_alloc_page(trans, priority); + if (!page) return; - } spin_lock(&rxq->lock); @@ -355,7 +394,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) lockdep_assert_held(&rxq->lock); - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + for (i = 0; i < RX_QUEUE_SIZE; i++) { if (!rxq->pool[i].page) continue; dma_unmap_page(trans->dev, rxq->pool[i].page_dma, @@ -372,32 +411,164 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) * When moving to rx_free an page is allocated for the slot. * * Also restock the Rx queue via iwl_pcie_rxq_restock. - * This is called as a scheduled work item (except for during initialization) + * This is called only during initialization */ -static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp) +static void iwl_pcie_rx_replenish(struct iwl_trans *trans) { - iwl_pcie_rxq_alloc_rbs(trans, gfp); + iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); iwl_pcie_rxq_restock(trans); } -static void iwl_pcie_rx_replenish_work(struct work_struct *data) +/* + * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues + * + * Allocates for each received request 8 pages + * Called as a scheduled work item. + */ +static void iwl_pcie_rx_allocator(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + struct list_head local_empty; + int pending = atomic_xchg(&rba->req_pending, 0); + + IWL_DEBUG_RX(trans, "Pending allocation requests = %d\n", pending); + + /* If we were scheduled - there is at least one request */ + spin_lock(&rba->lock); + /* swap out the rba->rbd_empty to a local list */ + list_replace_init(&rba->rbd_empty, &local_empty); + spin_unlock(&rba->lock); + + while (pending) { + int i; + struct list_head local_allocated; + + INIT_LIST_HEAD(&local_allocated); + + for (i = 0; i < RX_CLAIM_REQ_ALLOC;) { + struct iwl_rx_mem_buffer *rxb; + struct page *page; + + /* List should never be empty - each reused RBD is + * returned to the list, and initial pool covers any + * possible gap between the time the page is allocated + * to the time the RBD is added. + */ + BUG_ON(list_empty(&local_empty)); + /* Get the first rxb from the rbd list */ + rxb = list_first_entry(&local_empty, + struct iwl_rx_mem_buffer, list); + BUG_ON(rxb->page); + + /* Alloc a new receive buffer */ + page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL); + if (!page) + continue; + rxb->page = page; + + /* Get physical address of the RB */ + rxb->page_dma = dma_map_page(trans->dev, page, 0, + PAGE_SIZE << trans_pcie->rx_page_order, + DMA_FROM_DEVICE); + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + rxb->page = NULL; + __free_pages(page, trans_pcie->rx_page_order); + continue; + } + /* dma address must be no more than 36 bits */ + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); + /* and also 256 byte aligned! */ + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); + + /* move the allocated entry to the out list */ + list_move(&rxb->list, &local_allocated); + i++; + } + + pending--; + if (!pending) { + pending = atomic_xchg(&rba->req_pending, 0); + IWL_DEBUG_RX(trans, + "Pending allocation requests = %d\n", + pending); + } + + spin_lock(&rba->lock); + /* add the allocated rbds to the allocator allocated list */ + list_splice_tail(&local_allocated, &rba->rbd_allocated); + /* get more empty RBDs for current pending requests */ + list_splice_tail_init(&rba->rbd_empty, &local_empty); + spin_unlock(&rba->lock); + + atomic_inc(&rba->req_ready); + } + + spin_lock(&rba->lock); + /* return unused rbds to the allocator empty list */ + list_splice_tail(&local_empty, &rba->rbd_empty); + spin_unlock(&rba->lock); +} + +/* + * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages +.* +.* Called by queue when the queue posted allocation request and + * has freed 8 RBDs in order to restock itself. + */ +static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans, + struct iwl_rx_mem_buffer + *out[RX_CLAIM_REQ_ALLOC]) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + int i; + + /* + * atomic_dec_if_positive returns req_ready - 1 for any scenario. + * If req_ready is 0 atomic_dec_if_positive will return -1 and this + * function will return -ENOMEM, as there are no ready requests. + * atomic_dec_if_positive will perofrm the *actual* decrement only if + * req_ready > 0, i.e. - there are ready requests and the function + * hands one request to the caller. + */ + if (atomic_dec_if_positive(&rba->req_ready) < 0) + return -ENOMEM; + + spin_lock(&rba->lock); + for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) { + /* Get next free Rx buffer, remove it from free list */ + out[i] = list_first_entry(&rba->rbd_allocated, + struct iwl_rx_mem_buffer, list); + list_del(&out[i]->list); + } + spin_unlock(&rba->lock); + + return 0; +} + +static void iwl_pcie_rx_allocator_work(struct work_struct *data) { + struct iwl_rb_allocator *rba_p = + container_of(data, struct iwl_rb_allocator, rx_alloc); struct iwl_trans_pcie *trans_pcie = - container_of(data, struct iwl_trans_pcie, rx_replenish); + container_of(rba_p, struct iwl_trans_pcie, rba); - iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL); + iwl_pcie_rx_allocator(trans_pcie->trans); } static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; struct device *dev = trans->dev; memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); spin_lock_init(&rxq->lock); + spin_lock_init(&rba->lock); if (WARN_ON(rxq->bd || rxq->rb_stts)) return -EINVAL; @@ -487,15 +658,49 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); rxq->free_count = 0; + rxq->used_count = 0; - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + for (i = 0; i < RX_QUEUE_SIZE; i++) list_add(&rxq->pool[i].list, &rxq->rx_used); } +static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba) +{ + int i; + + lockdep_assert_held(&rba->lock); + + INIT_LIST_HEAD(&rba->rbd_allocated); + INIT_LIST_HEAD(&rba->rbd_empty); + + for (i = 0; i < RX_POOL_SIZE; i++) + list_add(&rba->pool[i].list, &rba->rbd_empty); +} + +static void iwl_pcie_rx_free_rba(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + int i; + + lockdep_assert_held(&rba->lock); + + for (i = 0; i < RX_POOL_SIZE; i++) { + if (!rba->pool[i].page) + continue; + dma_unmap_page(trans->dev, rba->pool[i].page_dma, + PAGE_SIZE << trans_pcie->rx_page_order, + DMA_FROM_DEVICE); + __free_pages(rba->pool[i].page, trans_pcie->rx_page_order); + rba->pool[i].page = NULL; + } +} + int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, err; if (!rxq->bd) { @@ -503,11 +708,21 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) if (err) return err; } + if (!rba->alloc_wq) + rba->alloc_wq = alloc_workqueue("rb_allocator", + WQ_HIGHPRI | WQ_UNBOUND, 1); + INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work); + + spin_lock(&rba->lock); + atomic_set(&rba->req_pending, 0); + atomic_set(&rba->req_ready, 0); + /* free all first - we might be reconfigured for a different size */ + iwl_pcie_rx_free_rba(trans); + iwl_pcie_rx_init_rba(rba); + spin_unlock(&rba->lock); spin_lock(&rxq->lock); - INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work); - /* free all first - we might be reconfigured for a different size */ iwl_pcie_rxq_free_rbs(trans); iwl_pcie_rx_init_rxb_lists(rxq); @@ -522,7 +737,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans, GFP_KERNEL); + iwl_pcie_rx_replenish(trans); iwl_pcie_rx_hw_init(trans, rxq); @@ -537,6 +752,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; /*if rxq->bd is NULL, it means that nothing has been allocated, * exit now */ @@ -545,7 +761,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) return; } - cancel_work_sync(&trans_pcie->rx_replenish); + cancel_work_sync(&rba->rx_alloc); + if (rba->alloc_wq) { + destroy_workqueue(rba->alloc_wq); + rba->alloc_wq = NULL; + } + + spin_lock(&rba->lock); + iwl_pcie_rx_free_rba(trans); + spin_unlock(&rba->lock); spin_lock(&rxq->lock); iwl_pcie_rxq_free_rbs(trans); @@ -566,8 +790,49 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rxq->rb_stts = NULL; } +/* + * iwl_pcie_rx_reuse_rbd - Recycle used RBDs + * + * Called when a RBD can be reused. The RBD is transferred to the allocator. + * When there are 2 empty RBDs - a request for allocation is posted + */ +static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, + struct iwl_rx_mem_buffer *rxb, + struct iwl_rxq *rxq, bool emergency) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + + /* Move the RBD to the used list, will be moved to allocator in batches + * before claiming or posting a request*/ + list_add_tail(&rxb->list, &rxq->rx_used); + + if (unlikely(emergency)) + return; + + /* Count the allocator owned RBDs */ + rxq->used_count++; + + /* If we have RX_POST_REQ_ALLOC new released rx buffers - + * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is + * used for the case we failed to claim RX_CLAIM_REQ_ALLOC, + * after but we still need to post another request. + */ + if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) { + /* Move the 2 RBDs to the allocator ownership. + Allocator has another 6 from pool for the request completion*/ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); + spin_unlock(&rba->lock); + + atomic_inc(&rba->req_pending); + queue_work(rba->alloc_wq, &rba->rx_alloc); + } +} + static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, - struct iwl_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb, + bool emergency) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; @@ -682,13 +947,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, */ __free_pages(rxb->page, trans_pcie->rx_page_order); rxb->page = NULL; - list_add_tail(&rxb->list, &rxq->rx_used); + iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency); } else { list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; } } else - list_add_tail(&rxb->list, &rxq->rx_used); + iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency); } /* @@ -698,10 +963,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - u32 r, i; - u8 fill_rx = 0; - u32 count = 8; - int total_empty; + u32 r, i, j, count = 0; + bool emergency = false; restart: spin_lock(&rxq->lock); @@ -714,47 +977,95 @@ restart: if (i == r) IWL_DEBUG_RX(trans, "HW = SW = %d\n", r); - /* calculate total frames need to be restock after handling RX */ - total_empty = r - rxq->write_actual; - if (total_empty < 0) - total_empty += RX_QUEUE_SIZE; - - if (total_empty > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - while (i != r) { struct iwl_rx_mem_buffer *rxb; + if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2)) + emergency = true; + rxb = rxq->queue[i]; rxq->queue[i] = NULL; IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n", r, i, rxb); - iwl_pcie_rx_handle_rb(trans, rxb); + iwl_pcie_rx_handle_rb(trans, rxb, emergency); i = (i + 1) & RX_QUEUE_MASK; - /* If there are a lot of unused frames, - * restock the Rx queue so ucode wont assert. */ - if (fill_rx) { + + /* If we have RX_CLAIM_REQ_ALLOC released rx buffers - + * try to claim the pre-allocated buffers from the allocator */ + if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) { + struct iwl_rb_allocator *rba = &trans_pcie->rba; + struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC]; + + if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && + !emergency) { + /* Add the remaining 6 empty RBDs + * for allocator use + */ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, + &rba->rbd_empty); + spin_unlock(&rba->lock); + } + + /* If not ready - continue, will try to reclaim later. + * No need to reschedule work - allocator exits only on + * success */ + if (!iwl_pcie_rx_allocator_get(trans, out)) { + /* If success - then RX_CLAIM_REQ_ALLOC + * buffers were retrieved and should be added + * to free list */ + rxq->used_count -= RX_CLAIM_REQ_ALLOC; + for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) { + list_add_tail(&out[j]->list, + &rxq->rx_free); + rxq->free_count++; + } + } + } + if (emergency) { count++; - if (count >= 8) { - rxq->read = i; - spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans, GFP_ATOMIC); + if (count == 8) { count = 0; - goto restart; + if (rxq->used_count < RX_QUEUE_SIZE / 3) + emergency = false; + spin_unlock(&rxq->lock); + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); + spin_lock(&rxq->lock); } } + /* handle restock for three cases, can be all of them at once: + * - we just pulled buffers from the allocator + * - we have 8+ unstolen pages accumulated + * - we are in emergency and allocated buffers + */ + if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { + rxq->read = i; + spin_unlock(&rxq->lock); + iwl_pcie_rxq_restock(trans); + goto restart; + } } /* Backtrack one entry */ rxq->read = i; spin_unlock(&rxq->lock); - if (fill_rx) - iwl_pcie_rx_replenish(trans, GFP_ATOMIC); - else - iwl_pcie_rxq_restock(trans); + /* + * handle a case where in emergency there are some unallocated RBDs. + * those RBDs are in the used list, but are not tracked by the queue's + * used_count which counts allocator owned RBDs. + * unallocated emergency RBDs must be allocated on exit, otherwise + * when called again the function may not be in emergency mode and + * they will be handed to the allocator with no tracking in the RBD + * allocator counters, which will lead to them never being claimed back + * by the queue. + * by allocating them here, they are now in the queue free list, and + * will be restocked by the next call of iwl_pcie_rxq_restock. + */ + if (unlikely(emergency && count)) + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); if (trans_pcie->napi.poll) napi_gro_flush(&trans_pcie->napi, false); -- cgit v1.2.3-70-g09d2 From e112018776a88b1e9c31fff3c6a9341c4f37c358 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Sun, 19 Jul 2015 11:15:07 +0300 Subject: iwlwifi: mvm: Add FW paging mechanism for the UMAC on SDIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Family 8000 products has 2 embedded processors, the first known as LMAC (lower MAC) and implements the functionality from previous products, the second one is known as UMAC (upper MAC) and is used mainly for driver offloads as well as new features. The UMAC is typically “less” real-time than the LMAC and is used for higher level controls. The UMAC's code/data size is estimated to be in the mega-byte arena, taking into account the code it needs to replace in the driver and the set of new features. In order to allow the UMAC to execute code that is bigger than its code memory, we allow the UMAC embedded processor to page out code pages on DRAM. When the device is slave on the bus(SDIO) the driver saves the UMAC's image pages in blocks of 32K in the DRAM and sends the layout of the pages to the FW. When the FW wants load / unload pages, it creates an interrupt, and the driver uploads / downloads the page to an address in the a specific address on the device's memory. The driver can support up to 1 MB of pages. Add paging mechanism for the UMAC on SDIO in order to allow the program to use a larger virtual space while using less physical memory on the device itself. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 2 + drivers/net/wireless/iwlwifi/iwl-fw.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-prph.h | 6 +++ drivers/net/wireless/iwlwifi/iwl-trans.h | 14 ++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 26 +++++++++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 76 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 7 files changed, 128 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index fa716618735e..543abeaffcf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -200,6 +200,7 @@ #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ +#define CSR_INT_BIT_PAGING (1 << 24) /* SDIO PAGING */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ @@ -210,6 +211,7 @@ CSR_INT_BIT_HW_ERR | \ CSR_INT_BIT_FH_TX | \ CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_PAGING | \ CSR_INT_BIT_RF_KILL | \ CSR_INT_BIT_SW_RX | \ CSR_INT_BIT_WAKEUP | \ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 0d9d6f51766e..45e732150d28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -163,6 +163,9 @@ struct iwl_sf_region { /* maximum image size 1024KB */ #define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) +/* Virtual address signature */ +#define PAGING_ADDR_SIG 0xAA000000 + #define PAGING_CMD_IS_SECURED BIT(9) #define PAGING_CMD_IS_ENABLED BIT(8) #define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c4e7a713af0f..3ab777f79e4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -392,4 +392,10 @@ enum { LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0), }; +/* FW chicken bits */ +#define LMPM_PAGE_PASS_NOTIF 0xA03824 +enum { + LMPM_PAGE_PASS_NOTIF_POS = BIT(20), +}; + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 151e3de2247f..9d8b5cb06343 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -668,6 +668,12 @@ enum iwl_d0i3_mode { * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + * @paging_req_addr: The location were the FW will upload / download the pages + * from. The address is set by the opmode + * @paging_db: Pointer to the opmode paging data base, the pointer is set by + * 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 */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -705,6 +711,14 @@ struct iwl_trans { struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; u8 dbg_dest_reg_num; + /* + * Paging parameters - All of the parameters should be set by the + * opmode when paging is enabled + */ + u32 paging_req_addr; + struct iwl_fw_paging *paging_db; + void *paging_download_buf; + enum iwl_d0i3_mode d0i3_mode; bool wowlan_d0i3; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9c6b153f2e12..4af7513adda2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -120,6 +120,9 @@ enum { ADD_STA = 0x18, REMOVE_STA = 0x19, + /* paging get item */ + FW_GET_ITEM_CMD = 0x1a, + /* TX */ TX_CMD = 0x1c, TXPATH_FLUSH = 0x1e, @@ -394,6 +397,29 @@ struct iwl_fw_paging_cmd { __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; } __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ +/* + * Fw items ID's + * + * @IWL_FW_ITEM_ID_PAGING: Address of the pages that the FW will upload + * download + */ +enum iwl_fw_item_id { + IWL_FW_ITEM_ID_PAGING = 3, +}; + +/* + * struct iwl_fw_get_item_cmd - get an item from the fw + */ +struct iwl_fw_get_item_cmd { + __le32 item_id; +} __packed; /* FW_GET_ITEM_CMD_API_S_VER_1 */ + +struct iwl_fw_get_item_resp { + __le32 item_id; + __le32 item_byte_cnt; + __le32 item_val; +} __packed; /* FW_GET_ITEM_RSP_S_VER_1 */ + /** * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD * @offset: offset in bytes into the section diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index aff5bbf3f141..4a0ce83315bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -125,6 +125,7 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm) __free_pages(mvm->fw_paging_db[i].fw_paging_block, get_order(mvm->fw_paging_db[i].fw_paging_size)); } + kfree(mvm->trans->paging_download_buf); memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); } @@ -258,6 +259,9 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, return -ENOMEM; } mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } else { + mvm->fw_paging_db[blk_idx].fw_paging_phys = PAGING_ADDR_SIG | + blk_idx << BLOCK_2_EXP_SIZE; } IWL_DEBUG_FW(mvm, @@ -294,6 +298,10 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, return -ENOMEM; } mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } else { + mvm->fw_paging_db[blk_idx].fw_paging_phys = + PAGING_ADDR_SIG | + blk_idx << BLOCK_2_EXP_SIZE; } IWL_DEBUG_FW(mvm, @@ -344,6 +352,60 @@ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) 0, sizeof(fw_paging_cmd), &fw_paging_cmd); } +/* + * Send paging item cmd to FW in case CPU2 has paging image + */ +static int iwl_trans_get_paging_item(struct iwl_mvm *mvm) +{ + int ret; + struct iwl_fw_get_item_cmd fw_get_item_cmd = { + .item_id = cpu_to_le32(IWL_FW_ITEM_ID_PAGING), + }; + + struct iwl_fw_get_item_resp *item_resp; + struct iwl_host_cmd cmd = { + .id = iwl_cmd_id(FW_GET_ITEM_CMD, IWL_ALWAYS_LONG_GROUP, 0), + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &fw_get_item_cmd, }, + }; + + cmd.len[0] = sizeof(struct iwl_fw_get_item_cmd); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, + "Paging: Failed to send FW_GET_ITEM_CMD cmd (err = %d)\n", + ret); + return ret; + } + + item_resp = (void *)((struct iwl_rx_packet *)cmd.resp_pkt)->data; + if (item_resp->item_id != cpu_to_le32(IWL_FW_ITEM_ID_PAGING)) { + IWL_ERR(mvm, + "Paging: got wrong item in FW_GET_ITEM_CMD resp (item_id = %u)\n", + le32_to_cpu(item_resp->item_id)); + ret = -EIO; + goto exit; + } + + mvm->trans->paging_download_buf = kzalloc(MAX_PAGING_IMAGE_SIZE, + GFP_KERNEL); + if (!mvm->trans->paging_download_buf) { + ret = -ENOMEM; + goto exit; + } + mvm->trans->paging_req_addr = le32_to_cpu(item_resp->item_val); + mvm->trans->paging_db = mvm->fw_paging_db; + IWL_DEBUG_FW(mvm, + "Paging: got paging request address (paging_req_addr 0x%08x)\n", + mvm->trans->paging_req_addr); + +exit: + iwl_free_resp(&cmd); + + return ret; +} + static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -517,6 +579,20 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, * included in the IWL_UCODE_INIT image. */ if (fw->paging_mem_size) { + /* + * When dma is not enabled, the driver needs to copy / write + * the downloaded / uploaded page to / from the smem. + * This gets the location of the place were the pages are + * stored. + */ + if (!is_device_dma_capable(mvm->trans->dev)) { + ret = iwl_trans_get_paging_item(mvm); + if (ret) { + IWL_ERR(mvm, "failed to get FW paging item\n"); + return ret; + } + } + ret = iwl_save_fw_paging(mvm, fw); if (ret) { IWL_ERR(mvm, "failed to save the FW paging image\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 48731124afe1..5d577c13db5b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -291,6 +291,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { 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), -- cgit v1.2.3-70-g09d2 From eed6e971973667d067d510e9540773ff0f9fe8fd Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 22 Jul 2015 14:21:31 +0300 Subject: iwlwifi: mvm: ToF - Set correct range request cmd id Command ID of ToF range request command adapted to new FW commands grouping scheme. Signed-off-by: Assaf Krauss Reviewed-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c index d060e12c3239..380972f8fb82 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -194,7 +194,7 @@ int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_host_cmd cmd = { - .id = TOF_CMD, + .id = iwl_cmd_id(TOF_CMD, IWL_ALWAYS_LONG_GROUP, 0), .len = { sizeof(mvm->tof_data.range_req), }, /* no copy because of the command size */ .dataflags = { IWL_HCMD_DFL_NOCOPY, }, -- cgit v1.2.3-70-g09d2 From b084a35663c3f1f7de1c45c4ae3006864c940fe7 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 12 Jul 2015 09:10:05 +0300 Subject: iwlwifi: mvm: set different pm_timeout for action frames When building a Tx Command for management frames, we are lacking a check for action frames, for which we should set a different pm_timeout. This cause the fw to stay awake for 100TU after each such frame is transmitted, resulting an excessive power consumption. Signed-off-by: Avri Altman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 12 ++++++++++++ drivers/net/wireless/iwlwifi/mvm/tx.c | 10 ++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 81c4ea3c6958..853698ab8b05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -124,6 +124,18 @@ enum iwl_tx_flags { TX_CMD_FLG_HCCA_CHUNK = BIT(31) }; /* TX_FLAGS_BITS_API_S_VER_1 */ +/** + * enum iwl_tx_pm_timeouts - pm timeout values in TX command + * @PM_FRAME_NONE: no need to suspend sleep mode + * @PM_FRAME_MGMT: fw suspend sleep mode for 100TU + * @PM_FRAME_ASSOC: fw suspend sleep mode for 10sec + */ +enum iwl_tx_pm_timeouts { + PM_FRAME_NONE = 0, + PM_FRAME_MGMT = 2, + PM_FRAME_ASSOC = 3, +}; + /* * TX command security control */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 15bf36ad3809..6df5aada4f16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -153,18 +153,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(3); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); + else if (ieee80211_is_action(fc)) + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); else - tx_cmd->pm_frame_timeout = cpu_to_le16(2); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); /* The spec allows Action frames in A-MPDU, we don't support * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { - tx_cmd->pm_frame_timeout = cpu_to_le16(2); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); } else { - tx_cmd->pm_frame_timeout = 0; + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); } if (ieee80211_is_data(fc) && len > mvm->rts_threshold && -- cgit v1.2.3-70-g09d2 From f1ad8c9346de80c91d7f35d4a1b0d1f2b93b3661 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:49 +0300 Subject: wil6210: support boot loader struct v0 & v1 There are 2 versions of boot loader struct: v0 and v1. In the v1, boot loader build version added; as well as RF status. Support both versions. Boot loader structure v1 has RF status; ignore RF error if firmware not going to be loaded; driver can still be used to interact with the HW Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/boot_loader.h | 56 +++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 85 ++++++++++++++++++++------ drivers/net/wireless/ath/wil6210/wil6210.h | 10 --- 3 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 drivers/net/wireless/ath/wil6210/boot_loader.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h new file mode 100644 index 000000000000..1b4fd402cba2 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -0,0 +1,56 @@ +/* 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. + */ + +/* This file contains the definitions for the boot loader + * for the Qualcomm "Sparrow" 60 Gigabit wireless solution. + */ +#ifndef BOOT_LOADER_EXPORT_H_ +#define BOOT_LOADER_EXPORT_H_ + +struct bl_dedicated_registers_v1 { + __le32 boot_loader_ready; /* 0x880A3C driver will poll + * this Dword until BL will + * set it to 1 (initial value + * should be 0) + */ + __le32 boot_loader_struct_version; /* 0x880A40 BL struct ver. */ + __le16 rf_type; /* 0x880A44 connected RF ID */ + __le16 rf_status; /* 0x880A46 RF status, + * 0 is OK else error + */ + __le32 baseband_type; /* 0x880A48 board type ID */ + u8 mac_address[6]; /* 0x880A4c BL mac address */ + u8 bl_version_major; /* 0x880A52 BL ver. major */ + u8 bl_version_minor; /* 0x880A53 BL ver. minor */ + __le16 bl_version_subminor; /* 0x880A54 BL ver. subminor */ + __le16 bl_version_build; /* 0x880A56 BL ver. build */ +} __packed; + +/* the following struct is the version 0 struct */ + +struct bl_dedicated_registers_v0 { + __le32 boot_loader_ready; /* 0x880A3C driver will poll + * this Dword until BL will + * set it to 1 (initial value + * should be 0) + */ +#define BL_READY (1) /* ready indication */ + __le32 boot_loader_struct_version; /* 0x880A40 BL struct ver. */ + __le32 rf_type; /* 0x880A44 connected RF ID */ + __le32 baseband_type; /* 0x880A48 board type ID */ + u8 mac_address[6]; /* 0x880A4c BL mac address */ +} __packed; + +#endif /* BOOT_LOADER_EXPORT_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6ca6193ab8a6..ae0df3588e5d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,6 +21,7 @@ #include "wil6210.h" #include "txrx.h" #include "wmi.h" +#include "boot_loader.h" #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 @@ -565,7 +566,8 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); /* clear all boot loader "ready" bits */ - W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); + W(RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); @@ -607,7 +609,8 @@ static int wil_target_reset(struct wil6210_priv *wil) /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); + x = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; @@ -617,7 +620,7 @@ static int wil_target_reset(struct wil6210_priv *wil) x); return -ETIME; } - } while (x != BIT_BL_READY); + } while (x != BL_READY); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); @@ -641,25 +644,71 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) static int wil_get_bl_info(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - struct RGF_BL bl; - - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); - le32_to_cpus(&bl.ready); - le32_to_cpus(&bl.version); - le32_to_cpus(&bl.rf_type); - le32_to_cpus(&bl.baseband_type); + union { + struct bl_dedicated_registers_v0 bl0; + struct bl_dedicated_registers_v1 bl1; + } bl; + u32 bl_ver; + u8 *mac; + u16 rf_status; + + bl_ver = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); + switch (bl_ver) { + case 0: + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl.bl0)); + le32_to_cpus(&bl.bl0.boot_loader_ready); + le32_to_cpus(&bl.bl0.boot_loader_struct_version); + le32_to_cpus(&bl.bl0.rf_type); + le32_to_cpus(&bl.bl0.baseband_type); + mac = bl.bl0.mac_address; + rf_status = 0; /* actually, unknown */ + wil_info(wil, + "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl_ver, mac, + bl.bl0.rf_type, bl.bl0.baseband_type); + wil_info(wil, "Boot Loader build unknown for struct v0\n"); + break; + case 1: + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl.bl1)); + le32_to_cpus(&bl.bl1.boot_loader_ready); + le32_to_cpus(&bl.bl1.boot_loader_struct_version); + le16_to_cpus(&bl.bl1.rf_type); + rf_status = le16_to_cpu(bl.bl1.rf_status); + le32_to_cpus(&bl.bl1.baseband_type); + le16_to_cpus(&bl.bl1.bl_version_subminor); + le16_to_cpus(&bl.bl1.bl_version_build); + mac = bl.bl1.mac_address; + wil_info(wil, + "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n", + bl_ver, mac, + bl.bl1.rf_type, rf_status, + bl.bl1.baseband_type); + wil_info(wil, "Boot Loader build %d.%d.%d.%d\n", + bl.bl1.bl_version_major, bl.bl1.bl_version_minor, + bl.bl1.bl_version_subminor, bl.bl1.bl_version_build); + break; + default: + wil_err(wil, "BL: unsupported struct version 0x%08x\n", bl_ver); + return -EINVAL; + } - if (!is_valid_ether_addr(bl.mac_address)) { - wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + if (!is_valid_ether_addr(mac)) { + wil_err(wil, "BL: Invalid MAC %pM\n", mac); return -EINVAL; } - ether_addr_copy(ndev->perm_addr, bl.mac_address); + ether_addr_copy(ndev->perm_addr, mac); if (!is_valid_ether_addr(ndev->dev_addr)) - ether_addr_copy(ndev->dev_addr, bl.mac_address); - wil_info(wil, - "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", - bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + ether_addr_copy(ndev->dev_addr, mac); + + if (rf_status) {/* bad RF cable? */ + wil_err(wil, "RF communication error 0x%04x", + rf_status); + return -EAGAIN; + } return 0; } @@ -735,6 +784,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; rc = wil_get_bl_info(wil); + if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ + rc = 0; if (rc) return rc; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c63e4a35eaa0..b79ba4994d0c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -127,16 +127,6 @@ struct RGF_ICR { u32 IMC; /* Mask Clear, write 1 to clear */ } __packed; -struct RGF_BL { - u32 ready; /* 0x880A3C bit [0] */ -#define BIT_BL_READY BIT(0) - u32 version; /* 0x880A40 version of the BL struct */ - u32 rf_type; /* 0x880A44 ID of the connected RF */ - u32 baseband_type; /* 0x880A48 ID of the baseband */ - u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ - u8 pad[2]; -} __packed; - /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) -- cgit v1.2.3-70-g09d2 From 6093e66b6b456f4526e190b00d362520b787889b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:50 +0300 Subject: wil6210: count drops in Rx block ack reorder When performing Rx reordering, count skb's dropped per reorder buffer; and print dropped packets count on the "stations" debugfs entry Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 75219a1b8805..b862676de577 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1353,7 +1353,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); + seq_printf(s, "] drop %llu last 0x%03x\n", r->drop, r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index ca10dcf0986e..e4ac11cf0f50 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -153,6 +153,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { r->ssn_last_drop = seq; + r->drop++; dev_kfree_skb(skb); goto out; } @@ -173,6 +174,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* check if we already stored this frame */ if (r->reorder_buf[index]) { + r->drop++; dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b79ba4994d0c..54f16732d226 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -426,6 +426,7 @@ struct pci_dev; * @timeout: reset timer value (in TUs). * @dialog_token: dialog token for aggregation session * @rcu_head: RCU head used for freeing this struct + * @drop: total frames dropped for this reorder buffer * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -443,6 +444,7 @@ struct wil_tid_ampdu_rx { u16 buf_size; u16 timeout; u16 ssn_last_drop; + unsigned long long drop; u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.2.3-70-g09d2 From 8ea06188fd8cb4c6bb85663b6dedcab22f7ffba7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:51 +0300 Subject: wil6210: print "ulong" fields in hex format in the debugfs In the debugfs, there is "ulong" attribute printing. It is used for bitmap printing, and more appropriate format would be hexadecimal, not decimal. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b862676de577..2651ec4fb620 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -306,7 +306,7 @@ static int wil_debugfs_ulong_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, - wil_debugfs_ulong_set, "%llu\n"); + wil_debugfs_ulong_set, "0x%llx\n"); static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, -- cgit v1.2.3-70-g09d2 From 8a9d1dc5741da8575e3393de392cc1704ecd4fe7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:52 +0300 Subject: wil6210: use <> vs. "" for global include linux/device.h should be included using <>, not "" since it is not local include Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index de15f1422fe9..2e831bf20117 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "linux/device.h" +#include #include "wil_platform.h" int __init wil_platform_modinit(void) -- cgit v1.2.3-70-g09d2 From 3e9191fce2d6b36a429dc046cdc1f7e8ec70465c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:53 +0300 Subject: wil6210: wait for del_station to complete Multiple del_station requests may be sent to the driver by the supplicant when turning down AP. This may overflow mailbox between the FW and ucode Wait till disconnect of one STA completed before sending next command. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c759759afbb2..362ce7a257e8 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1129,15 +1129,42 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) { + int rc; + u16 reason_code; struct wmi_disconnect_sta_cmd cmd = { .disconnect_reason = cpu_to_le16(reason), }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_disconnect_event evt; + } __packed reply; ether_addr_copy(cmd.dst_mac, mac); wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); - return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); + rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd), + WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000); + /* failure to disconnect in reasonable time treated as FW error */ + if (rc) { + wil_fw_error_recovery(wil); + return rc; + } + + /* call event handler manually after processing wmi_call, + * to avoid deadlock - disconnect event handler acquires wil->mutex + * while it is already held here + */ + reason_code = le16_to_cpu(reply.evt.protocol_reason_status); + + wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", + reply.evt.bssid, reason_code, + reply.evt.disconnect_reason); + + wil->sinfo_gen++; + wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + + return 0; } int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) -- cgit v1.2.3-70-g09d2 From 8ad6600fbdd699f0d7a3ec250d20256a7ec98889 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:54 +0300 Subject: wil6210: use wil_fw_error_recovery() Use function wil_fw_error_recovery() instead of inline equivalent code Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index ae0df3588e5d..c77ae1739afc 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -271,8 +271,7 @@ static void wil_scan_timer_fn(ulong x) clear_bit(wil_status_fwready, wil->status); wil_err(wil, "Scan timeout detected, start fw error recovery\n"); - wil->recovery_state = fw_recovery_pending; - schedule_work(&wil->fw_error_worker); + wil_fw_error_recovery(wil); } static int wil_wait_for_recovery(struct wil6210_priv *wil) -- cgit v1.2.3-70-g09d2 From 67131a1dba5f45cee78e9de09605cbdda1a1ce6c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:55 +0300 Subject: wil6210: skip HW version check for chip debugging When loading with debug_fw flag, do not bail out on unknown chipId Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c77ae1739afc..33a3e9b136d9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -738,9 +738,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_dbg_misc(wil, "%s()\n", __func__); - if (wil->hw_version == HW_VER_UNKNOWN) - return -ENODEV; - WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(test_bit(wil_status_napi_en, wil->status)); @@ -755,6 +752,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return 0; } + if (wil->hw_version == HW_VER_UNKNOWN) + return -ENODEV; + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_bcast_fini(wil); -- cgit v1.2.3-70-g09d2 From 3d4bde15315605d2490eafe9f763897e69f9125e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:56 +0300 Subject: wil6210: TSO implementation Driver report supported TSO (v4 & v6) and IP checksum offload in addition to previously supported features. In data path skbs are checked for non-zero gso_size, and when detected sent to additional function for processing TSO SKBs. Since HW does not fully support TSO, additional effort is required from the driver. Driver partitions the data into mss sized descriptors which are then DMAed to the HW. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 4 +- drivers/net/wireless/ath/wil6210/txrx.c | 371 +++++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/txrx.h | 8 + 3 files changed, 371 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 8ef18ace110f..25c51167adff 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -173,7 +173,9 @@ void *wil_if_alloc(struct device *dev) wil_set_ethtoolops(ndev); ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | - NETIF_F_SG | NETIF_F_GRO; + NETIF_F_SG | NETIF_F_GRO | + NETIF_F_TSO | NETIF_F_TSO6; + ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index aa20af86e1d6..7722df78b267 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1058,14 +1058,52 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, static inline void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) { - d->mac.d[2] |= ((nr_frags + 1) << - MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); + d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); } -static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, - struct vring_tx_desc *d, - struct sk_buff *skb) +/** + * Sets the descriptor @d up for csum and/or TSO offloading. The corresponding + * @skb is used to obtain the protocol and headers length. + * @tso_desc_type is a descriptor type for TSO: 0 - a header, 1 - first data, + * 2 - middle, 3 - last descriptor. + */ + +static void wil_tx_desc_offload_setup_tso(struct vring_tx_desc *d, + struct sk_buff *skb, + int tso_desc_type, bool is_ipv4, + int tcp_hdr_len, int skb_net_hdr_len) { + d->dma.b11 = ETH_HLEN; /* MAC header length */ + d->dma.b11 |= is_ipv4 << DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS; + + d->dma.d0 |= (2 << DMA_CFG_DESC_TX_0_L4_TYPE_POS); + /* L4 header len: TCP header length */ + d->dma.d0 |= (tcp_hdr_len & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK); + + /* Setup TSO: bit and desc type */ + d->dma.d0 |= (BIT(DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS)) | + (tso_desc_type << DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS); + d->dma.d0 |= (is_ipv4 << DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS); + + d->dma.ip_length = skb_net_hdr_len; + /* Enable TCP/UDP checksum */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS); + /* Calculate pseudo-header */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS); +} + +/** + * Sets the descriptor @d up for csum. The corresponding + * @skb is used to obtain the protocol and headers length. + * Returns the protocol: 0 - not TCP, 1 - TCPv4, 2 - TCPv6. + * Note, if d==NULL, the function only returns the protocol result. + * + * It is very similar to previous wil_tx_desc_offload_setup_tso. This + * is "if unrolling" to optimize the critical path. + */ + +static int wil_tx_desc_offload_setup(struct vring_tx_desc *d, + struct sk_buff *skb){ int protocol; if (skb->ip_summed != CHECKSUM_PARTIAL) @@ -1110,6 +1148,305 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } +static inline void wil_tx_last_desc(struct vring_tx_desc *d) +{ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS) | + BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS) | + BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); +} + +static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d) +{ + d->dma.d0 |= wil_tso_type_lst << + DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS; +} + +static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + struct device *dev = wil_to_dev(wil); + + /* point to descriptors in shared memory */ + volatile struct vring_tx_desc *_desc = NULL, *_hdr_desc, + *_first_desc = NULL; + + /* pointers to shadow descriptors */ + struct vring_tx_desc desc_mem, hdr_desc_mem, first_desc_mem, + *d = &hdr_desc_mem, *hdr_desc = &hdr_desc_mem, + *first_desc = &first_desc_mem; + + /* pointer to shadow descriptors' context */ + struct wil_ctx *hdr_ctx, *first_ctx = NULL; + + int descs_used = 0; /* total number of used descriptors */ + int sg_desc_cnt = 0; /* number of descriptors for current mss*/ + + u32 swhead = vring->swhead; + int used, avail = wil_vring_avail_tx(vring); + int nr_frags = skb_shinfo(skb)->nr_frags; + int min_desc_required = nr_frags + 1; + int mss = skb_shinfo(skb)->gso_size; /* payload size w/o headers */ + int f, len, hdrlen, headlen; + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + uint i = swhead; + dma_addr_t pa; + const skb_frag_t *frag = NULL; + int rem_data = mss; + int lenmss; + int hdr_compensation_need = true; + int desc_tso_type = wil_tso_type_first; + bool is_ipv4; + int tcp_hdr_len; + int skb_net_hdr_len; + int gso_type; + + wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", + __func__, skb->len, vring_index); + + if (unlikely(!txdata->enabled)) + return -EINVAL; + + /* A typical page 4K is 3-4 payloads, we assume each fragment + * is a full payload, that's how min_desc_required has been + * calculated. In real we might need more or less descriptors, + * this is the initial check only. + */ + if (unlikely(avail < min_desc_required)) { + wil_err_ratelimited(wil, + "TSO: Tx ring[%2d] full. No space for %d fragments\n", + vring_index, min_desc_required); + return -ENOMEM; + } + + /* Header Length = MAC header len + IP header len + TCP header len*/ + hdrlen = ETH_HLEN + + (int)skb_network_header_len(skb) + + tcp_hdrlen(skb); + + gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV6 | SKB_GSO_TCPV4); + switch (gso_type) { + case SKB_GSO_TCPV4: + /* TCP v4, zero out the IP length and IPv4 checksum fields + * as required by the offloading doc + */ + ip_hdr(skb)->tot_len = 0; + ip_hdr(skb)->check = 0; + is_ipv4 = true; + break; + case SKB_GSO_TCPV6: + /* TCP v6, zero out the payload length */ + ipv6_hdr(skb)->payload_len = 0; + is_ipv4 = false; + break; + default: + /* other than TCPv4 or TCPv6 types are not supported for TSO. + * It is also illegal for both to be set simultaneously + */ + return -EINVAL; + } + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return -EINVAL; + + /* tcp header length and skb network header length are fixed for all + * packet's descriptors - read then once here + */ + tcp_hdr_len = tcp_hdrlen(skb); + skb_net_hdr_len = skb_network_header_len(skb); + + _hdr_desc = &vring->va[i].tx; + + pa = dma_map_single(dev, skb->data, hdrlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, pa))) { + wil_err(wil, "TSO: Skb head DMA map error\n"); + goto err_exit; + } + + wil_tx_desc_map(hdr_desc, pa, hdrlen, vring_index); + wil_tx_desc_offload_setup_tso(hdr_desc, skb, wil_tso_type_hdr, is_ipv4, + tcp_hdr_len, skb_net_hdr_len); + wil_tx_last_desc(hdr_desc); + + vring->ctx[i].mapped_as = wil_mapped_as_single; + hdr_ctx = &vring->ctx[i]; + + descs_used++; + headlen = skb_headlen(skb) - hdrlen; + + for (f = headlen ? -1 : 0; f < nr_frags; f++) { + if (headlen) { + len = headlen; + wil_dbg_txrx(wil, "TSO: process skb head, len %u\n", + len); + } else { + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + wil_dbg_txrx(wil, "TSO: frag[%d]: len %u\n", f, len); + } + + while (len) { + wil_dbg_txrx(wil, + "TSO: len %d, rem_data %d, descs_used %d\n", + len, rem_data, descs_used); + + if (descs_used == avail) { + wil_err(wil, "TSO: ring overflow\n"); + goto dma_error; + } + + lenmss = min_t(int, rem_data, len); + i = (swhead + descs_used) % vring->size; + wil_dbg_txrx(wil, "TSO: lenmss %d, i %d\n", lenmss, i); + + if (!headlen) { + pa = skb_frag_dma_map(dev, frag, + frag->size - len, lenmss, + DMA_TO_DEVICE); + vring->ctx[i].mapped_as = wil_mapped_as_page; + } else { + pa = dma_map_single(dev, + skb->data + + skb_headlen(skb) - headlen, + lenmss, + DMA_TO_DEVICE); + vring->ctx[i].mapped_as = wil_mapped_as_single; + headlen -= lenmss; + } + + if (unlikely(dma_mapping_error(dev, pa))) + goto dma_error; + + _desc = &vring->va[i].tx; + + if (!_first_desc) { + _first_desc = _desc; + first_ctx = &vring->ctx[i]; + d = first_desc; + } else { + d = &desc_mem; + } + + wil_tx_desc_map(d, pa, lenmss, vring_index); + wil_tx_desc_offload_setup_tso(d, skb, desc_tso_type, + is_ipv4, tcp_hdr_len, + skb_net_hdr_len); + + /* use tso_type_first only once */ + desc_tso_type = wil_tso_type_mid; + + descs_used++; /* desc used so far */ + sg_desc_cnt++; /* desc used for this segment */ + len -= lenmss; + rem_data -= lenmss; + + wil_dbg_txrx(wil, + "TSO: len %d, rem_data %d, descs_used %d, sg_desc_cnt %d,\n", + len, rem_data, descs_used, sg_desc_cnt); + + /* Close the segment if reached mss size or last frag*/ + if (rem_data == 0 || (f == nr_frags - 1 && len == 0)) { + if (hdr_compensation_need) { + /* first segment include hdr desc for + * release + */ + hdr_ctx->nr_frags = sg_desc_cnt; + wil_tx_desc_set_nr_frags(first_desc, + sg_desc_cnt + + 1); + hdr_compensation_need = false; + } else { + wil_tx_desc_set_nr_frags(first_desc, + sg_desc_cnt); + } + first_ctx->nr_frags = sg_desc_cnt - 1; + + wil_tx_last_desc(d); + + /* first descriptor may also be the last + * for this mss - make sure not to copy + * it twice + */ + if (first_desc != d) + *_first_desc = *first_desc; + + /*last descriptor will be copied at the end + * of this TS processing + */ + if (f < nr_frags - 1 || len > 0) + *_desc = *d; + + rem_data = mss; + _first_desc = NULL; + sg_desc_cnt = 0; + } else if (first_desc != d) /* update mid descriptor */ + *_desc = *d; + } + } + + /* first descriptor may also be the last. + * in this case d pointer is invalid + */ + if (_first_desc == _desc) + d = first_desc; + + /* Last data descriptor */ + wil_set_tx_desc_last_tso(d); + *_desc = *d; + + /* Fill the total number of descriptors in first desc (hdr)*/ + wil_tx_desc_set_nr_frags(hdr_desc, descs_used); + *_hdr_desc = *hdr_desc; + + /* hold reference to skb + * to prevent skb release before accounting + * in case of immediate "tx done" + */ + vring->ctx[i].skb = skb_get(skb); + + /* performance monitoring */ + used = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used, used + descs_used)) { + txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + vring_index, used, used + descs_used); + } + + /* advance swhead */ + wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_vring_advance_head(vring, descs_used); + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + + iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + return 0; + +dma_error: + wil_err(wil, "TSO: DMA map page error\n"); + while (descs_used > 0) { + struct wil_ctx *ctx; + + i = (swhead + descs_used) % vring->size; + d = (struct vring_tx_desc *)&vring->va[i].tx; + _desc = &vring->va[i].tx; + *d = *_desc; + _desc->dma.status = TX_DMA_STATUS_DU; + ctx = &vring->ctx[i]; + wil_txdesc_unmap(dev, d, ctx); + if (ctx->skb) + dev_kfree_skb_any(ctx->skb); + memset(ctx, 0, sizeof(*ctx)); + descs_used--; + } + +err_exit: + return -EINVAL; +} + static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb) { @@ -1128,7 +1465,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, bool mcast = (vring_index == wil->bcast_vring); uint len = skb_headlen(skb); - wil_dbg_txrx(wil, "%s()\n", __func__); + wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", + __func__, skb->len, vring_index); if (unlikely(!txdata->enabled)) return -EINVAL; @@ -1159,14 +1497,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS); } /* Process TCP/UDP checksum offloading */ - if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { + if (unlikely(wil_tx_desc_offload_setup(d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } vring->ctx[i].nr_frags = nr_frags; - wil_tx_desc_set_nr_frags(d, nr_frags); + wil_tx_desc_set_nr_frags(d, nr_frags + 1); /* middle segments */ for (; f < nr_frags; f++) { @@ -1190,7 +1528,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * if it succeeded for 1-st descriptor, * it will succeed here too */ - wil_tx_desc_offload_cksum_set(wil, d, skb); + wil_tx_desc_offload_setup(d, skb); } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); @@ -1221,6 +1559,12 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); return 0; @@ -1254,8 +1598,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, int rc; spin_lock(&txdata->lock); - rc = __wil_tx_vring(wil, vring, skb); + + rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) + (wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; } @@ -1382,7 +1730,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct wil_ctx *ctx = &vring->ctx[vring->swtail]; /** * For the fragmented skb, HW will set DU bit only for the - * last fragment. look for it + * last fragment. look for it. + * In TSO the first DU will include hdr desc */ int lf = (vring->swtail + ctx->nr_frags) % vring->size; /* TODO: check we are not past head */ diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 0c4638487c74..82a8f9a030e7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -291,6 +291,14 @@ struct vring_tx_dma { __le16 length; } __packed; +/* TSO type used in dma descriptor d0 bits 11-12 */ +enum { + wil_tso_type_hdr = 0, + wil_tso_type_first = 1, + wil_tso_type_mid = 2, + wil_tso_type_lst = 3, +}; + /* Rx descriptor - MAC part * [dword 0] * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field -- cgit v1.2.3-70-g09d2 From 90d89e9aaa9923cd44bd5bf8a26abb7834581ba6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:57 +0300 Subject: wil6210: improve mgmt frame handling Check event length; hex dump both Rx and Tx frames Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 54 +++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 362ce7a257e8..349f14ae9944 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -312,22 +312,44 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) struct wiphy *wiphy = wil_to_wiphy(wil); struct ieee80211_mgmt *rx_mgmt_frame = (struct ieee80211_mgmt *)data->payload; - int ch_no = data->info.channel+1; - u32 freq = ieee80211_channel_to_frequency(ch_no, - IEEE80211_BAND_60GHZ); - struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); - s32 signal = data->info.sqi; - __le16 fc = rx_mgmt_frame->frame_control; - u32 d_len = le32_to_cpu(data->info.len); - u16 d_status = le16_to_cpu(data->info.status); - - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", + int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload); + int ch_no; + u32 freq; + struct ieee80211_channel *channel; + s32 signal; + __le16 fc; + u32 d_len; + u16 d_status; + + if (flen < 0) { + wil_err(wil, "MGMT Rx: short event, len %d\n", len); + return; + } + + d_len = le32_to_cpu(data->info.len); + if (d_len != flen) { + wil_err(wil, + "MGMT Rx: length mismatch, d_len %d should be %d\n", + d_len, flen); + return; + } + + ch_no = data->info.channel + 1; + freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); + channel = ieee80211_get_channel(wiphy, freq); + signal = data->info.sqi; + d_status = le16_to_cpu(data->info.status); + fc = rx_mgmt_frame->frame_control; + + wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n", data->info.channel, data->info.mcs, data->info.snr, data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); + wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame, + d_len, true); if (!channel) { wil_err(wil, "Frame on unsupported channel\n"); @@ -363,6 +385,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } +static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) +{ + struct wmi_tx_mgmt_packet_event *data = d; + struct ieee80211_mgmt *mgmt_frame = + (struct ieee80211_mgmt *)data->payload; + int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload); + + wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame, + flen, true); +} + static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, void *d, int len) { @@ -659,6 +692,7 @@ static const struct { {WMI_READY_EVENTID, wmi_evt_ready}, {WMI_FW_READY_EVENTID, wmi_evt_fw_ready}, {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt}, + {WMI_TX_MGMT_PACKET_EVENTID, wmi_evt_tx_mgmt}, {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, {WMI_CONNECT_EVENTID, wmi_evt_connect}, {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, -- cgit v1.2.3-70-g09d2 From a3ce5ccd50ee24313fa3e55d2cafc6da7dfcbe18 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 30 Jul 2015 13:51:58 +0300 Subject: wil6210: treat "unhandled event" as warning instead of error FW is allowed to generate WMI events that are not handled by this driver. Treat such case as warning instead of error. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 349f14ae9944..fbcea838ccfa 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1340,7 +1340,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, /* search for handler */ if (!wmi_evt_call_handler(wil, id, evt_data, len - sizeof(*wmi))) { - wil_err(wil, "Unhandled event 0x%04x\n", id); + wil_info(wil, "Unhandled event 0x%04x\n", id); } } else { wil_err(wil, "Unknown event type\n"); -- cgit v1.2.3-70-g09d2 From cab5abbf9d0ef8b36d5f5181f0087ed3836385d0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:59 +0300 Subject: wil6210: sort IEs handling sort overall IE's handling prepare code (disabled for now) to add IEs for the beacon Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 78 +++++++++++------------------ 1 file changed, 29 insertions(+), 49 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e4be2d9bbac4..8811174e51c3 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -722,46 +722,51 @@ static int wil_fix_bcon(struct wil6210_priv *wil, { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - int rc = 0; if (bcon->probe_resp_len <= hlen) return 0; +/* always use IE's from full probe frame, they has more info + * notable RSN + */ + bcon->proberesp_ies = f->u.probe_resp.variable; + bcon->proberesp_ies_len = bcon->probe_resp_len - hlen; if (!bcon->assocresp_ies) { - bcon->assocresp_ies = f->u.probe_resp.variable; - bcon->assocresp_ies_len = bcon->probe_resp_len - hlen; - rc = 1; + bcon->assocresp_ies = bcon->proberesp_ies; + bcon->assocresp_ies_len = bcon->proberesp_ies_len; } - return rc; + return 1; } /* internal functions for device reset and starting AP */ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, - size_t probe_ies_len, const u8 *probe_ies, - size_t assoc_ies_len, const u8 *assoc_ies) - + struct cfg80211_beacon_data *bcon) { int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); - /* FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, probe_ies_len, probe_ies); + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, + bcon->proberesp_ies); if (rc) { wil_err(wil, "set_ie(PROBE_RESP) failed\n"); return rc; } - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, assoc_ies_len, assoc_ies); + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, + bcon->assocresp_ies); if (rc) { wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); return rc; } +#if 0 /* to use beacon IE's, remove this #if 0 */ + rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, + bcon->tail); + if (rc) { + wil_err(wil, "set_ie(BEACON) failed\n"); + return rc; + } +#endif return 0; } @@ -770,8 +775,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, const u8 *ssid, size_t ssid_len, u32 privacy, int bi, u8 chan, - size_t probe_ies_len, const u8 *probe_ies, - size_t assoc_ies_len, const u8 *assoc_ies, + struct cfg80211_beacon_data *bcon, u8 hidden_ssid) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); @@ -792,8 +796,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, if (rc) goto out; - rc = _wil_cfg80211_set_ies(wiphy, probe_ies_len, probe_ies, - assoc_ies_len, assoc_ies); + rc = _wil_cfg80211_set_ies(wiphy, bcon); if (rc) goto out; @@ -827,27 +830,20 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; - size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - const u8 *pr_ies = NULL; - size_t pr_ies_len = 0; int rc; u32 privacy = 0; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); - if (bcon->probe_resp_len > hlen) { - pr_ies = f->u.probe_resp.variable; - pr_ies_len = bcon->probe_resp_len - hlen; - } - if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); } - if (pr_ies && cfg80211_find_ie(WLAN_EID_RSN, pr_ies, pr_ies_len)) + if (bcon->proberesp_ies && + cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies, + bcon->proberesp_ies_len)) privacy = 1; /* in case privacy has changed, need to restart the AP */ @@ -860,14 +856,10 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, wdev->ssid_len, privacy, wdev->beacon_interval, - wil->channel, pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies, + wil->channel, bcon, wil->hidden_ssid); } else { - rc = _wil_cfg80211_set_ies(wiphy, pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies); + rc = _wil_cfg80211_set_ies(wiphy, bcon); } return rc; @@ -882,10 +874,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; - struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; - size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - const u8 *pr_ies = NULL; - size_t pr_ies_len = 0; u8 hidden_ssid; wil_dbg_misc(wil, "%s()\n", __func__); @@ -925,11 +913,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); - if (bcon->probe_resp_len > hlen) { - pr_ies = f->u.probe_resp.variable; - pr_ies_len = bcon->probe_resp_len - hlen; - } - if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); @@ -938,10 +921,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, info->ssid, info->ssid_len, info->privacy, info->beacon_interval, channel->hw_value, - pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies, - hidden_ssid); + bcon, hidden_ssid); return rc; } -- cgit v1.2.3-70-g09d2 From 5421bf0c1e37642f42758fe1c73e43b27901dd61 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:00 +0300 Subject: wil6210: unify wmi_set_ie() error handling When printing error message, provide string describing IE kind. Derive it from IE type This allows removing of error messages printing in callers Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 29 ++++++++--------------------- drivers/net/wireless/ath/wil6210/wmi.c | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 8811174e51c3..20d07ef679e8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -336,12 +336,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, else wil_dbg_misc(wil, "Scan has no IE's\n"); - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, - request->ie); - if (rc) { - wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc); + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); + if (rc) goto out; - } rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); @@ -462,10 +459,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, * ies in FW. */ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); - if (rc) { - wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); + if (rc) goto out; - } /* WMI_CONNECT_CMD */ memset(&conn, 0, sizeof(conn)); @@ -748,27 +743,19 @@ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); - if (rc) { - wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + if (rc) return rc; - } rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); - if (rc) { - wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); - return rc; - } #if 0 /* to use beacon IE's, remove this #if 0 */ - rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, - bcon->tail); - if (rc) { - wil_err(wil, "set_ie(BEACON) failed\n"); + if (rc) return rc; - } + + rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail); #endif - return 0; + return rc; } static int _wil_cfg80211_start_ap(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index fbcea838ccfa..b9cf9a68d565 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1022,12 +1022,21 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) { + static const char *const names[] = { + [WMI_FRAME_BEACON] = "BEACON", + [WMI_FRAME_PROBE_REQ] = "PROBE_REQ", + [WMI_FRAME_PROBE_RESP] = "WMI_FRAME_PROBE_RESP", + [WMI_FRAME_ASSOC_REQ] = "WMI_FRAME_ASSOC_REQ", + [WMI_FRAME_ASSOC_RESP] = "WMI_FRAME_ASSOC_RESP", + }; int rc; u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + rc = -ENOMEM; + goto out; + } if (!ie) ie_len = 0; @@ -1037,6 +1046,12 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); kfree(cmd); +out: + if (rc) { + const char *name = type < ARRAY_SIZE(names) ? + names[type] : "??"; + wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc); + } return rc; } -- cgit v1.2.3-70-g09d2 From 91a8edcc3173958fd8102343a8a7919a7b703ef0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:01 +0300 Subject: wil6210: detailed statistics for Rx reorder drop Rx drops may be for 2 reasons: frame is old, or it is duplicate. On the debugfs "stations" entry, provide counters per reorder buffer for total frames processed, drops for these 2 reasons. Also add debug print for dropped frames. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++++- drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 ++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 15 ++++++++------- 3 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 2651ec4fb620..05b550f32914 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1344,6 +1344,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, r->head_seq_num); @@ -1353,7 +1354,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_printf(s, "] drop %llu last 0x%03x\n", r->drop, r->ssn_last_drop); + seq_printf(s, + "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n", + r->total, drop_dup + drop_old, drop_dup, drop_old, + r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index e4ac11cf0f50..9238c1ac23dd 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -121,6 +121,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) goto out; } + r->total++; hseq = r->head_seq_num; /** Due to the race between WMI events, where BACK establishment @@ -153,7 +154,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { r->ssn_last_drop = seq; - r->drop++; + r->drop_old++; + wil_dbg_txrx(wil, "Rx drop: old seq 0x%03x head 0x%03x\n", + seq, r->head_seq_num); dev_kfree_skb(skb); goto out; } @@ -174,7 +177,8 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* check if we already stored this frame */ if (r->reorder_buf[index]) { - r->drop++; + r->drop_dup++; + wil_dbg_txrx(wil, "Rx drop: dup seq 0x%03x\n", seq); dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 54f16732d226..c72272449652 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -424,13 +424,12 @@ struct pci_dev; * @ssn: Starting Sequence Number expected to be aggregated. * @buf_size: buffer size for incoming A-MPDUs * @timeout: reset timer value (in TUs). + * @ssn_last_drop: SSN of the last dropped frame + * @total: total number of processed incoming frames + * @drop_dup: duplicate frames dropped for this reorder buffer + * @drop_old: old frames dropped for this reorder buffer * @dialog_token: dialog token for aggregation session - * @rcu_head: RCU head used for freeing this struct - * @drop: total frames dropped for this reorder buffer - * - * This structure's lifetime is managed by RCU, assignments to - * the array holding it must hold the aggregation mutex. - * + * @first_time: true when this buffer used 1-st time */ struct wil_tid_ampdu_rx { struct sk_buff **reorder_buf; @@ -444,7 +443,9 @@ struct wil_tid_ampdu_rx { u16 buf_size; u16 timeout; u16 ssn_last_drop; - unsigned long long drop; + unsigned long long total; /* frames processed */ + unsigned long long drop_dup; + unsigned long long drop_old; u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.2.3-70-g09d2 From bd2d18b50631c027af7674c3f328913c3b87d422 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:02 +0300 Subject: wil6210: remove 3-MSI support In the recent kernel versions, multiple MSI is not well supported. In particular, it is not supported on x86 and ARM architectures. Also, internal interrupt handling logic is simpler and more effective when using single interrupt. Remove support for 3 MSI, convert module parameter "use_msi" from int with range [0,1,3] to boolean. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/interrupt.c | 55 +++------------------------ drivers/net/wireless/ath/wil6210/pcie_bus.c | 56 ++++++---------------------- drivers/net/wireless/ath/wil6210/wil6210.h | 3 +- 3 files changed, 18 insertions(+), 96 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 28ffc18466c4..596d09b8c60a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -541,42 +541,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) return rc; } -static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) -{ - int rc; - /* - * IRQ's are in the following order: - * - Tx - * - Rx - * - Misc - */ - - rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, - WIL_NAME"_tx", wil); - if (rc) - return rc; - - rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, - WIL_NAME"_rx", wil); - if (rc) - goto free0; - - rc = request_threaded_irq(irq + 2, wil6210_irq_misc, - wil6210_irq_misc_thread, - IRQF_SHARED, WIL_NAME"_misc", wil); - if (rc) - goto free1; - - return 0; - /* error branch */ -free1: - free_irq(irq + 1, wil); -free0: - free_irq(irq, wil); - - return rc; -} - /* can't use wil_ioread32_and_clear because ICC value is not set yet */ static inline void wil_clear32(void __iomem *addr) { @@ -596,19 +560,16 @@ void wil6210_clear_irq(struct wil6210_priv *wil) wmb(); /* make sure write completed */ } -int wil6210_init_irq(struct wil6210_priv *wil, int irq) +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi) { int rc; - wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi); + wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx"); - if (wil->n_msi == 3) - rc = wil6210_request_3msi(wil, irq); - else - rc = request_threaded_irq(irq, wil6210_hardirq, - wil6210_thread_irq, - wil->n_msi ? 0 : IRQF_SHARED, - WIL_NAME, wil); + rc = request_threaded_irq(irq, wil6210_hardirq, + wil6210_thread_irq, + use_msi ? 0 : IRQF_SHARED, + WIL_NAME, wil); return rc; } @@ -618,8 +579,4 @@ void wil6210_fini_irq(struct wil6210_priv *wil, int irq) wil_mask_irq(wil); free_irq(irq, wil); - if (wil->n_msi == 3) { - free_irq(irq + 1, wil); - free_irq(irq + 2, wil); - } } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index aa3ecc607ca3..d065b796d67e 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -21,11 +21,9 @@ #include "wil6210.h" -static int use_msi = 1; -module_param(use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, - " Use MSI interrupt: " - "0 - don't, 1 - (default) - single, or 3"); +static bool use_msi = true; +module_param(use_msi, bool, S_IRUGO); +MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); static void wil_set_capabilities(struct wil6210_priv *wil) @@ -50,24 +48,12 @@ void wil_set_capabilities(struct wil6210_priv *wil) void wil_disable_irq(struct wil6210_priv *wil) { - int irq = wil->pdev->irq; - - disable_irq(irq); - if (wil->n_msi == 3) { - disable_irq(irq + 1); - disable_irq(irq + 2); - } + disable_irq(wil->pdev->irq); } void wil_enable_irq(struct wil6210_priv *wil) { - int irq = wil->pdev->irq; - - enable_irq(irq); - if (wil->n_msi == 3) { - enable_irq(irq + 1); - enable_irq(irq + 2); - } + enable_irq(wil->pdev->irq); } /* Bus ops */ @@ -80,6 +66,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) * and only MSI should be used */ int msi_only = pdev->msi_enabled; + bool _use_msi = use_msi; wil_dbg_misc(wil, "%s()\n", __func__); @@ -87,41 +74,20 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) pci_set_master(pdev); - /* - * how many MSI interrupts to request? - */ - switch (use_msi) { - case 3: - case 1: - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); - break; - case 0: - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); - break; - default: - wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); - use_msi = 1; - } - - if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { - wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); - use_msi = 1; - } + wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); - if (use_msi == 1 && pci_enable_msi(pdev)) { + if (use_msi && pci_enable_msi(pdev)) { wil_err(wil, "pci_enable_msi failed, use INTx\n"); - use_msi = 0; + _use_msi = false; } - wil->n_msi = use_msi; - - if ((wil->n_msi == 0) && msi_only) { + if (!_use_msi && msi_only) { wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); rc = -ENODEV; goto stop_master; } - rc = wil6210_init_irq(wil, pdev->irq); + rc = wil6210_init_irq(wil, pdev->irq, _use_msi); if (rc) goto stop_master; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c72272449652..3c22178f6729 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -536,7 +536,6 @@ struct pmc_ctx { struct wil6210_priv { struct pci_dev *pdev; - int n_msi; struct wireless_dev *wdev; void __iomem *csr; DECLARE_BITMAP(status, wil_status_last); @@ -739,7 +738,7 @@ void wil_back_tx_worker(struct work_struct *work); void wil_back_tx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); -int wil6210_init_irq(struct wil6210_priv *wil, int irq); +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil_mask_irq(struct wil6210_priv *wil); void wil_unmask_irq(struct wil6210_priv *wil); -- cgit v1.2.3-70-g09d2 From b9eeb512496f1b1b5a6e0748c947277d95003af5 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:03 +0300 Subject: wil6210: use inline functions for register access Replace macros like "R", "W", "S", "C", defined multiple times, with inline functions "wil_[rwsc]". Use "readl" and "writel" instead of "ioread32" and "iowrite32" since it is granted that memory transactions are used, not port ones like IN/OUT Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 8 +- drivers/net/wireless/ath/wil6210/ethtool.c | 14 +--- drivers/net/wireless/ath/wil6210/fw.c | 10 --- drivers/net/wireless/ath/wil6210/fw_inc.c | 16 ++-- drivers/net/wireless/ath/wil6210/interrupt.c | 110 ++++++++++++--------------- drivers/net/wireless/ath/wil6210/ioctl.c | 4 +- drivers/net/wireless/ath/wil6210/main.c | 94 ++++++++++------------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 6 +- drivers/net/wireless/ath/wil6210/wil6210.h | 31 +++++++- drivers/net/wireless/ath/wil6210/wmi.c | 26 +++---- 11 files changed, 151 insertions(+), 170 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 05b550f32914..613ca2b2527b 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -62,7 +62,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " swhead = %d\n", vring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); if (x) { - v = ioread32(x); + v = readl(x); seq_printf(s, "0x%08x = %d\n", v, v); } else { seq_puts(s, "???\n"); @@ -268,7 +268,7 @@ static const struct file_operations fops_mbox = { static int wil_debugfs_iomem_x32_set(void *data, u64 val) { - iowrite32(val, (void __iomem *)data); + writel(val, (void __iomem *)data); wmb(); /* make sure write propagated to HW */ return 0; @@ -276,7 +276,7 @@ static int wil_debugfs_iomem_x32_set(void *data, u64 val) static int wil_debugfs_iomem_x32_get(void *data, u64 *val) { - *val = ioread32((void __iomem *)data); + *val = readl((void __iomem *)data); return 0; } @@ -477,7 +477,7 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data) void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); if (a) - seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); + seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a)); else seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 0ea695ff98ad..7053b62ca8d3 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,19 +50,13 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, wil_dbg_misc(wil, "%s()\n", __func__); - tx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) - tx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); - rx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL); if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) - rx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); + rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 4428345e5a47..82aae2d705b4 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -22,16 +22,6 @@ MODULE_FIRMWARE(WIL_FW_NAME); MODULE_FIRMWARE(WIL_FW2_NAME); -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#define S(a, v) W(a, R(a) | v) -/* register clear = read, AND with inverted, write */ -#define C(a, v) W(a, R(a) & ~v) - static void wil_memset_toio_32(volatile void __iomem *dst, u32 val, size_t count) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 157f5ef384e0..d30657ee7e83 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -221,12 +221,12 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, FW_ADDR_CHECK(dst, block[i].addr, "address"); - x = ioread32(dst); + x = readl(dst); y = (x & m) | (v & ~m); wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x " "(old 0x%08x val 0x%08x mask 0x%08x)\n", le32_to_cpu(block[i].addr), y, x, v, m); - iowrite32(y, dst); + writel(y, dst); wmb(); /* finish before processing next record */ } @@ -239,18 +239,18 @@ static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr, { unsigned delay = 0; - iowrite32(a, gwa_addr); - iowrite32(gw_cmd, gwa_cmd); + writel(a, gwa_addr); + writel(gw_cmd, gwa_cmd); wmb(); /* finish before activate gw */ - iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ + writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ do { udelay(1); /* typical time is few usec */ if (delay++ > 100) { wil_err_fw(wil, "gw timeout\n"); return -EINVAL; } - } while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ + } while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ return 0; } @@ -305,7 +305,7 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n", i, a, v); - iowrite32(v, gwa_val); + writel(v, gwa_val); rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); if (rc) return rc; @@ -372,7 +372,7 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, sizeof(v), false); for (k = 0; k < ARRAY_SIZE(block->value); k++) - iowrite32(v[k], gwa_val[k]); + writel(v[k], gwa_val[k]); rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); if (rc) return rc; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 596d09b8c60a..a371f036d054 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -61,13 +61,13 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr) static inline void wil_icr_clear(u32 x, void __iomem *addr) { - iowrite32(x, addr); + writel(x, addr); } #endif /* defined(CONFIG_WIL6210_ISR_COR) */ static inline u32 wil_ioread32_and_clear(void __iomem *addr) { - u32 x = ioread32(addr); + u32 x = readl(addr); wil_icr_clear(x, addr); @@ -76,54 +76,47 @@ static inline u32 wil_ioread32_and_clear(void __iomem *addr) static void wil6210_mask_irq_tx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_rx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_misc(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); + wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE); clear_bit(wil_status_irqen, wil->status); } void wil6210_unmask_irq_tx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_TX, wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_TX); } void wil6210_unmask_irq_rx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_RX, wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_RX); } static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_MISC, wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_MISC); } static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) @@ -132,8 +125,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) set_bit(wil_status_irqen, wil->status); - iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); + wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK); } void wil_mask_irq(struct wil6210_priv *wil) @@ -150,12 +142,12 @@ void wil_unmask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICC)); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICC)); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, ICC)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); wil6210_unmask_irq_pseudo(wil); wil6210_unmask_irq_tx(wil); @@ -163,9 +155,6 @@ void wil_unmask_irq(struct wil6210_priv *wil) wil6210_unmask_irq_misc(wil); } -/* target write operation */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) - void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); @@ -177,44 +166,42 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil) return; /* Disable and clear tx counter before (re)configuration */ - W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); - W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); + wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n", wil->tx_max_burst_duration); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_TX_CNT_CTL, - BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, + BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); /* Disable and clear tx idle counter before (re)configuration */ - W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); - W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n", wil->tx_interframe_timeout); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | - BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); /* Disable and clear rx counter before (re)configuration */ - W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); - W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); + wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n", wil->rx_max_burst_duration); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_RX_CNT_CTL, - BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, + BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); /* Disable and clear rx idle counter before (re)configuration */ - W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); - W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n", wil->rx_interframe_timeout); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | - BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); } -#undef W - static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -452,27 +439,24 @@ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) u32 icr_rx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_rx = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + + offsetof(struct RGF_ICR, IMV)); u32 icm_tx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICM)); u32 icr_tx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_tx = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + offsetof(struct RGF_ICR, IMV)); u32 icm_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICM)); u32 icr_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_misc = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + + offsetof(struct RGF_ICR, IMV)); wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" @@ -492,7 +476,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) { irqreturn_t rc = IRQ_HANDLED; struct wil6210_priv *wil = cookie; - u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); + u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE); /** * pseudo_cause is Clear-On-Read, no need to ACK @@ -544,9 +528,9 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) /* can't use wil_ioread32_and_clear because ICC value is not set yet */ static inline void wil_clear32(void __iomem *addr) { - u32 x = ioread32(addr); + u32 x = readl(addr); - iowrite32(x, addr); + writel(x, addr); } void wil6210_clear_irq(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c index e9c0673819c6..f7f948621951 100644 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ b/drivers/net/wireless/ath/wil6210/ioctl.c @@ -76,11 +76,11 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: - io.val = ioread32(a); + io.val = readl(a); need_copy = true; break; case wil_mmio_write: - iowrite32(io.val, a); + writel(io.val, a); wmb(); /* make sure write propagated to HW */ break; default: diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 33a3e9b136d9..44223236a629 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -528,26 +528,16 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#define S(a, v) W(a, R(a) | v) -/* register clear = read, AND with inverted, write */ -#define C(a, v) W(a, R(a) & ~v) - static inline void wil_halt_cpu(struct wil6210_priv *wil) { - W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); - W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST); + wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); + wil_w(wil, RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST); } static inline void wil_release_cpu(struct wil6210_priv *wil) { /* Start CPU */ - W(RGF_USER_USER_CPU_0, 1); + wil_w(wil, RGF_USER_USER_CPU_0, 1); } static int wil_target_reset(struct wil6210_priv *wil) @@ -558,58 +548,60 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); /* Clear MAC link up */ - S(RGF_HP_CTRL, BIT(15)); - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); + wil_s(wil, RGF_HP_CTRL, BIT(15)); + wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); + wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); wil_halt_cpu(wil); /* clear all boot loader "ready" bits */ - W(RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); + wil_w(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* Clear Fw Download notification */ - C(RGF_USER_USAGE_6, BIT(0)); + wil_c(wil, RGF_USER_USAGE_6, BIT(0)); - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + wil_s(wil, RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); /* XTAL stabilization should take about 3ms */ usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); + x = wil_r(wil, RGF_CAF_PLL_LOCK_STATUS); if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { wil_err(wil, "Xtal stabilization timeout\n" "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); return -ETIME; } /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + wil_c(wil, RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + /* reset A2 PCIE AHB */ + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, - boot_loader_ready)); + x = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; @@ -621,11 +613,11 @@ static int wil_target_reset(struct wil6210_priv *wil) } } while (x != BL_READY); - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); /* enable fix for HW bug related to the SA/DA swap in AP Rx */ - S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | - BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; @@ -651,8 +643,9 @@ static int wil_get_bl_info(struct wil6210_priv *wil) u8 *mac; u16 rf_status; - bl_ver = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, - boot_loader_struct_version)); + bl_ver = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); switch (bl_ver) { case 0: wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), @@ -802,7 +795,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; /* Mark FW as loaded from host */ - S(RGF_USER_USAGE_6, 1); + wil_s(wil, RGF_USER_USAGE_6, 1); /* clear any interrupts which on-card-firmware * may have set @@ -810,8 +803,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil6210_clear_irq(wil); /* CAF_ICR - clear and mask */ /* it is W1C, clear by writing back same value */ - S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); - W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); wil_release_cpu(wil); } @@ -835,11 +828,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } -#undef R -#undef W -#undef S -#undef C - void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d065b796d67e..c37838dfe38a 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -28,7 +28,7 @@ MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); static void wil_set_capabilities(struct wil6210_priv *wil) { - u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); + u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); bitmap_zero(wil->hw_capabilities, hw_capability_last); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7722df78b267..359121f18674 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -509,7 +509,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) break; } } - iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); + wil_w(wil, v->hwtail, v->swtail); return rc; } @@ -1422,7 +1422,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, */ wmb(); - iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; dma_error: @@ -1565,7 +1565,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ wmb(); - iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; dma_error: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 3c22178f6729..c6b0fa26c403 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -252,9 +252,8 @@ enum { }; /* popular locations */ -#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) -#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ - offsetof(struct RGF_ICR, ICS)) +#define RGF_MBOX RGF_USER_USER_SCRATCH_PAD +#define HOST_MBOX HOSTADDR(RGF_MBOX) #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 /* ISR register bits */ @@ -649,6 +648,32 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +/* target operations */ +/* register read */ +static inline u32 wil_r(struct wil6210_priv *wil, u32 reg) +{ + return readl(wil->csr + HOSTADDR(reg)); +} + +/* register write. wmb() to make sure it is completed */ +static inline void wil_w(struct wil6210_priv *wil, u32 reg, u32 val) +{ + writel(val, wil->csr + HOSTADDR(reg)); + wmb(); /* wait for write to propagate to the HW */ +} + +/* register set = read, OR, write */ +static inline void wil_s(struct wil6210_priv *wil, u32 reg, u32 val) +{ + wil_w(wil, reg, wil_r(wil, reg) | val); +} + +/* register clear = read, AND with inverted, write */ +static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) +{ + wil_w(wil, reg, wil_r(wil, reg) & ~val); +} + #if defined(CONFIG_DYNAMIC_DEBUG) #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b9cf9a68d565..7a257360c420 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -228,8 +228,8 @@ 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--) { - r->tail = ioread32(wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, tx.tail)); + r->tail = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, tx.tail)); if (next_head != r->tail) break; msleep(20); @@ -254,16 +254,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); /* mark entry as full */ - iowrite32(1, wil->csr + HOSTADDR(r->head) + - offsetof(struct wil6210_mbox_ring_desc, sync)); + wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1); /* advance next ptr */ - iowrite32(r->head = next_head, wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, tx.head)); + wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head), + r->head = next_head); trace_wil6210_wmi_cmd(&cmd.wmi, buf, len); /* interrupt to FW */ - iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); + wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS), + SW_INT_MBOX); return 0; } @@ -729,8 +729,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) u16 len; bool q; - r->head = ioread32(wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, rx.head)); + r->head = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.head)); if (r->tail == r->head) break; @@ -768,8 +768,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) cmd = (void *)&evt->event.wmi; wil_memcpy_fromio_32(cmd, src, len); /* mark entry as empty */ - iowrite32(0, wil->csr + HOSTADDR(r->tail) + - offsetof(struct wil6210_mbox_ring_desc, sync)); + wil_w(wil, r->tail + + offsetof(struct wil6210_mbox_ring_desc, sync), 0); /* indicate */ if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { @@ -788,8 +788,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) /* advance tail */ r->tail = r->base + ((r->tail - r->base + sizeof(struct wil6210_mbox_ring_desc)) % r->size); - iowrite32(r->tail, wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, rx.tail)); + wil_w(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail); /* add to the pending list */ spin_lock_irqsave(&wil->wmi_ev_lock, flags); -- cgit v1.2.3-70-g09d2 From 0553640d28baf77cf0fb91c8a834059f0b9be972 Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Thu, 30 Jul 2015 13:52:04 +0300 Subject: wil6210: allow to handle Rx on 2 cores Allow network stack part of Rx processing to run on separate core, relaxing CPU utilization on the core used for Rx NAPI. If RXHASH feature is enabled, the driver sets rxhash of each skb to 1 to enable RPS. The core for processing the rx skb is determined by RPS mechanism according to rx_cpus bit mask which is configured at user level. For processing skbs on different core from the core which processes the interrupts, it is recommended not to enable core 0 in rx_cpus bit mask. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 3 ++- drivers/net/wireless/ath/wil6210/txrx.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 25c51167adff..e3b3c8fb4605 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -174,7 +174,8 @@ void *wil_if_alloc(struct device *dev) ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GRO | - NETIF_F_TSO | NETIF_F_TSO6; + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXHASH; ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 359121f18674..6229110d558a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -541,6 +541,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) [GRO_DROP] = "GRO_DROP", }; + if (ndev->features & NETIF_F_RXHASH) + /* fake L4 to ensure it won't be re-calculated later + * set hash to any non-zero value to activate rps + * mechanism, core will be chosen according + * to user-level rps configuration. + */ + skb_set_hash(skb, 1, PKT_HASH_TYPE_L4); + skb_orphan(skb); if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { -- cgit v1.2.3-70-g09d2 From 93cb679a768bb526a60a9c4ce30beb45465334be Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:05 +0300 Subject: wil6210: system power management Support for the system suspend/resume. In preparation for the run-time PM, implementation made run-time PM friendly: common for system and run-time PM code factored out as generic functions, albeit is_runtime parameter value is always false currently. For debug purposes, "PM" debug category introduced. Policy: AP-like interface can't be suspended; otherwise suspend is allowed. Hardware brought down if interface was up. Connection, if existed, get lost. Interface will be brought up upon resume if it was up before suspend. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/Makefile | 1 + drivers/net/wireless/ath/wil6210/pcie_bus.c | 69 ++++++++++++++++++++ drivers/net/wireless/ath/wil6210/pm.c | 98 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++ 4 files changed, 173 insertions(+) create mode 100644 drivers/net/wireless/ath/wil6210/pm.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 050506f842e9..64b432625fbb 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -12,6 +12,7 @@ wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o +wil6210-y += pm.o wil6210-y += pmc.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index c37838dfe38a..feff1ef10fb3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -259,11 +259,80 @@ static const struct pci_device_id wil6210_pcie_ids[] = { }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); +#ifdef CONFIG_PM + +static int wil6210_suspend(struct device *dev, bool is_runtime) +{ + int rc = 0; + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + rc = wil_can_suspend(wil, is_runtime); + if (rc) + goto out; + + rc = wil_suspend(wil, is_runtime); + if (rc) + goto out; + + /* TODO: how do I bring card in low power state? */ + + /* disable bus mastering */ + pci_clear_master(pdev); + /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + +out: + return rc; +} + +static int wil6210_resume(struct device *dev, bool is_runtime) +{ + int rc = 0; + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + /* allow master */ + pci_set_master(pdev); + + rc = wil_resume(wil, is_runtime); + if (rc) + pci_clear_master(pdev); + + return rc; +} + +#ifdef CONFIG_PM_SLEEP +static int wil6210_pm_suspend(struct device *dev) +{ + return wil6210_suspend(dev, false); +} + +static int wil6210_pm_resume(struct device *dev) +{ + return wil6210_resume(dev, false); +} +#endif /* CONFIG_PM_SLEEP */ + +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops wil6210_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) +}; + static struct pci_driver wil6210_driver = { .probe = wil_pcie_probe, .remove = wil_pcie_remove, .id_table = wil6210_pcie_ids, .name = WIL_NAME, + .driver = { + .pm = &wil6210_pm_ops, + }, }; static int __init wil6210_driver_init(void) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c new file mode 100644 index 000000000000..0b7ecbcac19c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 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 "wil6210.h" + +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct wireless_dev *wdev = wil->wdev; + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + switch (wdev->iftype) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + break; + /* AP-like interface - can't suspend */ + default: + wil_dbg_pm(wil, "AP-like interface\n"); + rc = -EBUSY; + break; + } + + wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__, + is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + + return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + /* if netif up, hardware is alive, shut it down */ + if (ndev->flags & IFF_UP) { + rc = wil_down(wil); + if (rc) { + wil_err(wil, "wil_down : %d\n", rc); + goto out; + } + } + + if (wil->platform_ops.suspend) + rc = wil->platform_ops.suspend(wil->platform_handle); + +out: + wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, + is_runtime ? "runtime" : "system", rc); + return rc; +} + +int wil_resume(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + if (wil->platform_ops.resume) { + rc = wil->platform_ops.resume(wil->platform_handle); + if (rc) { + wil_err(wil, "platform_ops.resume : %d\n", rc); + goto out; + } + } + + /* if netif up, bring hardware up + * During open(), IFF_UP set after actual device method + * invocation. This prevent recursive call to wil_up() + */ + if (ndev->flags & IFF_UP) + rc = wil_up(wil); + +out: + wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, + is_runtime ? "runtime" : "system", rc); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c6b0fa26c403..dd4ea926b8e3 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -647,6 +647,7 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +#define wil_dbg_pm(wil, fmt, arg...) wil_dbg(wil, "DBG[ PM ]" fmt, ##arg) /* target operations */ /* register read */ @@ -815,4 +816,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name); +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_resume(struct wil6210_priv *wil, bool is_runtime); + #endif /* __WIL6210_H__ */ -- cgit v1.2.3-70-g09d2 From 409ead544d747a5e80fdd3626a7fd75d6990a2fb Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:06 +0300 Subject: wil6210: report boot loader error Boot loader reports error starting from the struct v2. Print error info before reset (power up state) in debug mode, and print same info as error if target reset timed out. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/boot_loader.h | 5 ++++ drivers/net/wireless/ath/wil6210/main.c | 37 +++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h index 1b4fd402cba2..c131b5e1292f 100644 --- a/drivers/net/wireless/ath/wil6210/boot_loader.h +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -36,6 +36,11 @@ struct bl_dedicated_registers_v1 { u8 bl_version_minor; /* 0x880A53 BL ver. minor */ __le16 bl_version_subminor; /* 0x880A54 BL ver. subminor */ __le16 bl_version_build; /* 0x880A56 BL ver. build */ + /* valid only for version 2 and above */ + __le32 bl_assert_code; /* 0x880A58 BL Assert code */ + __le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ + __le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */ + __le32 bl_magic_number; /* 0x880AB8 BL Magic number */ } __packed; /* the following struct is the version 0 struct */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 44223236a629..d11a147489bf 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -663,6 +663,7 @@ static int wil_get_bl_info(struct wil6210_priv *wil) wil_info(wil, "Boot Loader build unknown for struct v0\n"); break; case 1: + case 2: wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl.bl1)); le32_to_cpus(&bl.bl1.boot_loader_ready); @@ -705,6 +706,37 @@ static int wil_get_bl_info(struct wil6210_priv *wil) return 0; } +static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) +{ + u32 bl_assert_code, bl_assert_blink, bl_magic_number; + u32 bl_ver = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); + + if (bl_ver < 2) + return; + + bl_assert_code = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_assert_code)); + bl_assert_blink = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_assert_blink)); + bl_magic_number = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_magic_number)); + + if (is_err) { + wil_err(wil, + "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", + bl_assert_code, bl_assert_blink, bl_magic_number); + } else { + wil_dbg_misc(wil, + "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", + bl_assert_code, bl_assert_blink, bl_magic_number); + } +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -770,10 +802,13 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); + wil_bl_crash_info(wil, false); rc = wil_target_reset(wil); wil_rx_fini(wil); - if (rc) + if (rc) { + wil_bl_crash_info(wil, true); return rc; + } rc = wil_get_bl_info(wil); if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ -- cgit v1.2.3-70-g09d2 From 19c871ce3ac5f99d4354b0345c7560f6d0f760bd Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:07 +0300 Subject: wil6210: support future boot loaders Boot loader versions as backward compatible, starting from v1 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d11a147489bf..2fb04c51da53 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -643,37 +643,26 @@ static int wil_get_bl_info(struct wil6210_priv *wil) u8 *mac; u16 rf_status; - bl_ver = wil_r(wil, RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, - boot_loader_struct_version)); - switch (bl_ver) { - case 0: - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), - sizeof(bl.bl0)); - le32_to_cpus(&bl.bl0.boot_loader_ready); - le32_to_cpus(&bl.bl0.boot_loader_struct_version); + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl)); + bl_ver = le32_to_cpu(bl.bl0.boot_loader_struct_version); + mac = bl.bl0.mac_address; + + if (bl_ver == 0) { le32_to_cpus(&bl.bl0.rf_type); le32_to_cpus(&bl.bl0.baseband_type); - mac = bl.bl0.mac_address; rf_status = 0; /* actually, unknown */ wil_info(wil, "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n", bl_ver, mac, bl.bl0.rf_type, bl.bl0.baseband_type); wil_info(wil, "Boot Loader build unknown for struct v0\n"); - break; - case 1: - case 2: - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), - sizeof(bl.bl1)); - le32_to_cpus(&bl.bl1.boot_loader_ready); - le32_to_cpus(&bl.bl1.boot_loader_struct_version); + } else { le16_to_cpus(&bl.bl1.rf_type); rf_status = le16_to_cpu(bl.bl1.rf_status); le32_to_cpus(&bl.bl1.baseband_type); le16_to_cpus(&bl.bl1.bl_version_subminor); le16_to_cpus(&bl.bl1.bl_version_build); - mac = bl.bl1.mac_address; wil_info(wil, "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n", bl_ver, mac, @@ -682,10 +671,6 @@ static int wil_get_bl_info(struct wil6210_priv *wil) wil_info(wil, "Boot Loader build %d.%d.%d.%d\n", bl.bl1.bl_version_major, bl.bl1.bl_version_minor, bl.bl1.bl_version_subminor, bl.bl1.bl_version_build); - break; - default: - wil_err(wil, "BL: unsupported struct version 0x%08x\n", bl_ver); - return -EINVAL; } if (!is_valid_ether_addr(mac)) { -- cgit v1.2.3-70-g09d2 From b4336a282db86b298b70563f8ed51782b36b772c Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Thu, 16 Jul 2015 18:50:01 +0200 Subject: mwifiex: sdio: reset adapter using mmc_hw_reset Since 1fb654fd97ff("mmc: sdio: add reset callback to bus operations"), sdio cards can be power cycled using mmc_hw_reset. The use mmc_remove_host/mmc_add_host is discouraged, because these are internal functions to the mmc core and should only be used by mmc hosts Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 51 ++++++++++++++++++++++++++----------- drivers/net/wireless/mwifiex/sdio.h | 3 +++ 2 files changed, 39 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index a0b121f3460c..e4c35ee12782 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -91,6 +91,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return -ENOMEM; card->func = func; + card->device_id = id; func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; @@ -2107,26 +2108,46 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static void mwifiex_recreate_adapter(struct sdio_mmc_card *card) +{ + struct sdio_func *func = card->func; + const struct sdio_device_id *device_id = card->device_id; + + /* TODO mmc_hw_reset does not require destroying and re-probing the + * whole adapter. Hence there was no need to for this rube-goldberg + * design to reload the fw from an external workqueue. If we don't + * destroy the adapter we could reload the fw from + * mwifiex_main_work_queue directly. + * The real difficulty with fw reset is to restore all the user + * settings applied through ioctl. By destroying and recreating the + * adapter, we take the easy way out, since we rely on user space to + * restore them. We assume that user space will treat the new + * incarnation of the adapter(interfaces) as if they had been just + * discovered and initializes them from scratch. + */ + + mwifiex_sdio_remove(func); + + /* power cycle the adapter */ + sdio_claim_host(func); + mmc_hw_reset(func->card->host); + sdio_release_host(func); + + mwifiex_sdio_probe(func, device_id); +} + static struct mwifiex_adapter *save_adapter; static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - struct mmc_host *target = card->func->card->host; - - /* The actual reset operation must be run outside of driver thread. - * This is because mmc_remove_host() will cause the device to be - * instantly destroyed, and the driver then needs to end its thread, - * leading to a deadlock. - * - * We run it in a totally independent workqueue. - */ - mwifiex_dbg(adapter, WARN, "Resetting card...\n"); - mmc_remove_host(target); - /* 200ms delay is based on experiment with sdhci controller */ - mdelay(200); - target->rescan_entered = 0; /* rescan non-removable cards */ - mmc_add_host(target); + /* TODO card pointer is unprotected. If the adapter is removed + * physically, sdio core might trigger mwifiex_sdio_remove, before this + * workqueue is run, which will destroy the adapter struct. When this + * workqueue eventually exceutes it will dereference an invalid adapter + * pointer + */ + mwifiex_recreate_adapter(card); } /* This function read/write firmware */ diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6f645cf47369..c44da610541a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -262,6 +262,9 @@ struct sdio_mmc_card { struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; + + /* needed for card reset */ + const struct sdio_device_id *device_id; }; struct mwifiex_sdio_device { -- cgit v1.2.3-70-g09d2 From e3a3ef25b8cb6d7a20b52dfdadd56516041ffb51 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:03 +0200 Subject: mwifiex: remove explicit mwifiex_complete_cmd calls standard call chain when releasing a cmd node: mwifiex_recycle_cmd_node -> mwifiex_insert_cmd_to_free_q -> mwifiex_complete_cmd, if wait_q_enabled calling mwifiex_complete_cmd explicitly and setting wait_q_enabled = false is redundant Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 207da40500f4..2f4715e45664 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -167,8 +167,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, mwifiex_dbg(adapter, ERROR, "DNLD_CMD: FW in reset state, ignore cmd %#x\n", cmd_code); - if (cmd_node->wait_q_enabled) - mwifiex_complete_cmd(adapter, cmd_node); mwifiex_recycle_cmd_node(adapter, cmd_node); queue_work(adapter->workqueue, &adapter->main_work); return -1; @@ -1024,6 +1022,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) adapter->curr_cmd->wait_q_enabled = false; adapter->cmd_wait_q.status = -1; mwifiex_complete_cmd(adapter, adapter->curr_cmd); + /* no recycle probably wait for response */ } /* Cancel all pending command */ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -1032,11 +1031,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); - if (cmd_node->wait_q_enabled) { + if (cmd_node->wait_q_enabled) adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter, cmd_node); - cmd_node->wait_q_enabled = false; - } mwifiex_recycle_cmd_node(adapter, cmd_node); spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); } @@ -1094,10 +1090,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); cmd_node = adapter->curr_cmd; - cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; mwifiex_recycle_cmd_node(adapter, cmd_node); - mwifiex_complete_cmd(adapter, adapter->curr_cmd); adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } -- cgit v1.2.3-70-g09d2 From aeb03000837eec7df4f57034106542efd60be02b Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:04 +0200 Subject: mwifiex: remove redundant reset of cmd_wait_q status mwifiex_cancel_pending_ioctl is called only from mwifiex_cmd_timeout_func. There the wait_q status is set to -ETIMEDWAIT before calling this function. Whether we reset the status to -1 or leave it at -ETIMEDWAIT at end doesn't matter since both are != 0 hence mean failure Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 2f4715e45664..87b6dee2b049 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1123,7 +1123,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) } } } - adapter->cmd_wait_q.status = -1; } /* -- cgit v1.2.3-70-g09d2 From e9f21d403699a4d299a02df107326f11acecd13e Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:05 +0200 Subject: mwifiex: remove CMD_F_CANCELED flag CMD_F_CANCELED was used to abort mwifiex_process_cmdresp in case it already started or starts processing the cmd. But this was probably not working the way intended: - it is racy: mwifiex_process_cmdresp might already have passed that test and is continuing to use the cmd node being recycled - mwifiex_process_cmdresp repeatedly uses adapter->curr_cmd which we just set to NULL - mwifiex_recycle_cmd_node will clear the flag The reason why it probably works is that mwifiex_cancel_pending_ioctl is only called from mwifiex_cmd_timeout_func, where the there is little chance of a command response still arriving Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 23 ++++++++++------------- drivers/net/wireless/mwifiex/fw.h | 1 - 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 87b6dee2b049..6458e17304ca 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -807,17 +807,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) adapter->is_cmd_timedout = 0; resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; - if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { - mwifiex_dbg(adapter, ERROR, - "CMD_RESP: %#x been canceled\n", - le16_to_cpu(resp->command)); - mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->curr_cmd = NULL; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - return -1; - } - if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { /* Copy original response back to response buffer */ struct mwifiex_ds_misc_cmd *hostcmd; @@ -1090,10 +1079,18 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); cmd_node = adapter->curr_cmd; - cmd_node->cmd_flag |= CMD_F_CANCELED; - mwifiex_recycle_cmd_node(adapter, cmd_node); + /* setting curr_cmd to NULL is quite dangerous, because + * mwifiex_process_cmdresp checks curr_cmd to be != NULL + * at the beginning then relies on it and dereferences + * it at will + * this probably works since mwifiex_cmd_timeout_func + * is the only caller of this function and responses + * at that point + */ adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + + mwifiex_recycle_cmd_node(adapter, cmd_node); } /* Cancel all pending scan command */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cff38ad129aa..9a8c1832d068 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -438,7 +438,6 @@ enum P2P_MODES { #define CMD_F_HOSTCMD (1 << 0) -#define CMD_F_CANCELED (1 << 1) #define HostCmd_CMD_ID_MASK 0x0fff -- cgit v1.2.3-70-g09d2 From c5bc15fce6aa33b7aeba4e049ceacfab66fa4a9f Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:06 +0200 Subject: mwifiex: simplify mwifiex_complete_cmd 600f5d909a54("mwifiex: cleanup ioctl wait queue and abstraction layer") introduced the wakeup_interruptible suppression in mwifiex_complete_cmd b1a47aa5e1e1("mwifiex: fix system hang issue in cmd timeout error case") then added wakup_interruptible to mwifiex_cmd_timeout_func the single place setting a status of ETIMEDOUT. Instead of doing extra work, using the standard call-chain will have the same effect: mwifiex_cancel_pending_ioctl -> mwifiex_recycle_cmd_node -> mwifiex_insert_cmd_to_free_q -> mwifiex_complete_cmd -> wake_up_interruptible The difference is that previously the condition was not set to true, but that's probably just an oversight in b1a47aa5e1e1 and shouldn't have any consequence Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 1 - drivers/net/wireless/mwifiex/sta_ioctl.c | 4 ++-- drivers/net/wireless/mwifiex/util.c | 12 ++++-------- 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 6458e17304ca..27b778d5164e 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -976,7 +976,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) if (cmd_node->wait_q_enabled) { adapter->cmd_wait_q.status = -ETIMEDOUT; - wake_up_interruptible(&adapter->cmd_wait_q.wait); mwifiex_cancel_pending_ioctl(adapter); } } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d8b7d9c20450..a6c8a4f7bfe9 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -66,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, if (status <= 0) { if (status == 0) status = -ETIMEDOUT; - mwifiex_dbg(adapter, ERROR, - "cmd_wait_q terminated: %d\n", status); + mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n", + status); mwifiex_cancel_all_pending_cmd(adapter); return status; } diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 2504e422364a..a5f34f2c1086 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -496,16 +496,12 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node) { - mwifiex_dbg(adapter, CMD, - "cmd completed: status=%d\n", + WARN_ON(!cmd_node->wait_q_enabled); + mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n", adapter->cmd_wait_q.status); - *(cmd_node->condition) = true; - - if (adapter->cmd_wait_q.status == -ETIMEDOUT) - mwifiex_dbg(adapter, ERROR, "cmd timeout\n"); - else - wake_up_interruptible(&adapter->cmd_wait_q.wait); + *cmd_node->condition = true; + wake_up_interruptible(&adapter->cmd_wait_q.wait); return 0; } -- cgit v1.2.3-70-g09d2 From eb61f9f623f78f463ec08b1c4a1defea9b511312 Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:40 +0200 Subject: ath9k: advertise p2p dev support when chanctx Advertise p2p device support when ath9k loaded with use_chanctx=1. This will fix problem, when first interface is an AP and next we would like to run p2p_find. Before p2p find (scan phase) failed with EOPNOTSUPP. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index eff0e5325e6a..89a457d02453 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -736,13 +736,14 @@ static const struct ieee80211_iface_limit if_limits_multi[] = { BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; static const struct ieee80211_iface_combination if_comb_multi[] = { { .limits = if_limits_multi, .n_limits = ARRAY_SIZE(if_limits_multi), - .max_interfaces = 2, + .max_interfaces = 3, .num_different_channels = 2, .beacon_int_infra_match = true, }, @@ -855,6 +856,10 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_WDS); + if (ath9k_is_chanctx_enabled()) + hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_P2P_DEVICE); + hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } -- cgit v1.2.3-70-g09d2 From d83520b7cd6e8c5399b1bd0d2f6f9ce733b10454 Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:41 +0200 Subject: ath9k: handle RoC cancel correctly In case we will get ROC cancel from mac80211 we should not call ieee80211_remain_on_channel_expired(). In other case I hit such warning on MIPS and p2p negotiation failed (tested with use_chanctx=1). ath: phy0: Starting RoC period ath: phy0: Channel definition created: 2412 MHz ath: phy0: Assigned next_chan to 2412 MHz ath: phy0: Offchannel duration for chan 2412 MHz : 506632 ath: phy0: ath_chanctx_set_next: current: 2412 MHz, next: 2412 MHz ath: phy0: Stopping current chanctx: 2412 ath: phy0: Flush timeout: 200 ath: phy0: ath_chanctx_set_next: Set channel 2412 MHz ath: phy0: Set channel: 2412 MHz width: 0 ath: phy0: Reset to 2412 MHz, HT40: 0 fastcc: 0 ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_TSF_TIMER, state: ATH_CHANCTX_STATE_IDLE ath: phy0: ath_offchannel_channel_change: offchannel state: ATH_OFFCHANNEL_ROC_START ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_SWITCH, state: ATH_CHANCTX_STATE_IDLE ath: phy0: Cancel RoC ath: phy0: RoC aborted ath: phy0: RoC request on vif: 00:03:7f:4e:a0:cd, type: 1 duration: 500 ath: phy0: Starting RoC period ath: phy0: Channel definition created: 2412 MHz ath: phy0: Assigned next_chan to 2412 MHz ath: phy0: Offchannel duration for chan 2412 MHz : 506705 ath: phy0: ath_chanctx_set_next: current: 2412 MHz, next: 2412 MHz ath: phy0: ath_offchannel_channel_change: offchannel state: ATH_OFFCHANNEL_ROC_START ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_SWITCH, state: ATH_CHANCTX_STATE_IDLE ------------[ cut here ]------------ WARNING: CPU: 0 PID: 3312 at drivers/net/wireless/ath/ath9k/main.c:2319 Modules linked in: ath9k ath9k_common ath9k_hw ath mac80211 cfg80211 Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 ++++++++- drivers/net/wireless/ath/ath9k/channel.c | 23 ++++++++++++++++------- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a7a81b3969ce..db7a7b64bcdf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -410,6 +410,12 @@ enum ath_offchannel_state { ATH_OFFCHANNEL_ROC_DONE, }; +enum ath_roc_complete_reason { + ATH_ROC_COMPLETE_EXPIRE, + ATH_ROC_COMPLETE_ABORT, + ATH_ROC_COMPLETE_CANCEL, +}; + struct ath_offchannel { struct ath_chanctx chan; struct timer_list timer; @@ -471,7 +477,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, void ath_chanctx_set_next(struct ath_softc *sc, bool force); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); -void ath_roc_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, + enum ath_roc_complete_reason reason); struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc); #else diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 206665059d66..90f5773a1a61 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -915,18 +915,27 @@ void ath_offchannel_next(struct ath_softc *sc) } } -void ath_roc_complete(struct ath_softc *sc, bool abort) +void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (abort) + sc->offchannel.roc_vif = NULL; + sc->offchannel.roc_chan = NULL; + + switch (reason) { + case ATH_ROC_COMPLETE_ABORT: ath_dbg(common, CHAN_CTX, "RoC aborted\n"); - else + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_EXPIRE: ath_dbg(common, CHAN_CTX, "RoC expired\n"); + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_CANCEL: + ath_dbg(common, CHAN_CTX, "RoC canceled\n"); + break; + } - sc->offchannel.roc_vif = NULL; - sc->offchannel.roc_chan = NULL; - ieee80211_remain_on_channel_expired(sc->hw); ath_offchannel_next(sc); ath9k_ps_restore(sc); } @@ -1058,7 +1067,7 @@ static void ath_offchannel_timer(unsigned long data) case ATH_OFFCHANNEL_ROC_START: case ATH_OFFCHANNEL_ROC_WAIT: sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; - ath_roc_complete(sc, false); + ath_roc_complete(sc, ATH_ROC_COMPLETE_EXPIRE); break; default: break; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc..b7b77e000507 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2246,7 +2246,7 @@ static void ath9k_cancel_pending_offchannel(struct ath_softc *sc) del_timer_sync(&sc->offchannel.timer); if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) - ath_roc_complete(sc, true); + ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT); } if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { @@ -2355,7 +2355,7 @@ static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) if (sc->offchannel.roc_vif) { if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) - ath_roc_complete(sc, true); + ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL); } mutex_unlock(&sc->mutex); -- cgit v1.2.3-70-g09d2 From f3771c08282afa1354c2e5a2fdade587f30db4fd Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:42 +0200 Subject: ath9k: setup rxfilter for all chanctx While mac80211 setup this per HW, set same rxfilter configuration for all chanctx. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b7b77e000507..3de829f13747 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1459,13 +1459,15 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx; u32 rfilt; changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; spin_lock_bh(&sc->chan_lock); - sc->cur_chan->rxfilter = *total_flags; + ath_for_each_chanctx(sc, ctx) + ctx->rxfilter = *total_flags; spin_unlock_bh(&sc->chan_lock); ath9k_ps_wakeup(sc); -- cgit v1.2.3-70-g09d2 From 1738203ee7291b5e93670d19a663fae03155aebc Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:43 +0200 Subject: ath9k: setup rxfilter when offchannel Setup rxfiler correctly for offchannel ctx. This fix problem we didn't configure rxfilter, next didn't receive probe requests and next failed p2p_find. This was seen when ath9k loaded with use_chanctx=1 Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3de829f13747..c27143ba9ffb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1468,6 +1468,9 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, spin_lock_bh(&sc->chan_lock); ath_for_each_chanctx(sc, ctx) ctx->rxfilter = *total_flags; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + sc->offchannel.chan.rxfilter = *total_flags; +#endif spin_unlock_bh(&sc->chan_lock); ath9k_ps_wakeup(sc); -- cgit v1.2.3-70-g09d2 From f419c5f1d8d28391a025618dee7e1a4fdc7a5654 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:12 +0200 Subject: ath9k: add fast-xmit support Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 89a457d02453..57f95f2dca5b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -827,6 +827,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); if (ath9k_ps_enable) ieee80211_hw_set(hw, SUPPORTS_PS); -- cgit v1.2.3-70-g09d2 From 592fa228f213932dc5ec433aade654d7352b3e08 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:13 +0200 Subject: ath9k: remove struct ath_atx_ac struct ath_atx_ac contains a list of active TIDs belonging to one WMM AC. This patch changes the code to track active station TIDs in the txq directly. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 12 +--- drivers/net/wireless/ath/ath9k/xmit.c | 128 ++++++++++----------------------- 2 files changed, 41 insertions(+), 99 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index db7a7b64bcdf..ac1f10028fe7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -172,14 +172,6 @@ struct ath_txq { struct sk_buff_head complete_q; }; -struct ath_atx_ac { - struct ath_txq *txq; - struct list_head list; - struct list_head tid_q; - bool clear_ps_filter; - bool sched; -}; - struct ath_frame_info { struct ath_buf *bf; u16 framelen; @@ -242,7 +234,7 @@ struct ath_atx_tid { struct sk_buff_head buf_q; struct sk_buff_head retry_q; struct ath_node *an; - struct ath_atx_ac *ac; + struct ath_txq *txq; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; u16 seq_start; u16 seq_next; @@ -254,6 +246,7 @@ struct ath_atx_tid { s8 bar_index; bool sched; bool active; + bool clear_ps_filter; }; struct ath_node { @@ -261,7 +254,6 @@ struct ath_node { struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; - struct ath_atx_ac ac[IEEE80211_NUM_ACS]; u16 maxampdu; u8 mpdudensity; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b766a7fc60aa..f7d6a85433ed 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { - struct ath_atx_ac *ac = tid->ac; struct list_head *list; struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; struct ath_chanctx *ctx = avp->chanctx; @@ -118,15 +117,8 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, return; tid->sched = true; - list_add_tail(&tid->list, &ac->tid_q); - - if (ac->sched) - return; - - ac->sched = true; - list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; - list_add_tail(&ac->list, list); + list_add_tail(&tid->list, list); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -208,7 +200,7 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) static void ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = tid->ac->txq; + struct ath_txq *txq = tid->txq; struct ieee80211_tx_info *tx_info; struct sk_buff *skb, *tskb; struct ath_buf *bf; @@ -237,7 +229,7 @@ ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = tid->ac->txq; + struct ath_txq *txq = tid->txq; struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; @@ -644,7 +636,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_queue_tid(sc, txq, tid); if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) - tid->ac->clear_ps_filter = true; + tid->clear_ps_filter = true; } } @@ -734,7 +726,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; u32 max_4ms_framelen, frmlen; u16 aggr_limit, bt_aggr_limit, legacy = 0; - int q = tid->ac->txq->mac80211_qnum; + int q = tid->txq->mac80211_qnum; int i; skb = bf->bf_mpdu; @@ -1471,8 +1463,8 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, if (list_empty(&bf_q)) return false; - if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) { - tid->ac->clear_ps_filter = false; + if (tid->clear_ps_filter || tid->an->no_ps_filter) { + tid->clear_ps_filter = false; tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; } @@ -1491,7 +1483,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); - txq = txtid->ac->txq; + txq = txtid->txq; ath_txq_lock(sc, txq); @@ -1525,7 +1517,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { 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->ac->txq; + struct ath_txq *txq = txtid->txq; ath_txq_lock(sc, txq); txtid->active = false; @@ -1538,7 +1530,6 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; bool buffered; int tidno; @@ -1546,8 +1537,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -1561,11 +1551,6 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, tid->sched = false; list_del(&tid->list); - if (ac->sched) { - ac->sched = false; - list_del(&ac->list); - } - ath_txq_unlock(sc, txq); ieee80211_sta_set_buffered(sta, tidno, buffered); @@ -1575,18 +1560,16 @@ 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_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; int tidno; for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); - ac->clear_ps_filter = true; + tid->clear_ps_filter = true; if (ath_tid_has_buffered(tid)) { ath_tx_queue_tid(sc, txq, tid); @@ -1606,7 +1589,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; tid = ATH_AN_2_TID(an, tidno); - txq = tid->ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -1645,7 +1628,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, tid = ATH_AN_2_TID(an, i); - ath_txq_lock(sc, tid->ac->txq); + ath_txq_lock(sc, tid->txq); while (nframes > 0) { bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); if (!bf) @@ -1669,7 +1652,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, if (an->sta && !ath_tid_has_buffered(tid)) ieee80211_sta_set_buffered(an->sta, i, false); } - ath_txq_unlock_complete(sc, tid->ac->txq); + ath_txq_unlock_complete(sc, tid->txq); } if (list_empty(&bf_q)) @@ -1918,9 +1901,8 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; - struct list_head *ac_list; + struct list_head *tid_list; bool sent = false; if (txq->mac80211_qnum < 0) @@ -1930,63 +1912,46 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) return; spin_lock_bh(&sc->chan_lock); - ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; + tid_list = &sc->cur_chan->acq[txq->mac80211_qnum]; - if (list_empty(ac_list)) { + if (list_empty(tid_list)) { spin_unlock_bh(&sc->chan_lock); return; } rcu_read_lock(); - last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); - while (!list_empty(ac_list)) { + last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list); + while (!list_empty(tid_list)) { bool stop = false; if (sc->cur_chan->stopped) break; - ac = list_first_entry(ac_list, struct ath_atx_ac, list); - last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); - list_del(&ac->list); - ac->sched = false; - - while (!list_empty(&ac->tid_q)) { - - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, - list); - list_del(&tid->list); - tid->sched = false; - - if (ath_tx_sched_aggr(sc, txq, tid, &stop)) - sent = true; - - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (ath_tid_has_buffered(tid)) - ath_tx_queue_tid(sc, txq, tid); + tid = list_first_entry(tid_list, struct ath_atx_tid, list); + list_del(&tid->list); + tid->sched = false; - if (stop || tid == last_tid) - break; - } + if (ath_tx_sched_aggr(sc, txq, tid, &stop)) + sent = true; - if (!list_empty(&ac->tid_q) && !ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, ac_list); - } + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (ath_tid_has_buffered(tid)) + ath_tx_queue_tid(sc, txq, tid); if (stop) break; - if (ac == last_ac) { + if (tid == last_tid) { if (!sent) break; sent = false; - last_ac = list_entry(ac_list->prev, - struct ath_atx_ac, list); + last_tid = list_entry(tid_list->prev, + struct ath_atx_tid, list); } } @@ -2376,10 +2341,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); } else if (txctl->an && queue) { - WARN_ON(tid->ac->txq != txctl->txq); + WARN_ON(tid->txq != txctl->txq); if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) - tid->ac->clear_ps_filter = true; + tid->clear_ps_filter = true; /* * Add this frame to software queue for scheduling later @@ -2873,7 +2838,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; int tidno, acno; for (tidno = 0, tid = &an->tid[tidno]; @@ -2886,24 +2850,16 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_head = tid->baw_tail = 0; tid->sched = false; tid->active = false; + tid->clear_ps_filter = true; __skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->retry_q); acno = TID_TO_WME_AC(tidno); - tid->ac = &an->ac[acno]; - } - - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - ac->sched = false; - ac->clear_ps_filter = true; - ac->txq = sc->tx.txq_map[acno]; - INIT_LIST_HEAD(&ac->tid_q); + tid->txq = sc->tx.txq_map[acno]; } } void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - struct ath_atx_ac *ac; struct ath_atx_tid *tid; struct ath_txq *txq; int tidno; @@ -2911,8 +2867,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -2921,11 +2876,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) tid->sched = false; } - if (ac->sched) { - list_del(&ac->list); - tid->ac->sched = false; - } - ath_tid_drain(sc, txq, tid); tid->active = false; -- cgit v1.2.3-70-g09d2 From d70d848a75fd65b28835a843bcc4faec2f5803ea Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:14 +0200 Subject: ath9k: remove the sched field in struct ath_atx_tid Use list_empty(&tid->list) instead Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 23 ++++++++--------------- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ac1f10028fe7..c85c47978e1e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -244,7 +244,6 @@ struct ath_atx_tid { int baw_tail; /* next unused tx buffer slot */ s8 bar_index; - bool sched; bool active; bool clear_ps_filter; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f7d6a85433ed..3e3dac3d7060 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -113,12 +113,9 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, if (!ctx) return; - if (tid->sched) - return; - - tid->sched = true; list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; - list_add_tail(&tid->list, list); + if (list_empty(&tid->list)) + list_add_tail(&tid->list, list); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -1541,15 +1538,14 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, ath_txq_lock(sc, txq); - if (!tid->sched) { + if (list_empty(&tid->list)) { ath_txq_unlock(sc, txq); continue; } buffered = ath_tid_has_buffered(tid); - tid->sched = false; - list_del(&tid->list); + list_del_init(&tid->list); ath_txq_unlock(sc, txq); @@ -1929,8 +1925,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) break; tid = list_first_entry(tid_list, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; + list_del_init(&tid->list); if (ath_tx_sched_aggr(sc, txq, tid, &stop)) sent = true; @@ -2848,11 +2843,11 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->seq_start = tid->seq_next = 0; tid->baw_size = WME_MAX_BA; tid->baw_head = tid->baw_tail = 0; - tid->sched = false; tid->active = false; tid->clear_ps_filter = true; __skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->retry_q); + INIT_LIST_HEAD(&tid->list); acno = TID_TO_WME_AC(tidno); tid->txq = sc->tx.txq_map[acno]; } @@ -2871,10 +2866,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) ath_txq_lock(sc, txq); - if (tid->sched) { - list_del(&tid->list); - tid->sched = false; - } + if (!list_empty(&tid->list)) + list_del_init(&tid->list); ath_tid_drain(sc, txq, tid); tid->active = false; -- cgit v1.2.3-70-g09d2 From 3afafd6dcc0cb894a2a6cc1a42bb6f84a0519f16 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 22 Jul 2015 04:53:42 -0700 Subject: mwifiex: using right aid value for tdls action frame Variable pos is u8 here, so memcpy is needed to store u16 aid. At the same time, aid should be platform independent, upper layer utility(wpa_supplicant,etc.,) parse it as le16, so keep it le16 here. Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index aa3d3c5ed07b..b3e163de9899 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -164,7 +164,7 @@ static void mwifiex_tdls_add_aid(struct mwifiex_private *priv, pos = (void *)skb_put(skb, 4); *pos++ = WLAN_EID_AID; *pos++ = 2; - *pos++ = le16_to_cpu(assoc_rsp->a_id); + memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id)); return; } -- cgit v1.2.3-70-g09d2 From 398750992ebe8a3f26d9c1c978911b55c2b2ff8b Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 22 Jul 2015 04:53:43 -0700 Subject: mwifiex: fix command timeout for PCIe chipsets When WLAN interface is up and running, driver unload and load was causing command timeout error. We enable Rx data by updating RX ring read pointer in init_fw_port(). It should be done when FW is completely intialialised. Command timeout is fixed in this patch by moving init_fw_port() call to mwifiex_init_fw_complete(). Signed-off-by: Zhaoyang Liu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 5 ----- drivers/net/wireless/mwifiex/util.c | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 8fa363add970..7a970c28c557 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -551,11 +551,6 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) } } - if (adapter->if_ops.init_fw_port) { - if (adapter->if_ops.init_fw_port(adapter)) - return -1; - } - for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index a5f34f2c1086..0cec8a64473e 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -126,6 +126,10 @@ static int num_of_items = ARRAY_SIZE(items); int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) + if (adapter->if_ops.init_fw_port) + adapter->if_ops.init_fw_port(adapter); + adapter->init_wait_q_woken = true; wake_up_interruptible(&adapter->init_wait_q); return 0; -- cgit v1.2.3-70-g09d2 From d788ac29793ae591801103b714c20ca3ae311c21 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 22 Jul 2015 04:53:44 -0700 Subject: mwifiex: fix system crash observed during initialisation System crash was observed if one of the driver initialisation commands is timed out. The reason is our timeout handler triggers firmware dump, meanwhile driver initialisation error paths have already freed the adapter structure. Firmware hasn't yet completely initialized. So collecting firmware dump is not needed in this case. Command timeout handler is modified in this patch to fix the crash issue. Signed-off-by: Zhaoyang Liu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 27b778d5164e..45ae38e32621 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -979,8 +979,10 @@ mwifiex_cmd_timeout_func(unsigned long function_context) mwifiex_cancel_pending_ioctl(adapter); } } - if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { mwifiex_init_fw_complete(adapter); + return; + } if (adapter->if_ops.device_dump) adapter->if_ops.device_dump(adapter); -- cgit v1.2.3-70-g09d2 From 2728cecdc7d6bf3d216fc406718d88c35f4d09eb Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 22 Jul 2015 04:53:45 -0700 Subject: mwifiex: corrections in PCIe event skb handling Preallocated event SKBs are getting reused for PCIe chipset. Their physical addresses are shared with firmware so that firmware can write data into them. This patch makes sure that SKB is cleared and length is set to default while submitting it to firmware. Signed-off-by: Amitkumar Karwar Signed-off-by: Zhaoyang Liu Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/pcie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 77b9055a2d14..33c75d741017 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1807,6 +1807,8 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if (!card->evt_buf_list[rdptr]) { skb_push(skb, INTF_HEADER_LEN); + skb_put(skb, MAX_EVENT_SIZE - skb->len); + memset(skb->data, 0, MAX_EVENT_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE)) -- cgit v1.2.3-70-g09d2 From d1c5409612ad25d8a35a49a89ad302fc797eeb8e Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Mon, 27 Jul 2015 09:46:02 +0300 Subject: wl18xx: add dynamic fw traces add option to dynamically configure the fw which debug traces to open Signed-off-by: Guy Mishol Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/acx.c | 27 +++++++++++++++++ drivers/net/wireless/ti/wl18xx/acx.h | 13 ++++++++- drivers/net/wireless/ti/wl18xx/debugfs.c | 50 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/main.c | 5 ++++ drivers/net/wireless/ti/wlcore/wlcore.h | 3 ++ 5 files changed, 97 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index 67f2a0eec854..4be0409308cb 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -282,3 +282,30 @@ out: kfree(acx); return ret; } + +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl) +{ + struct acx_dynamic_fw_traces_cfg *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d", + wl->dynamic_fw_traces); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces); + + ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx config dynamic fw traces failed: %d", ret); + goto out; + } +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 4afccd4b9467..c8a33f43916e 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -35,7 +35,8 @@ enum { ACX_PEER_CAP = 0x0056, ACX_INTERRUPT_NOTIFY = 0x0057, ACX_RX_BA_FILTER = 0x0058, - ACX_AP_SLEEP_CFG = 0x0059 + ACX_AP_SLEEP_CFG = 0x0059, + ACX_DYNAMIC_TRACES_CFG = 0x005A, }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -367,6 +368,15 @@ struct acx_ap_sleep_cfg { u8 idle_conn_thresh; } __packed; +/* + * ACX_DYNAMIC_TRACES_CFG + * configure the FW dynamic traces + */ +struct acx_dynamic_fw_traces_cfg { + struct acx_header header; + __le32 dynamic_fw_traces; +} __packed; + int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); @@ -380,5 +390,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action); int wl18xx_acx_ap_sleep(struct wl1271 *wl); +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl); #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 5fbd2230f372..8c6a1c86f526 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -281,6 +281,55 @@ static const struct file_operations radar_detection_ops = { .llseek = default_llseek, }; +static ssize_t dynamic_fw_traces_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) + return ret; + + mutex_lock(&wl->mutex); + + wl->dynamic_fw_traces = value; + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl18xx_acx_dynamic_fw_traces(wl); + if (ret < 0) + count = ret; + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static ssize_t dynamic_fw_traces_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + return wl1271_format_buffer(userbuf, count, ppos, + "%d\n", wl->dynamic_fw_traces); +} + +static const struct file_operations dynamic_fw_traces_ops = { + .read = dynamic_fw_traces_read, + .write = dynamic_fw_traces_write, + .open = simple_open, + .llseek = default_llseek, +}; + int wl18xx_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -433,6 +482,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(conf, moddir); DEBUGFS_ADD(radar_detection, moddir); + DEBUGFS_ADD(dynamic_fw_traces, moddir); return 0; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 49aca2cf7605..8ce9825ee577 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1159,6 +1159,11 @@ static int wl18xx_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* set the dynamic fw traces bitmap */ + ret = wl18xx_acx_dynamic_fw_traces(wl); + if (ret < 0) + return ret; + if (checksum_param) { ret = wl18xx_acx_set_checksum_state(wl); if (ret != 0) diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 7f363fa566a3..a1b6040e6491 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -500,6 +500,9 @@ struct wl1271 { /* interface combinations supported by the hw */ const struct ieee80211_iface_combination *iface_combinations; u8 n_iface_combinations; + + /* dynamic fw traces */ + u32 dynamic_fw_traces; }; int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); -- cgit v1.2.3-70-g09d2 From 6c6317321107bee5aad2d85d848b0597428343d8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 27 Jul 2015 05:02:27 -0700 Subject: mwifiex: add missing skb_push() in mwifiex_check_uap_capabilties For PCIe/USB chipsets, preallocated skb buffers are reused for event handling. mwifiex_check_uap_capabilties() performs skb_pull(). This patch adds missing skb_push() to restore skb's data pointer/length. This bug was introduced by commit debfc6008169 ("mwifiex: update AP WMM settings from BSS_START event") Signed-off-by: Amitkumar Karwar Signed-off-by: Nishant Sarmukadam Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/uap_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 492a8b3c636e..46c972a650a4 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -41,6 +41,8 @@ static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv, mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:", event->data, event->len); + skb_push(event, MWIFIEX_BSS_START_EVT_FIX_SIZE); + while ((evt_len >= sizeof(tlv_hdr->header))) { tlv_hdr = (struct mwifiex_ie_types_data *)curr; tlv_len = le16_to_cpu(tlv_hdr->header.len); -- cgit v1.2.3-70-g09d2 From 5d7e73ba2fd54b17aa8a9f0bcc228a4200d094ad Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Mon, 27 Jul 2015 17:25:49 +0300 Subject: wlcore: add antenna diversity reading comments add comments to the antenna diversity reading Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/rx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 7df672a84530..5b2927391d1c 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,6 +74,12 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; + /* + * Read the signal level and antenna diversity indication. + * The msb in the signal level is always set as it is a + * negative number. + * The antenna indication is the msb of the rssi. + */ status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); -- cgit v1.2.3-70-g09d2 From 12e035968191c05a574c9c20367cb3090bc7d99d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 Aug 2015 12:44:30 +0200 Subject: ath9k: fix build with CONFIG_ATH9K_STATION_STATISTICS=y kbuild bot reported that commit 592fa228f213 ("ath9k: remove struct ath_atx_ac") broke the build when CONFIG_ATH9K_STATION_STATISTICS is y. Reported-by: kbuild test robot Fixes: 592fa228f213 ("ath9k: remove struct ath_atx_ac") Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug_sta.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index ffca918ff16a..c2ca57a2ed09 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -26,12 +26,11 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, struct ath_node *an = file->private_data; struct ath_softc *sc = an->sc; struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; u32 len = 0, size = 4096; char *buf; size_t retval; - int tidno, acno; + int tidno; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -48,19 +47,6 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n", an->mpdudensity); - len += scnprintf(buf + len, size - len, - "%2s%7s\n", "AC", "SCHED"); - - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - txq = ac->txq; - ath_txq_lock(sc, txq); - len += scnprintf(buf + len, size - len, - "%2d%7d\n", - acno, ac->sched); - ath_txq_unlock(sc, txq); - } - len += scnprintf(buf + len, size - len, "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", @@ -68,7 +54,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - txq = tid->ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); if (tid->active) { len += scnprintf(buf + len, size - len, @@ -80,7 +66,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, tid->baw_head, tid->baw_tail, tid->bar_index, - tid->sched); + !list_empty(&tid->list)); } ath_txq_unlock(sc, txq); } -- cgit v1.2.3-70-g09d2 From 60acc4ebe710a8e5c56a8488e91c8b1903289ca8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 27 May 2015 15:05:42 +0300 Subject: treewide: Fix typo compatability -> compatibility Even though 'compatability' has a dedicated entry in the Wiktionary, it's listed as 'Mispelling of compatibility'. Fix it. Signed-off-by: Laurent Pinchart Acked-by: David S. Miller Acked-by: Daniel Vetter for the atomic_helper.c Signed-off-by: Jiri Kosina --- arch/metag/include/asm/elf.h | 2 +- arch/powerpc/kvm/book3s.c | 2 +- arch/sparc/include/uapi/asm/pstate.h | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 4 ++-- drivers/media/dvb-frontends/au8522_dig.c | 2 +- drivers/net/wireless/ipw2x00/ipw2100.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/arch/metag/include/asm/elf.h b/arch/metag/include/asm/elf.h index d2baf6961794..87b0cf1e0acb 100644 --- a/arch/metag/include/asm/elf.h +++ b/arch/metag/include/asm/elf.h @@ -11,7 +11,7 @@ #define R_METAG_RELBRANCH 4 #define R_METAG_GETSETOFF 5 -/* Backward compatability */ +/* Backward compatibility */ #define R_METAG_REG32OP1 6 #define R_METAG_REG32OP2 7 #define R_METAG_REG32OP3 8 diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 05ea8fc7f829..6d6398f4d632 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -902,7 +902,7 @@ int kvmppc_core_check_processor_compat(void) { /* * We always return 0 for book3s. We check - * for compatability while loading the HV + * for compatibility while loading the HV * or PR module */ return 0; diff --git a/arch/sparc/include/uapi/asm/pstate.h b/arch/sparc/include/uapi/asm/pstate.h index 4b6b998afd99..cf832e14aa05 100644 --- a/arch/sparc/include/uapi/asm/pstate.h +++ b/arch/sparc/include/uapi/asm/pstate.h @@ -88,7 +88,7 @@ #define VERS_MAXTL _AC(0x000000000000ff00,UL) /* Max Trap Level. */ #define VERS_MAXWIN _AC(0x000000000000001f,UL) /* Max RegWindow Idx.*/ -/* Compatability Feature Register (%asr26), SPARC-T4 and later */ +/* Compatibility Feature Register (%asr26), SPARC-T4 and later */ #define CFR_AES _AC(0x0000000000000001,UL) /* Supports AES opcodes */ #define CFR_DES _AC(0x0000000000000002,UL) /* Supports DES opcodes */ #define CFR_KASUMI _AC(0x0000000000000004,UL) /* Supports KASUMI opcodes */ diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aac212297b49..a420c6602df8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -744,7 +744,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. * - * For compatability with legacy crtc helpers this should be called before + * For compatibility with legacy crtc helpers this should be called before * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -769,7 +769,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); * This function enables all the outputs with the new configuration which had to * be turned off for the update. * - * For compatability with legacy crtc helpers this should be called after + * For compatibility with legacy crtc helpers this should be called after * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index b744a3f8d467..f956f13fb3dc 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -922,7 +922,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable verbose debug messages"); module_param(zv_mode, int, 0644); -MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatability mode (default:on).\n" +MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatibility mode (default:on).\n" "\t\ton - modified AU8522 QAM256 initialization.\n" "\t\tProvides faster lock when using ZeeVee modulator based sources"); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index c6d78790cb0d..193947865efd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -746,7 +746,7 @@ struct ipw2100_priv { #define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030 #define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188 #define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C -#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 +#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 #define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC -- cgit v1.2.3-70-g09d2 From e1c05067c323fb92d27418fb3586171bd7ce2e12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 7 Jul 2015 10:14:59 +0900 Subject: treewide: fix typos in comment blocks Looks like the word "contiguous" is often mistyped. Signed-off-by: Masahiro Yamada Signed-off-by: Jiri Kosina --- arch/mips/kernel/setup.c | 2 +- drivers/gpio/gpiolib-acpi.c | 2 +- drivers/gpu/drm/via/via_dmablit.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- drivers/media/platform/exynos4-is/fimc-m2m.c | 2 +- drivers/media/v4l2-core/videobuf2-memops.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 2 +- drivers/net/wireless/ath/ath6kl/wmi.c | 4 ++-- drivers/usb/gadget/udc/bdc/bdc.h | 2 +- fs/ocfs2/ocfs2_fs.h | 4 ++-- include/media/videobuf-core.h | 2 +- mm/nommu.c | 10 +++++----- 12 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 008b3378653a..35b8316002f8 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -476,7 +476,7 @@ static void __init bootmem_init(void) * o bootmem_init() * o sparse_init() * o paging_init() - * o dma_continguous_reserve() + * o dma_contiguous_reserve() * * At this stage the bootmem allocator is ready to use. * diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 533fe5dbe6f8..143a9bdbaa53 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -68,7 +68,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) * GPIO controller driver. * * Typically the returned offset is same as @pin, but if the GPIO - * controller uses pin controller and the mapping is not contigous the + * controller uses pin controller and the mapping is not contiguous the * offset might be different. */ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index ba33cf679180..d0cbd5ecd7f0 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -260,7 +260,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) /* * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be - * quite large for some blits, and pages don't need to be contingous. + * quite large for some blits, and pages don't need to be contiguous. */ static int diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d26a6daa9719..0336d49e3d4c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -227,7 +227,7 @@ enum vmw_dma_map_mode { * device-specific information. * * @sgt: Pointer to a struct sg_table with binding information - * @num_regions: Number of regions with device-address contigous pages + * @num_regions: Number of regions with device-address contiguous pages */ struct vmw_sg_table { enum vmw_dma_map_mode mode; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 0ad1b6f84a27..d2bfe7c2a6b4 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -188,7 +188,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, if (IS_ERR(f)) return PTR_ERR(f); /* - * Return number of non-contigous planes (plane buffers) + * Return number of non-contiguous planes (plane buffers) * depending on the configured color format. */ if (!f->fmt) diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 81c1ad8b2cf1..0d49b7951f84 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c @@ -125,7 +125,7 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, } /* - * Memory is contigous, lock vma and return to the caller + * Memory is contiguous, lock vma and return to the caller */ *res_vma = vb2_get_vma(vma); if (*res_vma == NULL) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 717ce21b6077..8c9d01ef730d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -140,7 +140,7 @@ #define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) -/* Descriptors required for maximum contigous TSO/GSO packet */ +/* Descriptors required for maximum contiguous TSO/GSO packet */ #define XGBE_TX_MAX_SPLIT ((GSO_MAX_SIZE / XGBE_TX_MAX_BUF_SIZE) + 1) /* Maximum possible descriptors needed for an SKB: diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b921005ad7ee..a5e1de75a4a3 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -154,7 +154,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx) } /* Performs DIX to 802.3 encapsulation for transmit packets. - * Assumes the entire DIX header is contigous and that there is + * Assumes the entire DIX header is contiguous and that there is * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers. */ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) @@ -449,7 +449,7 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) /* * Performs 802.3 to DIX encapsulation for received packets. - * Assumes the entire 802.3 header is contigous. + * Assumes the entire 802.3 header is contiguous. */ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) { diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index dc18a20bf040..916d47135cac 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -290,7 +290,7 @@ struct bdc_sr { __le32 offset[4]; }; -/* bd_table: contigous bd's in a table */ +/* bd_table: contiguous bd's in a table */ struct bd_table { struct bdc_bd *start_bd; /* dma address of start bd of table*/ diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index db64ce2d4667..540ab5b75dbb 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -168,7 +168,7 @@ /* Refcount tree support */ #define OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE 0x1000 -/* Discontigous block groups */ +/* Discontiguous block groups */ #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG 0x2000 /* @@ -939,7 +939,7 @@ struct ocfs2_group_desc /* * Block groups may be discontiguous when * OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG is set. - * The extents of a discontigous block group are + * The extents of a discontiguous block group are * stored in bg_list. It is a flat list. * l_tree_depth must always be zero. A * discontiguous group is signified by a non-zero diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 8c6e825940e5..d760aa73ebbb 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -37,7 +37,7 @@ struct videobuf_queue; * * about the mmap helpers (videobuf_mmap_*): * - * The mmaper function allows to map any subset of contingous buffers. + * The mmaper function allows to map any subset of contiguous buffers. * This includes one mmap() call for all buffers (which the original * video4linux API uses) as well as one mmap() for every single buffer * (which v4l2 uses). diff --git a/mm/nommu.c b/mm/nommu.c index 58ea3643b9e9..0b34f4033cb6 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -324,12 +324,12 @@ long vwrite(char *buf, char *addr, unsigned long count) } /* - * vmalloc - allocate virtually continguos memory + * vmalloc - allocate virtually contiguous memory * * @size: allocation size * * Allocate enough pages to cover @size from the page level - * allocator and map them into continguos kernel virtual space. + * allocator and map them into contiguous kernel virtual space. * * For tight control over page level allocator and protection flags * use __vmalloc() instead. @@ -341,12 +341,12 @@ void *vmalloc(unsigned long size) EXPORT_SYMBOL(vmalloc); /* - * vzalloc - allocate virtually continguos memory with zero fill + * vzalloc - allocate virtually contiguous memory with zero fill * * @size: allocation size * * Allocate enough pages to cover @size from the page level - * allocator and map them into continguos kernel virtual space. + * allocator and map them into contiguous kernel virtual space. * The memory allocated is set to zero. * * For tight control over page level allocator and protection flags @@ -420,7 +420,7 @@ void *vmalloc_exec(unsigned long size) * @size: allocation size * * Allocate enough 32bit PA addressable pages to cover @size from the - * page level allocator and map them into continguos kernel virtual space. + * page level allocator and map them into contiguous kernel virtual space. */ void *vmalloc_32(unsigned long size) { -- cgit v1.2.3-70-g09d2 From 100a008331072e678ffcf2d903e48c633c2795fe Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 28 Jul 2015 07:22:20 -0700 Subject: mwifiex: correct TDLS link delete failure message priority Commit d8d2f19feb16 ("mwifiex: silence TDLS link delete failure for nonexistent link") lowers the priority of error message when TDLS link is already deleted. But it had got increased by commit acebe8c10a6e ("mwifiex: change dbg print func to mwifiex_dbg") Reported-by: Nicholas Mc Guire Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 89e8dafb4738..87b69d8ad120 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -895,7 +895,7 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv, case ACT_TDLS_DELETE: if (reason) { if (!node || reason == TDLS_ERR_LINK_NONEXISTENT) - mwifiex_dbg(priv->adapter, ERROR, + mwifiex_dbg(priv->adapter, MSG, "TDLS link delete for %pM failed: reason %d\n", cmd_tdls_oper->peer_mac, reason); else -- cgit v1.2.3-70-g09d2 From 6d5c898798aca634f493cabd2e7a47407ee5e95d Mon Sep 17 00:00:00 2001 From: "Machani, Yaniv" Date: Thu, 30 Jul 2015 22:38:19 +0300 Subject: wlcore/wl18xx : add time sync event handling Added support for a new time sync event the event data contains the WiLink TSF value. To trigger the event, a HW modification is required, so as a supporting firmware binary. Signed-off-by: Yaniv Machani Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/event.c | 13 +++++++++++++ drivers/net/wireless/ti/wl18xx/event.h | 12 ++++++++---- drivers/net/wireless/ti/wl18xx/main.c | 4 ++-- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index 548bb9e7e91e..09c7e098f460 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -112,6 +112,14 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl, return 0; } +static void wlcore_event_time_sync(struct wl1271 *wl, u16 tsf_msb, u16 tsf_lsb) +{ + u32 clock; + /* convert the MSB+LSB to a u32 TSF value */ + clock = (tsf_msb << 16) | tsf_lsb; + wl1271_info("TIME_SYNC_EVENT_ID: clock %u", clock); +} + int wl18xx_process_mailbox_events(struct wl1271 *wl) { struct wl18xx_event_mailbox *mbox = wl->mbox; @@ -128,6 +136,11 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) wl18xx_scan_completed(wl, wl->scan_wlvif); } + if (vector & TIME_SYNC_EVENT_ID) + wlcore_event_time_sync(wl, + mbox->time_sync_tsf_msb, + mbox->time_sync_tsf_lsb); + if (vector & RADAR_DETECTED_EVENT_ID) { wl1271_info("radar event: channel %d type %s", mbox->radar_channel, diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 266ee87834e4..f3d4f13379cb 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -38,8 +38,9 @@ enum { REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), - SMART_CONFIG_SYNC_EVENT_ID = BIT(22), - SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + SMART_CONFIG_SYNC_EVENT_ID = BIT(22), + SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + TIME_SYNC_EVENT_ID = BIT(24), }; enum wl18xx_radar_types { @@ -95,13 +96,16 @@ struct wl18xx_event_mailbox { /* smart config sync channel */ u8 sc_sync_channel; u8 sc_sync_band; - u8 padding2[2]; + /* time sync msb*/ + u16 time_sync_tsf_msb; /* radar detect */ u8 radar_channel; u8 radar_type; - u8 padding3[2]; + /* time sync lsb*/ + u16 time_sync_tsf_lsb; + } __packed; int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 8ce9825ee577..3da6ac60c65d 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1026,8 +1026,8 @@ static int wl18xx_boot(struct wl1271 *wl) CHANNEL_SWITCH_COMPLETE_EVENT_ID | DFS_CHANNELS_CONFIG_COMPLETE_EVENT | SMART_CONFIG_SYNC_EVENT_ID | - SMART_CONFIG_DECODE_EVENT_ID; -; + SMART_CONFIG_DECODE_EVENT_ID | + TIME_SYNC_EVENT_ID; wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; -- cgit v1.2.3-70-g09d2 From 8698a3a4fff2b63831fdc0283da87f9f46c2aeb8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:20 +0300 Subject: wl18xx: use long intervals in sched scan Add support for long intervals on sched scan. If configured, the original request interval will be used num_short_interval times, and then the long interval will be used. While on it, fix the scan command field names to reflect the expected value is in ms (rather than secs). These values will be taken from the conf file, so bump its version accordingly. Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/main.c | 2 ++ drivers/net/wireless/ti/wl18xx/scan.c | 17 ++++++++++++++--- drivers/net/wireless/ti/wl18xx/scan.h | 4 ++-- drivers/net/wireless/ti/wlcore/conf.h | 11 ++++++++++- drivers/net/wireless/ti/wlcore/scan.h | 6 ++++++ 5 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 3da6ac60c65d..f9c9d5cf0854 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -422,6 +422,8 @@ static struct wlcore_conf wl18xx_conf = { .num_probe_reqs = 2, .rssi_threshold = -90, .snr_threshold = 0, + .num_short_intervals = SCAN_MAX_SHORT_INTERVALS, + .long_interval = 30000, }, .ht = { .rx_ba_win_size = 32, diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 98666f235a12..ec2eb147add3 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -223,9 +223,20 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, SCAN_TYPE_PERIODIC); wl18xx_adjust_channels(cmd, cmd_channels); - cmd->short_cycles_sec = 0; - cmd->long_cycles_sec = cpu_to_le16(req->interval); - cmd->short_cycles_count = 0; + if (c->num_short_intervals && c->long_interval && + c->long_interval > req->interval) { + cmd->short_cycles_msec = cpu_to_le16(req->interval); + cmd->long_cycles_msec = cpu_to_le16(c->long_interval); + cmd->short_cycles_count = c->num_short_intervals; + } else { + cmd->short_cycles_msec = 0; + cmd->long_cycles_msec = cpu_to_le16(req->interval); + cmd->short_cycles_count = 0; + } + wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", + le16_to_cpu(cmd->short_cycles_msec), + le16_to_cpu(cmd->long_cycles_msec), + cmd->short_cycles_count); cmd->total_cycles = 0; diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h index 2e636aa5dba9..66a763f644d2 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.h +++ b/drivers/net/wireless/ti/wl18xx/scan.h @@ -74,8 +74,8 @@ struct wl18xx_cmd_scan_params { u8 dfs; /* number of dfs channels in 5ghz */ u8 passive_active; /* number of passive before active channels 2.4ghz */ - __le16 short_cycles_sec; - __le16 long_cycles_sec; + __le16 short_cycles_msec; + __le16 long_cycles_msec; u8 short_cycles_count; u8 total_cycles; /* 0 - infinite */ u8 padding[2]; diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 166add00b50f..52a9d1b14020 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -1186,6 +1186,15 @@ struct conf_sched_scan_settings { /* SNR threshold to be used for filtering */ s8 snr_threshold; + + /* + * number of short intervals scheduled scan cycles before + * switching to long intervals + */ + u8 num_short_intervals; + + /* interval between each long scheduled scan cycle (in ms) */ + u16 long_interval; } __packed; struct conf_ht_setting { @@ -1352,7 +1361,7 @@ struct conf_recovery_settings { * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0006 << 16) +#define WLCORE_CONF_VERSION (0x0007 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index 4dadd0c62cde..782eb297c196 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h @@ -83,6 +83,12 @@ struct wl1271_cmd_trigger_scan_to { #define MAX_CHANNELS_5GHZ 42 #define SCAN_MAX_CYCLE_INTERVALS 16 + +/* The FW intervals can take up to 16 entries. + * The 1st entry isn't used (scan is immediate). The last + * entry should be used for the long_interval + */ +#define SCAN_MAX_SHORT_INTERVALS (SCAN_MAX_CYCLE_INTERVALS - 2) #define SCAN_MAX_BANDS 3 enum { -- cgit v1.2.3-70-g09d2 From c32e35f29ce96da371e798a8a04ed299f4ecfc44 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:21 +0300 Subject: wlcore: add generic_cfg_feature command definitions Add definitions and function prototypes for generic_cfg command. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/cmd.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/cmd.h | 15 +++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 68919f8d4310..dbc55a0aa905 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -2059,3 +2059,33 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) out: return ret; } + +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 feature, u8 enable, u8 value) +{ + struct wlcore_cmd_generic_cfg *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, + "cmd generic cfg (role %d feature %d enable %d value %d)", + wlvif->role_id, feature, enable, value); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->feature = feature; + cmd->enable = enable; + cmd->value = value; + + ret = wl1271_cmd_send(wl, CMD_GENERIC_CFG, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send generic cfg command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} +EXPORT_SYMBOL_GPL(wlcore_cmd_generic_cfg); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index e14cd407a6ae..8dc46c0a489a 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -92,6 +92,8 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, enum ieee80211_band band); int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 feature, u8 enable, u8 value); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); @@ -652,6 +654,19 @@ struct wl12xx_cmd_regdomain_dfs_config { u8 padding[3]; } __packed; +enum wlcore_generic_cfg_feature { + WLCORE_CFG_FEATURE_RADAR_DEBUG = 2, +}; + +struct wlcore_cmd_generic_cfg { + struct wl1271_cmd_header header; + + u8 role_id; + u8 feature; + u8 enable; + u8 value; +} __packed; + struct wl12xx_cmd_config_fwlog { struct wl1271_cmd_header header; -- cgit v1.2.3-70-g09d2 From 7845af35e0deeb7537de759ebc69d6395d4123bf Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:22 +0300 Subject: wlcore: add p2p device support When starting a p2p mgmt interface, enable its device role. This allows us to keep the sta role disabled and scan on the dev role. In general, p2p management interfaces cannot send vif-specific commands to FW, as the vif role id is invalid. Only off-channel data and scans happen on this vif, so most ops are not relevant. If the vif is a p2p mgmt vif, block some mac80211 ops. Configure rate policies for p2p mgmt interface, as otherwise p2p packets come out with arbitrary rates. Since wpa_supplicant currently doesn't support standalone p2p device mode (without another attached managed interface), add p2p device to the allowed interface combinations without decreasing the allowed station count. Moreover, increase the station count in some cases, as AP mode usually starts as station interface, and the AP interface is now different from the p2p management one). Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl12xx/scan.c | 6 ++- drivers/net/wireless/ti/wl18xx/main.c | 48 ++++++++++++++++++++- drivers/net/wireless/ti/wl18xx/scan.c | 6 ++- drivers/net/wireless/ti/wlcore/cmd.c | 26 +++++++----- drivers/net/wireless/ti/wlcore/init.c | 2 +- drivers/net/wireless/ti/wlcore/init.h | 1 + drivers/net/wireless/ti/wlcore/main.c | 69 +++++++++++++++++++++++++------ drivers/net/wireless/ti/wlcore/wlcore_i.h | 5 +++ 8 files changed, 136 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 0c0d5cd98514..7c355fff2c5e 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -118,7 +118,11 @@ static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; - cmd->params.role_id = wlvif->role_id; + /* scan on the dev role if the regular one is not started */ + if (wlcore_is_p2p_mgmt(wlvif)) + cmd->params.role_id = wlvif->dev_role_id; + else + cmd->params.role_id = wlvif->role_id; if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index f9c9d5cf0854..abbf054fb6da 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1804,7 +1804,7 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { static const struct ieee80211_iface_limit wl18xx_iface_limits[] = { { - .max = 3, + .max = 2, .types = BIT(NL80211_IFTYPE_STATION), }, { @@ -1813,6 +1813,10 @@ static const struct ieee80211_iface_limit wl18xx_iface_limits[] = { BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { @@ -1820,6 +1824,48 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { .max = 2, .types = BIT(NL80211_IFTYPE_AP), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_cl_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_go_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_combination diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index ec2eb147add3..c938c494c785 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -51,7 +51,11 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, goto out; } - cmd->role_id = wlvif->role_id; + /* scan on the dev role if the regular one is not started */ + if (wlcore_is_p2p_mgmt(wlvif)) + cmd->role_id = wlvif->dev_role_id; + else + cmd->role_id = wlvif->role_id; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index dbc55a0aa905..f01d24baff7c 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -2003,12 +2003,15 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, wlvif->bss_type == BSS_TYPE_IBSS))) return -EINVAL; - ret = wl12xx_cmd_role_enable(wl, - wl12xx_wlvif_to_vif(wlvif)->addr, - WL1271_ROLE_DEVICE, - &wlvif->dev_role_id); - if (ret < 0) - goto out; + /* the dev role is already started for p2p mgmt interfaces */ + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_enable(wl, + wl12xx_wlvif_to_vif(wlvif)->addr, + WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + } ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel); if (ret < 0) @@ -2023,7 +2026,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, out_stop: wl12xx_cmd_role_stop_dev(wl, wlvif); out_disable: - wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (!wlcore_is_p2p_mgmt(wlvif)) + wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); out: return ret; } @@ -2052,9 +2056,11 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (ret < 0) goto out; - ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); - if (ret < 0) - goto out; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto out; + } out: return ret; diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 5ca1fb161a50..e92f2639af2c 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -348,7 +348,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl) } /* generic sta initialization (non vif-specific) */ -static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; diff --git a/drivers/net/wireless/ti/wlcore/init.h b/drivers/net/wireless/ti/wlcore/init.h index a45fbfddec19..fd1cdb6bc3e4 100644 --- a/drivers/net/wireless/ti/wlcore/init.h +++ b/drivers/net/wireless/ti/wlcore/init.h @@ -35,5 +35,6 @@ int wl1271_hw_init(struct wl1271 *wl); int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif); int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 337223b9f6f8..e819369d8f8f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1792,6 +1792,9 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + ret = wl1271_configure_suspend(wl, wlvif, wow); if (ret < 0) { mutex_unlock(&wl->mutex); @@ -1901,6 +1904,9 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) goto out; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + wl1271_configure_resume(wl, wlvif); } @@ -2256,6 +2262,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wlvif->p2p = 1; /* fall-through */ case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_DEVICE: wlvif->bss_type = BSS_TYPE_STA_BSS; break; case NL80211_IFTYPE_ADHOC: @@ -2477,7 +2484,8 @@ static void wlcore_hw_queue_iter(void *data, u8 *mac, { struct wlcore_hw_queue_iter_data *iter_data = data; - if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) + if (vif->type == NL80211_IFTYPE_P2P_DEVICE || + WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) return; if (iter_data->cur_running || vif == iter_data->vif) { @@ -2495,6 +2503,11 @@ static int wlcore_allocate_hw_queue_base(struct wl1271 *wl, struct wlcore_hw_queue_iter_data iter_data = {}; int i, q_base; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + return 0; + } + iter_data.vif = vif; /* mark all bits taken by active interfaces */ @@ -2618,14 +2631,27 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - ret = wl12xx_cmd_role_enable(wl, vif->addr, - role_type, &wlvif->role_id); - if (ret < 0) - goto out; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_enable(wl, vif->addr, + role_type, &wlvif->role_id); + if (ret < 0) + goto out; - ret = wl1271_init_vif_specific(wl, vif); - if (ret < 0) - goto out; + ret = wl1271_init_vif_specific(wl, vif); + if (ret < 0) + goto out; + + } else { + ret = wl12xx_cmd_role_enable(wl, vif->addr, WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + + /* needed mainly for configuring rate policies */ + ret = wl1271_sta_hw_init(wl, wlvif); + if (ret < 0) + goto out; + } list_add(&wlvif->list, &wl->wlvif_list); set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); @@ -2696,9 +2722,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl12xx_stop_dev(wl, wlvif); } - ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); - if (ret < 0) - goto deinit; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); + if (ret < 0) + goto deinit; + } else { + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto deinit; + } wl1271_ps_elp_sleep(wl); } @@ -3088,6 +3120,9 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, { int ret; + if (wlcore_is_p2p_mgmt(wlvif)) + return 0; + if (conf->power_level != wlvif->power_level) { ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); if (ret < 0) @@ -3207,6 +3242,9 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, goto out; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + if (wlvif->bss_type != BSS_TYPE_AP_BSS) { if (*total & FIF_ALLMULTI) ret = wl1271_acx_group_address_tbl(wl, wlvif, @@ -4837,6 +4875,9 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u8 ps_scheme; int ret = 0; + if (wlcore_is_p2p_mgmt(wlvif)) + return 0; + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); @@ -6078,8 +6119,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_sched_scan_ssids = 16; wl->hw->wiphy->max_match_sets = 16; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 39efc6d78b10..27c56876b2c1 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -503,6 +503,11 @@ struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); } +static inline bool wlcore_is_p2p_mgmt(struct wl12xx_vif *wlvif) +{ + return wl12xx_wlvif_to_vif(wlvif)->type == NL80211_IFTYPE_P2P_DEVICE; +} + #define wl12xx_for_each_wlvif(wl, wlvif) \ list_for_each_entry(wlvif, &wl->wlvif_list, list) -- cgit v1.2.3-70-g09d2 From bed429e1ae8b7ee207e01f3aa60dcc0d06a8ed4d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:46 +0200 Subject: mt7601u: fix dma from stack address DMA to variables located on the stack is a bad idea. For simplicity and to avoid frequent allocations create a buffer inside the device structure. Protect this buffer with vendor_req_mutex. Don't protect vendor requests which don't use this buffer. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +- drivers/net/wireless/mediatek/mt7601u/usb.c | 63 ++++++++++++------------- drivers/net/wireless/mediatek/mt7601u/usb.h | 2 + 3 files changed, 34 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 9102be6b95cb..6bdfc1103fcc 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -146,7 +146,7 @@ enum { * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. - * @vendor_req_mutex: ensures atomicity of vendor requests. + * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). * @hw_atomic_mutex: ensures exclusive access to HW during critical @@ -184,6 +184,8 @@ struct mt7601u_dev { struct mt7601u_eeprom_params *ee; struct mutex vendor_req_mutex; + void *vend_buf; + struct mutex reg_atomic_mutex; struct mutex hw_atomic_mutex; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 54dba4001865..416c6045ff31 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb) complete(cmpl); } -static int -__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen) +int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + const u8 direction, const u16 val, const u16 offset, + void *buf, const size_t buflen) { int i, ret; struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); @@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, trace_mt_vend_req(dev, pipe, req, req_type, val, offset, buf, buflen, ret); + if (ret == -ENODEV) + set_bit(MT7601U_STATE_REMOVED, &dev->state); if (ret >= 0 || ret == -ENODEV) return ret; @@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, return ret; } -int -mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen) -{ - int ret; - - mutex_lock(&dev->vendor_req_mutex); - - ret = __mt7601u_vendor_request(dev, req, direction, val, offset, - buf, buflen); - if (ret == -ENODEV) - set_bit(MT7601U_STATE_REMOVED, &dev->state); - - mutex_unlock(&dev->vendor_req_mutex); - - return ret; -} - void mt7601u_vendor_reset(struct mt7601u_dev *dev) { mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, @@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { int ret; - __le32 reg; - u32 val; + u32 val = ~0; WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); + mutex_lock(&dev->vendor_req_mutex); + ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, - 0, offset, ®, sizeof(reg)); - val = le32_to_cpu(reg); - if (ret > 0 && ret != sizeof(reg)) { + 0, offset, dev->vend_buf, MT_VEND_BUF); + if (ret == MT_VEND_BUF) + val = get_unaligned_le32(dev->vend_buf); + else if (ret > 0) dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", ret, offset); - val = ~0; - } + + mutex_unlock(&dev->vendor_req_mutex); trace_reg_read(dev, offset, val); return val; @@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, { int ret; + mutex_lock(&dev->vendor_req_mutex); + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, val & 0xffff, offset, NULL, 0); - if (ret) - return ret; - return mt7601u_vendor_request(dev, req, USB_DIR_OUT, - val >> 16, offset + 2, NULL, 0); + if (!ret) + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val >> 16, offset + 2, NULL, 0); + + mutex_unlock(&dev->vendor_req_mutex); + + return ret; } void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) @@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); + dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); + if (!dev->vend_buf) { + ret = -ENOMEM; + goto err; + } + ret = mt7601u_assign_pipes(usb_intf, dev); if (ret) goto err; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h index 49e188fa3798..bc182022b9d6 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.h +++ b/drivers/net/wireless/mediatek/mt7601u/usb.h @@ -23,6 +23,8 @@ #define MT_VEND_DEV_MODE_RESET 1 +#define MT_VEND_BUF sizeof(__le32) + enum mt_vendor_req { MT_VEND_DEV_MODE = 1, MT_VEND_WRITE = 2, -- cgit v1.2.3-70-g09d2 From d9517c0a5d7468a7ea63086057604fcb0fff480e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:47 +0200 Subject: mt7601u: use correct ieee80211_rx variant Rx is run inside a tasklet so ieee80211_rx() should be used instead of ieee80211_rx_ni(). Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 7217da4f1543..fb183e369d92 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -112,7 +112,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, if (!skb) return; - ieee80211_rx_ni(dev->hw, skb); + ieee80211_rx(dev->hw, skb); } static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) -- cgit v1.2.3-70-g09d2 From 4513493d188d5e3052aee68eda85eaaa1a4e41c2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:48 +0200 Subject: mt7601u: fix tx status reporting contexts mac80211 requires that rx path does not run concurrently with tx status reporting. Since rx path is run in driver tasklet, tx status cannot be reported directly from interrupt context (there would be no way to lock it out). Add tasklet for tx and move all possible code from irq handler there. Note: tx tasklet is needed because workqueue is queued very rarely and that kills TCP performance. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 30 +++++++++++++++++++++---- drivers/net/wireless/mediatek/mt7601u/init.c | 1 + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++++ drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 2 ++ 4 files changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index fb183e369d92..63c485443a38 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -236,23 +236,42 @@ static void mt7601u_complete_tx(struct urb *urb) skb = q->e[q->start].skb; trace_mt_tx_dma_done(dev, skb); - mt7601u_tx_status(dev, skb); + __skb_queue_tail(&dev->tx_skb_done, skb); + tasklet_schedule(&dev->tx_tasklet); if (q->used == q->entries - q->entries / 8) ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); q->start = (q->start + 1) % q->entries; q->used--; +out: + spin_unlock_irqrestore(&dev->tx_lock, flags); +} - if (urb->status) - goto out; +static void mt7601u_tx_tasklet(unsigned long data) +{ + struct mt7601u_dev *dev = (struct mt7601u_dev *) data; + struct sk_buff_head skbs; + unsigned long flags; + + __skb_queue_head_init(&skbs); + + spin_lock_irqsave(&dev->tx_lock, flags); set_bit(MT7601U_STATE_MORE_STATS, &dev->state); if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) queue_delayed_work(dev->stat_wq, &dev->stat_work, msecs_to_jiffies(10)); -out: + + skb_queue_splice_init(&dev->tx_skb_done, &skbs); + spin_unlock_irqrestore(&dev->tx_lock, flags); + + while (!skb_queue_empty(&skbs)) { + struct sk_buff *skb = __skb_dequeue(&skbs); + + mt7601u_tx_status(dev, skb); + } } static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, @@ -475,6 +494,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev) { int ret = -ENOMEM; + tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); ret = mt7601u_alloc_tx(dev); @@ -502,4 +522,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev) mt7601u_free_rx(dev); mt7601u_free_tx(dev); + + tasklet_kill(&dev->tx_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index df3dd56199a7..38eb20ba6e58 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -456,6 +456,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) spin_lock_init(&dev->lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); + skb_queue_head_init(&dev->tx_skb_done); dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); if (!dev->stat_wq) { diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index 7514bce1ac91..e3928cfa3d63 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) } mt76_mac_fill_tx_status(dev, &info, stat); + + local_bh_disable(); ieee80211_tx_status_noskb(dev->hw, sta, &info); + local_bh_enable(); + rcu_read_unlock(); } diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 6bdfc1103fcc..bc5e294feb8c 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -199,7 +199,9 @@ struct mt7601u_dev { /* TX */ spinlock_t tx_lock; + struct tasklet_struct tx_tasklet; struct mt7601u_tx_queue *tx_q; + struct sk_buff_head tx_skb_done; atomic_t avg_ampdu_len; -- cgit v1.2.3-70-g09d2 From 78623bfb6f4cbdba3183621e8e0e781611217022 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:49 +0200 Subject: mt7601u: lock out rx path and tx status reporting mac80211 requires that rx path does not run concurrently with tx status reporting. Add a spinlock which will ensure that. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 2 ++ drivers/net/wireless/mediatek/mt7601u/init.c | 1 + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +++- drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +++ 5 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 63c485443a38..57a80cfa39b1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, if (!skb) return; + spin_lock(&dev->mac_lock); ieee80211_rx(dev->hw, skb); + spin_unlock(&dev->mac_lock); } static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index 38eb20ba6e58..26190fd33407 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -454,6 +454,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); + spin_lock_init(&dev->mac_lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); skb_queue_head_init(&dev->tx_skb_done); diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index e3928cfa3d63..e21c53ed09fb 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -182,9 +182,9 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) mt76_mac_fill_tx_status(dev, &info, stat); - local_bh_disable(); + spin_lock_bh(&dev->mac_lock); ieee80211_tx_status_noskb(dev->hw, sta, &info); - local_bh_enable(); + spin_unlock_bh(&dev->mac_lock); rcu_read_unlock(); } diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index bc5e294feb8c..428bd2f10b7b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -141,8 +141,9 @@ enum { /** * struct mt7601u_dev - adapter structure * @lock: protects @wcid->tx_rate. + * @mac_lock: locks out mac80211's tx status and rx paths. * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS - flags in @state. + * flags in @state. * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. @@ -177,6 +178,7 @@ struct mt7601u_dev { struct mt76_wcid __rcu *wcid[N_WCIDS]; spinlock_t lock; + spinlock_t mac_lock; const u16 *beacon_offsets; diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index 0be2080ceab3..a0a33dc8f6bc 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) ieee80211_tx_info_clear_status(info); info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; + + spin_lock(&dev->mac_lock); ieee80211_tx_status(dev->hw, skb); + spin_unlock(&dev->mac_lock); } static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 9b412590faaea65dab54f9bc5ae5b48ba0e73c5d Mon Sep 17 00:00:00 2001 From: Bertold Van den Bergh Date: Mon, 3 Aug 2015 15:45:41 +0200 Subject: ath: Make ath_opmode_to_string understand OCB mode Make ath_opmode_to_string return "OCB" for NL80211_IFTYPE_OCB. Currently it will return "UNKNOWN". Signed-off-by: Bertold Van den Bergh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/debug.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 508eccf5d982..d59d83e0ce4b 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -40,6 +40,8 @@ const char *ath_opmode_to_string(enum nl80211_iftype opmode) return "P2P-CLIENT"; case NL80211_IFTYPE_P2P_GO: return "P2P-GO"; + case NL80211_IFTYPE_OCB: + return "OCB"; default: return "UNKNOWN"; } -- cgit v1.2.3-70-g09d2 From 2001a130d4fa8386b9d7978578dc40aa1f0dad6c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2015 10:20:10 +0200 Subject: iwlwifi: mvm: don't set K1/K2 for AES-CMAC According to firmware engineers, the firmware has never required these fields and the values have always been calculated, they were just leftovers from a previous implementation. Therefore remove the unnecessary calculation. Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/sta.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 21dd5b771660..493a8bdfbc9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -366,8 +366,8 @@ struct iwl_mvm_rm_sta_cmd { * ( MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: %iwl_sta_key_flag * @IGTK: - * @K1: IGTK master key - * @K2: IGTK sub key + * @K1: unused + * @K2: unused * @sta_id: station ID that support IGTK * @key_id: * @receive_seq_cnt: initial RSC/PN needed for replay check diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d68dc697a4a0..3d2fbf1bc226 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1277,8 +1277,6 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, const u8 *pn; memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen); - ieee80211_aes_cmac_calculate_k1_k2(keyconf, - igtk_cmd.K1, igtk_cmd.K2); ieee80211_get_key_rx_seq(keyconf, 0, &seq); pn = seq.aes_cmac.pn; igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) | -- cgit v1.2.3-70-g09d2 From 4dca0e6edd14e0c8afa19c8ad90f711f1563b52e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 3 Aug 2015 11:16:42 +0200 Subject: ath10k: remove futile fragmentation threshold config Commit 1010ba4c5d1c ("ath10k: unregister and remove frag_threshold callback") didn't remove all instances of (futile) fragmentation threshold configuration. No known firmware supports the parameter so don't even bother setting it. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index acd222f3b899..879af9c3bd4a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -678,20 +678,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); } -static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value) -{ - struct ath10k *ar = arvif->ar; - u32 vdev_param; - - if (value != 0xFFFFFFFF) - value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold, - ATH10K_FRAGMT_THRESHOLD_MIN, - ATH10K_FRAGMT_THRESHOLD_MAX); - - vdev_param = ar->wmi.vdev_param->fragmentation_threshold; - return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); -} - static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) { int ret; @@ -4276,13 +4262,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_peer_delete; } - ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); - if (ret) { - ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n", - arvif->vdev_id, ret); - goto err_peer_delete; - } - arvif->txpower = vif->bss_conf.txpower; ret = ath10k_mac_txpower_recalc(ar); if (ret) { -- cgit v1.2.3-70-g09d2 From 92092fe528e79c9bd25784ca0ef341d5a1d1b642 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 3 Aug 2015 11:16:43 +0200 Subject: ath10k: reject 11b tx fragmentation configuration Even though there's a WMI enum for fragmentation threshold no known firmware actually implements it. Moreover it is not possible to rely frame fragmentation to mac80211 because firmware clears the "more fragments" bit in frame control making it impossible for remote devices to reassemble frames. Hence implement a dummy callback just to say fragmentation isn't supported. This effectively prevents mac80211 from doing frame fragmentation in software. This fixes Tx becoming broken after setting fragmentation threshold. Fixes: 1010ba4c5d1c ("ath10k: unregister and remove frag_threshold callback") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 879af9c3bd4a..e0bbb6c543c7 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5563,6 +5563,21 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } +static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ + /* Even though there's a WMI enum for fragmentation threshold no known + * firmware actually implements it. Moreover it is not possible to rely + * frame fragmentation to mac80211 because firmware clears the "more + * fragments" bit in frame control making it impossible for remote + * devices to reassemble frames. + * + * Hence implement a dummy callback just to say fragmentation isn't + * supported. This effectively prevents mac80211 from doing frame + * fragmentation in software. + */ + return -EOPNOTSUPP; +} + static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -6405,6 +6420,7 @@ static const struct ieee80211_ops ath10k_ops = { .remain_on_channel = ath10k_remain_on_channel, .cancel_remain_on_channel = ath10k_cancel_remain_on_channel, .set_rts_threshold = ath10k_set_rts_threshold, + .set_frag_threshold = ath10k_mac_op_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, .set_antenna = ath10k_set_antenna, -- cgit v1.2.3-70-g09d2 From 08e75ea84cb595c52f140049fcf6362679473592 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 4 Aug 2015 10:45:11 +0530 Subject: ath10k: Support different txbf configuration schemes qca61x4 uses the vdev param as a sole sufficient configuration for txbf while qca99x0 enables txbf during peer assoc by combining the vdev param value with peer assoc's vht capabilities This patch gets the appropriate txbf configuration scheme before passing the wmi command to enable the same in the firmware. Signed-off-by: Vivek Natarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 +++ drivers/net/wireless/ath/ath10k/wmi-ops.h | 10 ++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.h | 6 ++++++ 5 files changed, 31 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e0bbb6c543c7..1865e45d18c2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2495,6 +2495,9 @@ static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar, u32 param; u32 value; + if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_AFTER_ASSOC) + return 0; + if (!(ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 47fe2e756bec..2591018c4dc5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -49,6 +49,7 @@ struct wmi_ops { struct wmi_roam_ev_arg *arg); int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb, struct wmi_wow_ev_arg *arg); + enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar); struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar); @@ -319,6 +320,15 @@ ath10k_wmi_pull_wow_event(struct ath10k *ar, struct sk_buff *skb, return ar->wmi.ops->pull_wow_event(ar, skb, arg); } +static inline enum wmi_txbf_conf +ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar) +{ + if (!ar->wmi.ops->get_txbf_conf_scheme) + return WMI_TXBF_CONF_UNSUPPORTED; + + return ar->wmi.ops->get_txbf_conf_scheme(ar); +} + static inline int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 567b79720b69..357b5a292a89 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1279,6 +1279,11 @@ ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar, return skb; } +static enum wmi_txbf_conf ath10k_wmi_tlv_txbf_conf_scheme(struct ath10k *ar) +{ + return WMI_TXBF_CONF_AFTER_ASSOC; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, u32 param_value) @@ -3408,6 +3413,7 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev, .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, + .get_txbf_conf_scheme = ath10k_wmi_tlv_txbf_conf_scheme, .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index e6d6b420ecea..36b8f7148b51 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3122,6 +3122,11 @@ static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, return 0; } +static enum wmi_txbf_conf ath10k_wmi_10_4_txbf_conf_scheme(struct ath10k *ar) +{ + return WMI_TXBF_CONF_BEFORE_ASSOC; +} + void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { struct wmi_swba_ev_arg arg = {}; @@ -6444,6 +6449,7 @@ static const struct wmi_ops wmi_10_4_ops = { .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + .get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme, .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 0d4efc9c5796..754cc33b387d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6008,6 +6008,12 @@ struct wmi_tdls_peer_capab_arg { u32 pref_offchan_bw; }; +enum wmi_txbf_conf { + WMI_TXBF_CONF_UNSUPPORTED, + WMI_TXBF_CONF_BEFORE_ASSOC, + WMI_TXBF_CONF_AFTER_ASSOC, +}; + struct ath10k; struct ath10k_vif; struct ath10k_fw_stats_pdev; -- cgit v1.2.3-70-g09d2 From a48e2cc8992a13a58cff04e54e05f959d418554b Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 4 Aug 2015 10:45:12 +0530 Subject: ath10k: Enable MU MIMO txbf support for QCA99X0 This patch enables MU-MIMO transmit beamforming support for QCA99X0 chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 44 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 5 ++++ 2 files changed, 49 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1865e45d18c2..53c627a58384 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4032,6 +4032,43 @@ static u32 get_nss_from_chainmask(u16 chain_mask) return 1; } +static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif) +{ + u32 value = 0; + struct ath10k *ar = arvif->ar; + + if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC) + return 0; + + if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) + value |= SM((ar->num_rf_chains - 1), WMI_TXBF_STS_CAP_OFFSET); + + if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) + value |= SM((ar->num_rf_chains - 1), WMI_BF_SOUND_DIM_OFFSET); + + if (!value) + return 0; + + if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; + + if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) + value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFER | + WMI_VDEV_PARAM_TXBF_SU_TX_BFER); + + if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; + + if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) + value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFEE | + WMI_VDEV_PARAM_TXBF_SU_TX_BFEE); + + return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, + ar->wmi.vdev_param->txbf, value); +} + /* * TODO: * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, @@ -4258,6 +4295,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, } } + ret = ath10k_mac_set_txbf_conf(arvif); + if (ret) { + ath10k_warn(ar, "failed to set txbf for vdev %d: %d\n", + arvif->vdev_id, ret); + goto err_peer_delete; + } + ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); if (ret) { ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 754cc33b387d..232500a5d7bd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4628,6 +4628,11 @@ enum wmi_10_4_vdev_param { #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) +#define WMI_TXBF_STS_CAP_OFFSET_LSB 4 +#define WMI_TXBF_STS_CAP_OFFSET_MASK 0xf0 +#define WMI_BF_SOUND_DIM_OFFSET_LSB 8 +#define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00 + /* slot time long */ #define WMI_VDEV_SLOT_TIME_LONG 0x1 /* slot time short */ -- cgit v1.2.3-70-g09d2 From 84e3df60f0daba5b1e7874101502d0b030afb867 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 5 Aug 2015 06:55:37 +0200 Subject: ath10k: initialize fw_features var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If firmware did not have any feature flags set the var would be left with values found on the stack (i.e. garbage) yielding print string like this: (...) features \xffffffa6m:^R\xfffffffbԂ\xffffffc4^E Fixes: b27bc5a40f91 ("ath10k: dump fw features during probing") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 1a33bf04b7b7..f7aa1c73b481 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - char fw_features[128]; + char fw_features[128] = {}; ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); -- cgit v1.2.3-70-g09d2 From 6f7429c29b9979d64d067543caec940bbc023340 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 5 Aug 2015 12:08:38 +0200 Subject: ath10k: fix hw reconfig on wow failure When WoWLAN resume fails with retval 1 mac80211 will attempt to reconfig the device in a similar manner when hw restart is requested. This wasn't handled properly and yielded call trace warnings and the device ended up not working. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wow.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index a68d8fd853a3..8e02b381990f 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -301,8 +301,26 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); exit: + if (ret) { + switch (ar->state) { + case ATH10K_STATE_ON: + ar->state = ATH10K_STATE_RESTARTING; + ret = 1; + break; + case ATH10K_STATE_OFF: + case ATH10K_STATE_RESTARTING: + case ATH10K_STATE_RESTARTED: + case ATH10K_STATE_UTF: + case ATH10K_STATE_WEDGED: + ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n", + ar->state); + ret = -EIO; + break; + } + } + mutex_unlock(&ar->conf_mutex); - return ret ? 1 : 0; + return ret; } int ath10k_wow_init(struct ath10k *ar) -- cgit v1.2.3-70-g09d2 From adaeed74bc085bc59991cd6e23ee7f720b6c6aab Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 5 Aug 2015 12:15:23 +0200 Subject: ath10k: don't remove peer that doesn't exist If peer creation failed during offchannel Tx the driver attempted to delete the peer nonetheless. This caused the ar->num_peers counter to be incorrectly decremented. This subsequently could cause the counter to drop below 0 and also eventually lead to firmware crash because host would think there are less peer entries created in firmware then there really were. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 53c627a58384..cf74db7b182c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3335,6 +3335,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) int vdev_id; int ret; unsigned long time_left; + bool tmp_peer_created = false; /* FW requirement: We must create a peer before FW will send out * an offchannel frame. Otherwise the frame will be stuck and @@ -3372,6 +3373,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (ret) ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); + tmp_peer_created = (ret == 0); } spin_lock_bh(&ar->data_lock); @@ -3387,7 +3389,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) ath10k_warn(ar, "timed out waiting for offchannel skb %p\n", skb); - if (!peer) { + if (!peer && tmp_peer_created) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); if (ret) ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n", -- cgit v1.2.3-70-g09d2 From e04cafbc38c70af2aad3810ce24ab0eba8114779 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 5 Aug 2015 12:15:24 +0200 Subject: ath10k: fix peer limit enforcement Firmware peer entries are involved in internal firmware vdev structures. This was not accounted for and could lead firmware to crash due to asking it to do more than it could. Fixes: 039a0051ec1a ("ath10k: allocate fw resources for iface combinations") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index cf74db7b182c..96f4285e93b8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -598,11 +598,19 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr, enum wmi_peer_type peer_type) { + struct ath10k_vif *arvif; + int num_peers = 0; int ret; lockdep_assert_held(&ar->conf_mutex); - if (ar->num_peers >= ar->max_num_peers) + num_peers = ar->num_peers; + + /* Each vdev consumes a peer entry as well */ + list_for_each_entry(arvif, &ar->arvifs, list) + num_peers++; + + if (num_peers >= ar->max_num_peers) return -ENOBUFS; ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type); @@ -4112,6 +4120,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, sizeof(arvif->bitrate_mask.control[i].vht_mcs)); } + if (ar->num_peers >= ar->max_num_peers) { + ath10k_warn(ar, "refusing vdev creation due to insufficient peer entry resources in firmware\n"); + return -ENOBUFS; + } + if (ar->free_vdev_map == 0) { ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n"); ret = -EBUSY; -- cgit v1.2.3-70-g09d2 From d07cb049af1a3343cf2043618aaa29f8c84f4649 Mon Sep 17 00:00:00 2001 From: Cheolhyun Park Date: Sun, 12 Apr 2015 16:59:48 +0000 Subject: rtlwifi: misspelled code and comments corrected. Signed-off-by: Cheolhyun Park Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/dm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 0aca6f47487c..d40acaca389e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -312,7 +312,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) struct dig_t *digtable = &rtlpriv->dm_digtable; u32 isbt; - /* modify DIG lower bound, deal with abnorally large false alarm */ + /* modify DIG lower bound, deal with abnormally large false alarm */ if (rtlpriv->falsealm_cnt.cnt_all > 10000) { digtable->large_fa_hit++; if (digtable->forbidden_igi < digtable->cur_igvalue) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 587b8c505a76..7c1db7e7572d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -420,7 +420,7 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw) "dm_DIG() Before: Recover_cnt=%d, rx_gain_min=%x\n", de_digtable->recover_cnt, de_digtable->rx_gain_min); - /* deal with abnorally large false alarm */ + /* deal with abnormally large false alarm */ if (falsealm_cnt->cnt_all > 10000) { RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG(): Abnormally false alarm case\n"); -- cgit v1.2.3-70-g09d2 From 34edd5f6839db083b625d473efa4145449cd1af0 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 14 May 2015 17:29:54 +0200 Subject: ath9k_htc: match wait_for_completion_timeout return type Return type of wait_for_completion_timeout is unsigned long not int. As time_left is exclusively used for wait_for_completion_timeout here its type is simply changed to unsigned long. API conformance testing for completions with coccinelle spatches are being used to locate API usage inconsistencies: ./drivers/net/wireless/ath/ath9k/htc_hst.c:171 int return assigned to unsigned long ./drivers/net/wireless/ath/ath9k/htc_hst.c:277 int return assigned to unsigned long ./drivers/net/wireless/ath/ath9k/htc_hst.c:206 int return assigned to unsigned long Patch was compile tested with x86_64_defconfig + CONFIG_ATH_CARDS=m, CONFIG_ATH9K_HTC=m Patch is against 4.1-rc3 (localversion-next is -next-20150514) Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_hst.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index d2408da38c1c..2294709ee8b0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -146,7 +146,8 @@ static int htc_config_pipe_credits(struct htc_target *target) { struct sk_buff *skb; struct htc_config_pipe_msg *cp_msg; - int ret, time_left; + int ret; + unsigned long time_left; skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { @@ -184,7 +185,8 @@ static int htc_setup_complete(struct htc_target *target) { struct sk_buff *skb; struct htc_comp_msg *comp_msg; - int ret = 0, time_left; + int ret = 0; + unsigned long time_left; skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { @@ -236,7 +238,8 @@ int htc_connect_service(struct htc_target *target, struct sk_buff *skb; struct htc_endpoint *endpoint; struct htc_conn_svc_msg *conn_msg; - int ret, time_left; + int ret; + unsigned long time_left; /* Find an available endpoint */ endpoint = get_next_avail_ep(target->endpoint); -- cgit v1.2.3-70-g09d2 From 70a56550a664ce93583f59ef1b885e7616c942e4 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 14 May 2015 18:25:26 +0200 Subject: ath9k_htc: drv_init: match wait_for_completion_timeout return type Return type of wait_for_completion_timeout is unsigned long not int. As time_left is exclusively used for wait_for_completion_timeout here its type is simply changed to unsigned long. API conformance testing for completions with coccinelle spatches are being used to locate API usage inconsistencies: ./drivers/net/wireless/ath/ath9k/htc_drv_init.c:81 int return assigned to unsigned long Patch was compile tested with x86_64_defconfig + CONFIG_ATH_CARDS=m, CONFIG_ATH9K_HTC=m Patch is against 4.1-rc3 (localversion-next is -next-20150514) Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 39eaf9b6e9b4..1e84882f8c5b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -74,7 +74,7 @@ static struct ath_ps_ops ath9k_htc_ps_ops = { static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { - int time_left; + unsigned long time_left; if (atomic_read(&priv->htc->tgt_ready) > 0) { atomic_dec(&priv->htc->tgt_ready); -- cgit v1.2.3-70-g09d2 From 61fc39204bc0db0070267fe0f7920c38b0af87ef Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 14 May 2015 18:43:41 +0200 Subject: ath9k_htc: wmi: match wait_for_completion_timeout return type Return type of wait_for_completion_timeout is unsigned long not int. As time_left is exclusively used for wait_for_completion_timeout here its type is simply changed to unsigned long. API conformance testing for completions with coccinelle spatches are being used to locate API usage inconsistencies: ./drivers/net/wireless/ath/ath9k/wmi.c:331 int return assigned to unsigned long Patch was compile tested with x86_64_defconfig + CONFIG_ATH_CARDS=m, CONFIG_ATH9K_HTC=m Patch is against 4.1-rc3 (localversion-next is -next-20150514) Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index ca533b4321bd..9c16e2a6d185 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -299,7 +299,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, sizeof(struct wmi_cmd_hdr); struct sk_buff *skb; u8 *data; - int time_left, ret = 0; + unsigned long time_left; + int ret = 0; if (ah->ah_flags & AH_UNPLUGGED) return 0; -- cgit v1.2.3-70-g09d2 From ab63cb8b0cc84a89f65e418357d7e6b9b914c89a Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 14 May 2015 18:56:16 +0200 Subject: ath9k: match wait_for_completion_timeout return type Return type of wait_for_completion_timeout is unsigned long not int. As time_left is exclusively used for wait_for_completion_timeout here its type is simply changed to unsigned long. API conformance testing for completions with coccinelle spatches are being used to locate API usage inconsistencies: ./drivers/net/wireless/ath/ath9k/link.c:197 int return assigned to unsigned long Patch was compile tested with x86_64_defconfig + CONFIG_ATH_CARDS=m, Patch is against 4.1-rc3 (localversion-next is -next-20150514) Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 90631d768a60..5ad0feeebc86 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -172,7 +172,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_tx_control txctl; - int time_left; + unsigned long time_left; memset(&txctl, 0, sizeof(txctl)); txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; -- cgit v1.2.3-70-g09d2 From d3928d0946bf75dc6709a08b12839ecb889f2564 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 9 Jul 2015 13:43:18 +0530 Subject: brcmfmac: dhd_sdio.c: use existing atomic_or primitive There's already a generic implementation so use that instead. Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index d36f5f3d931b..f990e3d0e696 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2564,15 +2564,6 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) } } -static void atomic_orr(int val, atomic_t *v) -{ - int old_val; - - old_val = atomic_read(v); - while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) - old_val = atomic_read(v); -} - static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) { struct brcmf_core *buscore; @@ -2595,7 +2586,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - atomic_orr(val, &bus->intstatus); + atomic_or(val, &bus->intstatus); } return ret; @@ -2712,7 +2703,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) /* Keep still-pending events for next scheduling */ if (intstatus) - atomic_orr(intstatus, &bus->intstatus); + atomic_or(intstatus, &bus->intstatus); brcmf_sdio_clrintr(bus); -- cgit v1.2.3-70-g09d2 From e41c513599187bd100644566bde86541c01db1d6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:11 -0500 Subject: rtlwifi: rtl8192ce: rtl8192cu: Fix endian issue Commit e996db69833a (rtlwifi: rtl8192c: Add init codes for "fw_version" and "fw_subversion") added initialization for fw_version, but failed to note that the variable in the firmware header is little-endian. The following Sparse warning results: CHECK drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c:242:36: warning: incorrect type in assignment (different base types) drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c:242:36: expected unsigned short [unsigned] [usertype] fw_version drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c:242:36: got restricted __le16 [usertype] version When fixing this problem, I noticed that several of the drivers contain nearly identical copies of the firmware header struct, and that only the one used in rtl8192c{e,u} had correct endian notation. The struct has been moved into a common header, and the other drivers will be fixed in subsequant patches. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 12 ++++++------ drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h | 19 ------------------- drivers/net/wireless/rtlwifi/wifi.h | 21 +++++++++++++++++++-- 3 files changed, 25 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 14b819ea8b71..43fcb25c885f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -221,7 +221,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl92c_firmware_header *pfwheader; + struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; int err; @@ -230,19 +230,19 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) if (!rtlhal->pfirmware) return 1; - pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; pfwdata = (u8 *)rtlhal->pfirmware; fwsize = rtlhal->fwsize; if (IS_FW_HEADER_EXIST(pfwheader)) { RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "Firmware Version(%d), Signature(%#x),Size(%d)\n", pfwheader->version, pfwheader->signature, - (int)sizeof(struct rtl92c_firmware_header)); + (int)sizeof(struct rtlwifi_firmware_header)); - rtlhal->fw_version = pfwheader->version; + rtlhal->fw_version = le16_to_cpu(pfwheader->version); rtlhal->fw_subversion = pfwheader->subversion; - pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); - fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); + fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); } _rtl92c_enable_fw_download(hw, true); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index e9f4281f5067..864806c19ca7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -69,25 +69,6 @@ ((GET_CVID_CUT_VERSION(version) == \ CHIP_VENDOR_UMC_B_CUT) ? true : false) : false) -struct rtl92c_firmware_header { - __le16 signature; - u8 category; - u8 function; - __le16 version; - u8 subversion; - u8 rsvd1; - u8 month; - u8 date; - u8 hour; - u8 minute; - __le16 ramcodeSize; - __le16 rsvd2; - __le32 svnindex; - __le32 rsvd3; - __le32 rsvd4; - __le32 rsvd5; -}; - #define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0)) #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 2b770b5e2620..3308f9ecd3d7 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -222,6 +222,25 @@ enum rf_tx_num { #define WOL_REASON_REALWOW_V2_WAKEUPPKT BIT(9) #define WOL_REASON_REALWOW_V2_ACKLOST BIT(10) +struct rtlwifi_firmware_header { + __le16 signature; + u8 category; + u8 function; + __le16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + __le16 ramcodeSize; + __le16 rsvd2; + __le32 svnindex; + __le32 rsvd3; + __le32 rsvd4; + __le32 rsvd5; +}; + struct txpower_info_2g { u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; @@ -2064,8 +2083,6 @@ struct rtl_tcb_desc { bool tx_enable_sw_calc_duration; }; -struct rtl92c_firmware_header; - struct rtl_wow_pattern { u8 type; u16 crc; -- cgit v1.2.3-70-g09d2 From 7c24d086ef9ccbffc46f5f9e2680f292ca356166 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:12 -0500 Subject: rtlwifi: rtl8723ae: rtl8723be: rtl8723com: Fix firmware header endian issues The drivers are converted to use the common firmware header struct. Because the old header definition failed to indicate that the multi-byte entries should be little endian, several problems were thus exposed. These are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8723ae/sw.c | 4 ++-- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 4 ++-- drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c | 10 +++++----- drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h | 19 ------------------- drivers/net/wireless/rtlwifi/wifi.h | 4 +--- 5 files changed, 10 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 8280bab43df4..3859b3e3d158 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -205,9 +205,9 @@ bool rtl8723e_get_btc_status(void) return true; } -static bool is_fw_header(struct rtl8723e_firmware_header *hdr) +static bool is_fw_header(struct rtlwifi_firmware_header *hdr) { - return (hdr->signature & 0xfff0) == 0x2300; + return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x2300; } static struct rtl_hal_ops rtl8723e_hal_ops = { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 1017f02d7bf7..3ba1e3218ed2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -209,9 +209,9 @@ bool rtl8723be_get_btc_status(void) return true; } -static bool is_fw_header(struct rtl8723e_firmware_header *hdr) +static bool is_fw_header(struct rtlwifi_firmware_header *hdr) { - return (hdr->signature & 0xfff0) == 0x5300; + return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x5300; } static struct rtl_hal_ops rtl8723be_hal_ops = { diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c index dd698e7e9ace..a2f5e89bedfe 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -253,7 +253,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl8723e_firmware_header *pfwheader; + struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; int err; @@ -263,7 +263,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, if (!rtlhal->pfirmware) return 1; - pfwheader = (struct rtl8723e_firmware_header *)rtlhal->pfirmware; + pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; pfwdata = rtlhal->pfirmware; fwsize = rtlhal->fwsize; @@ -275,10 +275,10 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "Firmware Version(%d), Signature(%#x), Size(%d)\n", pfwheader->version, pfwheader->signature, - (int)sizeof(struct rtl8723e_firmware_header)); + (int)sizeof(struct rtlwifi_firmware_header)); - pfwdata = pfwdata + sizeof(struct rtl8723e_firmware_header); - fwsize = fwsize - sizeof(struct rtl8723e_firmware_header); + pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); + fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); } if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h index 3ebafc80972f..8ea372d1626e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h @@ -50,25 +50,6 @@ enum version_8723e { VERSION_UNKNOWN = 0xFF, }; -struct rtl8723e_firmware_header { - u16 signature; - u8 category; - u8 function; - u16 version; - u8 subversion; - u8 rsvd1; - u8 month; - u8 date; - u8 hour; - u8 minute; - u16 ramcodesize; - u16 rsvd2; - u32 svnindex; - u32 rsvd3; - u32 rsvd4; - u32 rsvd5; -}; - enum rtl8723be_cmd { H2C_8723BE_RSVDPAGE = 0, H2C_8723BE_JOINBSSRPT = 1, diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 3308f9ecd3d7..b90ca618b123 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -2089,8 +2089,6 @@ struct rtl_wow_pattern { u32 mask[4]; }; -struct rtl8723e_firmware_header; - struct rtl_hal_ops { int (*init_sw_vars) (struct ieee80211_hw *hw); void (*deinit_sw_vars) (struct ieee80211_hw *hw); @@ -2194,7 +2192,7 @@ struct rtl_hal_ops { void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); bool (*get_btc_status) (void); - bool (*is_fw_header)(struct rtl8723e_firmware_header *hdr); + bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr); u32 (*rx_command_packet)(struct ieee80211_hw *hw, struct rtl_stats status, struct sk_buff *skb); void (*add_wowlan_pattern)(struct ieee80211_hw *hw, -- cgit v1.2.3-70-g09d2 From 253f10abb7c24665988cf0abda65acaa40ce5815 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:13 -0500 Subject: rtlwifi: rtl8821ae: Fix firmware endian issues This driver is converted to use the common firmware header struct. Because the old header definition failed to indicate that the multi-byte entries should be little endian, several problems were thus exposed. These are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/fw.c | 14 +++++++------- drivers/net/wireless/rtlwifi/rtl8821ae/fw.h | 23 ++--------------------- 2 files changed, 9 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c index 95e95626b632..525eb234627c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c @@ -210,7 +210,7 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl8821a_firmware_header *pfwheader; + struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; int err; @@ -228,8 +228,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) return 1; pfwheader = - (struct rtl8821a_firmware_header *)rtlhal->wowlan_firmware; - rtlhal->fw_version = pfwheader->version; + (struct rtlwifi_firmware_header *)rtlhal->wowlan_firmware; + rtlhal->fw_version = le16_to_cpu(pfwheader->version); rtlhal->fw_subversion = pfwheader->subversion; pfwdata = (u8 *)rtlhal->wowlan_firmware; fwsize = rtlhal->wowlan_fwsize; @@ -238,8 +238,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) return 1; pfwheader = - (struct rtl8821a_firmware_header *)rtlhal->pfirmware; - rtlhal->fw_version = pfwheader->version; + (struct rtlwifi_firmware_header *)rtlhal->pfirmware; + rtlhal->fw_version = le16_to_cpu(pfwheader->version); rtlhal->fw_subversion = pfwheader->subversion; pfwdata = (u8 *)rtlhal->pfirmware; fwsize = rtlhal->fwsize; @@ -255,8 +255,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) "Firmware Version(%d), Signature(%#x)\n", pfwheader->version, pfwheader->signature); - pfwdata = pfwdata + sizeof(struct rtl8821a_firmware_header); - fwsize = fwsize - sizeof(struct rtl8821a_firmware_header); + pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); + fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); } if (rtlhal->mac_func_enable) { diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h index 591c14c0b9b5..8f5b4aade3c9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h @@ -34,10 +34,10 @@ #define FW_8821AE_POLLING_TIMEOUT_COUNT 6000 #define IS_FW_HEADER_EXIST_8812(_pfwhdr) \ - ((_pfwhdr->signature&0xFFF0) == 0x9500) + ((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x9500) #define IS_FW_HEADER_EXIST_8821(_pfwhdr) \ - ((_pfwhdr->signature&0xFFF0) == 0x2100) + ((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x2100) #define USE_OLD_WOWLAN_DEBUG_FW 0 @@ -137,25 +137,6 @@ #define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) #define FW_PWR_STATE_RF_OFF 0 -struct rtl8821a_firmware_header { - u16 signature; - u8 category; - u8 function; - u16 version; - u8 subversion; - u8 rsvd1; - u8 month; - u8 date; - u8 hour; - u8 minute; - u16 ramcodeSize; - u16 rsvd2; - u32 svnindex; - u32 rsvd3; - u32 rsvd4; - u32 rsvd5; -}; - enum rtl8812_c2h_evt { C2H_8812_DBG = 0, C2H_8812_LB = 1, -- cgit v1.2.3-70-g09d2 From b290b57d18aa0e1d35caf209ccc12ac3ef14a6b3 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:14 -0500 Subject: rtlwifi: rtl8192de: Fix firmware header endian issues This driver is converted to use the common firmware header struct. Because the old header definition failed to indicate that the multi-byte entries should be little endian, several problems were thus exposed. These are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/fw.h | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h index 1646e7c3d0f8..8a38daa316cb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -110,28 +110,6 @@ #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) -struct rtl92d_firmware_header { - u16 signature; - u8 category; - u8 function; - u16 version; - u8 subversion; - u8 rsvd1; - - u8 month; - u8 date; - u8 hour; - u8 minute; - u16 ramcodeSize; - u16 rsvd2; - - u32 svnindex; - u32 rsvd3; - - u32 rsvd4; - u32 rsvd5; -}; - int rtl92d_download_fw(struct ieee80211_hw *hw); void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); -- cgit v1.2.3-70-g09d2 From 201b63c7c907bcc89bb11797ce2ca2a93027004b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:15 -0500 Subject: rtlwifi: rtl888ee: Fix firmware header endian issues This driver is converted to use the common firmware header struct. Because the old header definition failed to indicate that the multi-byte entries should be little endian, several problems were thus exposed. These are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8188ee/fw.c | 10 +++++----- drivers/net/wireless/rtlwifi/rtl8188ee/fw.h | 21 +-------------------- 2 files changed, 6 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c index c8058aa73ecf..629125658b87 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c @@ -200,7 +200,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl92c_firmware_header *pfwheader; + struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; int err; @@ -209,7 +209,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw, if (!rtlhal->pfirmware) return 1; - pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; pfwdata = rtlhal->pfirmware; fwsize = rtlhal->fwsize; RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, @@ -219,10 +219,10 @@ int rtl88e_download_fw(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "Firmware Version(%d), Signature(%#x), Size(%d)\n", pfwheader->version, pfwheader->signature, - (int)sizeof(struct rtl92c_firmware_header)); + (int)sizeof(struct rtlwifi_firmware_header)); - pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); - fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); + fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); } if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h index 05e944e451f4..21bd4a5337ab 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h @@ -37,7 +37,7 @@ #define FW_8192C_POLLING_TIMEOUT_COUNT 3000 #define IS_FW_HEADER_EXIST(_pfwhdr) \ - ((_pfwhdr->signature&0xFFFF) == 0x88E1) + ((le16_to_cpu(_pfwhdr->signature) & 0xFFFF) == 0x88E1) #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_88E_RSVDPAGE_LOC_LEN 5 @@ -131,25 +131,6 @@ #define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) #define FW_PWR_STATE_RF_OFF 0 -struct rtl92c_firmware_header { - u16 signature; - u8 category; - u8 function; - u16 version; - u8 subversion; - u8 rsvd1; - u8 month; - u8 date; - u8 hour; - u8 minute; - u16 ramcodesize; - u16 rsvd2; - u32 svnindex; - u32 rsvd3; - u32 rsvd4; - u32 rsvd5; -}; - enum rtl8188e_h2c_cmd { H2C_88E_RSVDPAGE = 0, H2C_88E_JOINBSSRPT = 1, -- cgit v1.2.3-70-g09d2 From 8d882bcf82743f20b0546088f935a718b4ae6f60 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 15:56:16 -0500 Subject: rtlwifi: rtl8192ee: Fix firmware header endian issues This driver is converted to use the common firmware header struct. Because the old header definition failed to indicate that the multi-byte entries should be little endian, several problems were thus exposed. These are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/fw.c | 12 ++++++------ drivers/net/wireless/rtlwifi/rtl8192ee/fw.h | 21 +-------------------- 2 files changed, 7 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c index 232865cc3ffd..0708eedd9671 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c @@ -198,7 +198,7 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl92c_firmware_header *pfwheader; + struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; int err; @@ -207,8 +207,8 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) if (!rtlhal->pfirmware) return 1; - pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; - rtlhal->fw_version = pfwheader->version; + pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; + rtlhal->fw_version = le16_to_cpu(pfwheader->version); rtlhal->fw_subversion = pfwheader->subversion; pfwdata = (u8 *)rtlhal->pfirmware; fwsize = rtlhal->fwsize; @@ -219,10 +219,10 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "Firmware Version(%d), Signature(%#x),Size(%d)\n", pfwheader->version, pfwheader->signature, - (int)sizeof(struct rtl92c_firmware_header)); + (int)sizeof(struct rtlwifi_firmware_header)); - pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); - fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); + fwsize = fwsize - sizeof(struct rtlwifi_firmware_header); } else { RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "Firmware no Header, Signature(%#x)\n", diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h index 3e2a48e5fb4d..069da1e7e80a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h @@ -33,7 +33,7 @@ #define FW_8192C_POLLING_TIMEOUT_COUNT 3000 #define IS_FW_HEADER_EXIST(_pfwhdr) \ - ((_pfwhdr->signature&0xFFF0) == 0x92E0) + ((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x92E0) #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_92E_RSVDPAGE_LOC_LEN 5 @@ -89,25 +89,6 @@ #define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) #define FW_PWR_STATE_RF_OFF 0 -struct rtl92c_firmware_header { - u16 signature; - u8 category; - u8 function; - u16 version; - u8 subversion; - u8 rsvd1; - u8 month; - u8 date; - u8 hour; - u8 minute; - u16 ramcodesize; - u16 rsvd2; - u32 svnindex; - u32 rsvd3; - u32 rsvd4; - u32 rsvd5; -}; - enum rtl8192e_h2c_cmd { H2C_92E_RSVDPAGE = 0, H2C_92E_MSRRPT = 1, -- cgit v1.2.3-70-g09d2 From 3544f9f150bb58a3678c161a505b186893971c8a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 3 Aug 2015 16:15:53 -0500 Subject: rtlwifi: rtl8192c-common: Fix two typos In this driver, two variables are masked by one quantity, and then tested against a second number with more bits that the mask. Accordingly, the test always fails. To minimize the possibility of such typos, a symbolic definition of the mask is created and used. The separate load and mask operations are also combined into a single statement. Reported-by: David Binderman Signed-off-by: Larry Finger Cc: David Binderman Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index d40acaca389e..03cbe4cf110b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -39,6 +39,7 @@ #define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) #define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) #define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) +#define BT_MASK 0x00ffffff #define RTLPRIV (struct rtl_priv *) #define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ @@ -1536,13 +1537,11 @@ static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) return false; bt_state = rtl_read_byte(rtlpriv, 0x4fd); - bt_tx = rtl_read_dword(rtlpriv, 0x488); - bt_tx = bt_tx & 0x00ffffff; - bt_pri = rtl_read_dword(rtlpriv, 0x48c); - bt_pri = bt_pri & 0x00ffffff; + bt_tx = rtl_read_dword(rtlpriv, 0x488) & BT_MASK; + bt_pri = rtl_read_dword(rtlpriv, 0x48c) & BT_MASK; polling = rtl_read_dword(rtlpriv, 0x490); - if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && + if (bt_tx == BT_MASK && bt_pri == BT_MASK && polling == 0xffffffff && bt_state == 0xff) return false; -- cgit v1.2.3-70-g09d2 From 3b1f0e86958b8afcfb6980f987c41e149480f9bd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 4 Aug 2015 10:49:27 +0300 Subject: mwifiex: usb: return an error if kmalloc fails The current code returns success if kmalloc fails. Signed-off-by: Dan Carpenter Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index fbad99c50307..f866d5da222b 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -870,8 +870,10 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, /* Allocate memory for transmit */ fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL); - if (!fwdata) + if (!fwdata) { + ret = -ENOMEM; goto fw_exit; + } /* Allocate memory for receive */ recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From 6d85ef00d9dfe3bb61b021476465fa4e371ed076 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 5 Aug 2015 06:09:40 -0700 Subject: mwifiex: add support for 8997 chipset This patch adds support for 8997 chipset to mwifiex with SDIO/PCIe/USB interface. The corresponding firmware image files are located in: "mrvl/sd8997_uapsta.bin" "mrvl/pcie8997_uapsta.bin" "mrvl/usb8997_uapsta.bin" Signed-off-by: Zhaoyang Liu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/Kconfig | 12 +++---- drivers/net/wireless/mwifiex/pcie.c | 12 +++++-- drivers/net/wireless/mwifiex/pcie.h | 45 ++++++++++++++++++++++++- drivers/net/wireless/mwifiex/sdio.c | 5 +++ drivers/net/wireless/mwifiex/sdio.h | 65 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/usb.c | 14 ++++++++ drivers/net/wireless/mwifiex/usb.h | 3 ++ 7 files changed, 147 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 48edf387683e..317d99189556 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -9,36 +9,36 @@ config MWIFIEX mwifiex. config MWIFIEX_SDIO - tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897" + tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897/SD8997" depends on MWIFIEX && MMC select FW_LOADER select WANT_DEV_COREDUMP ---help--- This adds support for wireless adapters based on Marvell - 8786/8787/8797/8887/8897 chipsets with SDIO interface. + 8786/8787/8797/8887/8897/8997 chipsets with SDIO interface. If you choose to build it as a module, it will be called mwifiex_sdio. config MWIFIEX_PCIE - tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" + tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897/8997" depends on MWIFIEX && PCI select FW_LOADER select WANT_DEV_COREDUMP ---help--- This adds support for wireless adapters based on Marvell - 8766/8897 chipsets with PCIe interface. + 8766/8897/8997 chipsets with PCIe interface. If you choose to build it as a module, it will be called mwifiex_pcie. config MWIFIEX_USB - tristate "Marvell WiFi-Ex Driver for USB8766/8797/8897" + tristate "Marvell WiFi-Ex Driver for USB8766/8797/8897/8997" depends on MWIFIEX && USB select FW_LOADER ---help--- This adds support for wireless adapters based on Marvell - 8797/8897 chipset with USB interface. + 8797/8897/8997 chipset with USB interface. If you choose to build it as a module, it will be called mwifiex_usb. diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 33c75d741017..408b68460716 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -266,12 +266,17 @@ static const struct pci_device_id mwifiex_ids[] = { { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - .driver_data = (unsigned long) &mwifiex_pcie8766, + .driver_data = (unsigned long)&mwifiex_pcie8766, }, { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - .driver_data = (unsigned long) &mwifiex_pcie8897, + .driver_data = (unsigned long)&mwifiex_pcie8897, + }, + { + PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + .driver_data = (unsigned long)&mwifiex_pcie8997, }, {}, }; @@ -1082,6 +1087,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) card->txbd_rdptr++; break; case PCIE_DEVICE_ID_MARVELL_88W8897: + case PCIE_DEVICE_ID_MARVELL_88W8997: card->txbd_rdptr += reg->ring_tx_start_ptr; break; } @@ -1179,6 +1185,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, card->txbd_wrptr++; break; case PCIE_DEVICE_ID_MARVELL_88W8897: + case PCIE_DEVICE_ID_MARVELL_88W8997: card->txbd_wrptr += reg->ring_tx_start_ptr; break; } @@ -2733,3 +2740,4 @@ MODULE_VERSION(PCIE_VERSION); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME); MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME); +MODULE_FIRMWARE(PCIE8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 0e7ee8b72358..48e549c3b285 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -30,10 +30,12 @@ #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" #define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" +#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcie8997_uapsta.bin" #define PCIE_VENDOR_ID_MARVELL (0x11ab) #define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) #define PCIE_DEVICE_ID_MARVELL_88W8897 (0x2b38) +#define PCIE_DEVICE_ID_MARVELL_88W8997 (0x2b42) /* Constants for Buffer Descriptor (BD) rings */ #define MWIFIEX_MAX_TXRX_BD 0x20 @@ -197,7 +199,38 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .sleep_cookie = 0, .fw_dump_ctrl = 0xcf4, .fw_dump_start = 0xcf8, - .fw_dump_end = 0xcff + .fw_dump_end = 0xcff, +}; + +static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { + .cmd_addr_lo = PCIE_SCRATCH_0_REG, + .cmd_addr_hi = PCIE_SCRATCH_1_REG, + .cmd_size = PCIE_SCRATCH_2_REG, + .fw_status = PCIE_SCRATCH_3_REG, + .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, + .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, + .tx_rdptr = 0xC1A4, + .tx_wrptr = 0xC1A8, + .rx_rdptr = 0xC1A8, + .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, + .rx_mask = 0x00000FFF, + .rx_wrap_mask = 0x000001FF, + .tx_rollover_ind = BIT(28), + .rx_rollover_ind = BIT(12), + .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, + .ring_flag_sop = MWIFIEX_BD_FLAG_SOP, + .ring_flag_eop = MWIFIEX_BD_FLAG_EOP, + .ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, + .ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, + .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, + .pfu_enabled = 1, + .sleep_cookie = 0, }; struct mwifiex_pcie_device { @@ -227,6 +260,15 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .can_ext_scan = true, }; +static const struct mwifiex_pcie_device mwifiex_pcie8997 = { + .firmware = PCIE8997_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_8997, + .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .can_dump_fw = false, + .can_ext_scan = true, +}; + struct mwifiex_evt_buf_desc { u64 paddr; u16 len; @@ -325,6 +367,7 @@ mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) return 1; break; case PCIE_DEVICE_ID_MARVELL_88W8897: + case PCIE_DEVICE_ID_MARVELL_88W8997: if (((card->txbd_wrptr & reg->tx_mask) != (card->txbd_rdptr & reg->tx_mask)) || ((card->txbd_wrptr & reg->tx_rollover_ind) == diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index e4c35ee12782..9904a77da848 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -288,6 +288,8 @@ static int mwifiex_sdio_suspend(struct device *dev) #define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) /* Device ID for SD8801 */ #define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) +/* Device ID for SD8997 */ +#define SDIO_DEVICE_ID_MARVELL_8997 (0x9141) /* WLAN IDs */ @@ -304,6 +306,8 @@ static const struct sdio_device_id mwifiex_ids[] = { .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997), + .driver_data = (unsigned long)&mwifiex_sdio_sd8997}, {}, }; @@ -2531,3 +2535,4 @@ MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME); +MODULE_FIRMWARE(SD8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index c44da610541a..cd149196042a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -35,6 +35,7 @@ #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin" #define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin" #define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin" +#define SD8997_DEFAULT_FW_NAME "mrvl/sd8997_uapsta.bin" #define BLOCK_MODE 1 #define BYTE_MODE 0 @@ -364,6 +365,55 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { 0x59, 0x5c, 0x5d}, }; +static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = { + .start_rd_port = 0, + .start_wr_port = 0, + .base_0_reg = 0xF8, + .base_1_reg = 0xF9, + .poll_reg = 0x5C, + .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | + CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, + .host_int_rsr_reg = 0x4, + .host_int_status_reg = 0x0C, + .host_int_mask_reg = 0x08, + .status_reg_0 = 0xE8, + .status_reg_1 = 0xE9, + .sdio_int_mask = 0xff, + .data_port_mask = 0xffffffff, + .io_port_0_reg = 0xE4, + .io_port_1_reg = 0xE5, + .io_port_2_reg = 0xE6, + .max_mp_regs = 196, + .rd_bitmap_l = 0x10, + .rd_bitmap_u = 0x11, + .rd_bitmap_1l = 0x12, + .rd_bitmap_1u = 0x13, + .wr_bitmap_l = 0x14, + .wr_bitmap_u = 0x15, + .wr_bitmap_1l = 0x16, + .wr_bitmap_1u = 0x17, + .rd_len_p0_l = 0x18, + .rd_len_p0_u = 0x19, + .card_misc_cfg_reg = 0xd8, + .card_cfg_2_1_reg = 0xd9, + .cmd_rd_len_0 = 0xc0, + .cmd_rd_len_1 = 0xc1, + .cmd_rd_len_2 = 0xc2, + .cmd_rd_len_3 = 0xc3, + .cmd_cfg_0 = 0xc4, + .cmd_cfg_1 = 0xc5, + .cmd_cfg_2 = 0xc6, + .cmd_cfg_3 = 0xc7, + .func1_dump_reg_start = 0x10, + .func1_dump_reg_end = 0x17, + .func1_scratch_reg = 0xe8, + .func1_spec_reg_num = 13, + .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, + 0x60, 0x61, 0x62, 0x64, + 0x65, 0x66, 0x68, 0x69, + 0x6a}, +}; + static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { .start_rd_port = 0, .start_wr_port = 0, @@ -472,6 +522,21 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .can_ext_scan = true, }; +static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { + .firmware = SD8997_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_sd8997, + .max_ports = 32, + .mp_agg_pkt_limit = 16, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, + .supports_sdio_new_mode = true, + .has_control_mask = false, + .can_dump_fw = false, + .can_auto_tdls = false, + .can_ext_scan = true, +}; + static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .firmware = SD8887_DEFAULT_FW_NAME, .reg = &mwifiex_reg_sd8887, diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index f866d5da222b..5e789b2e06ea 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -47,6 +47,11 @@ static struct usb_device_id mwifiex_usb_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff)}, + /* 8997 */ + {USB_DEVICE(USB8XXX_VID, USB8997_PID_1)}, + {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8997_PID_2, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0xff)}, { } /* Terminating entry */ }; @@ -382,12 +387,14 @@ static int mwifiex_usb_probe(struct usb_interface *intf, case USB8797_PID_1: case USB8801_PID_1: case USB8897_PID_1: + case USB8997_PID_1: card->usb_boot_state = USB8XXX_FW_DNLD; break; case USB8766_PID_2: case USB8797_PID_2: case USB8801_PID_2: case USB8897_PID_2: + case USB8997_PID_2: card->usb_boot_state = USB8XXX_FW_READY; break; default: @@ -814,6 +821,12 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->dev = &card->udev->dev; switch (le16_to_cpu(card->udev->descriptor.idProduct)) { + case USB8997_PID_1: + case USB8997_PID_2: + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; + strcpy(adapter->fw_name, USB8997_DEFAULT_FW_NAME); + adapter->ext_scan = true; + break; case USB8897_PID_1: case USB8897_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; @@ -1123,3 +1136,4 @@ MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); +MODULE_FIRMWARE(USB8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index 57e1a5736318..f0051f8c8981 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -32,6 +32,8 @@ #define USB8897_PID_2 0x2046 #define USB8801_PID_1 0x2049 #define USB8801_PID_2 0x204a +#define USB8997_PID_1 0x204d +#define USB8997_PID_2 0x204e #define USB8XXX_FW_DNLD 1 @@ -46,6 +48,7 @@ #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" #define USB8801_DEFAULT_FW_NAME "mrvl/usb8801_uapsta.bin" #define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin" +#define USB8997_DEFAULT_FW_NAME "mrvl/usb8997_uapsta.bin" #define FW_DNLD_TX_BUF_SIZE 620 #define FW_DNLD_RX_BUF_SIZE 2048 -- cgit v1.2.3-70-g09d2 From eee7f1961b9d85d1fbd1febf73c90d421cc75536 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 5 Aug 2015 06:09:41 -0700 Subject: mwifiex: add firmware dump support for SD8997 This patch adds firmware dump feature for SD8997 chipset. The difference here is only one memory type is needed to save all firmware information. Device dump information will be uploaded to usersapace file. Signed-off-by: Zhaoyang Liu Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 147 +++++++++++++++++++++++++++++++++--- drivers/net/wireless/mwifiex/sdio.h | 11 ++- 2 files changed, 148 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 9904a77da848..7cef27e9d33f 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -51,6 +51,10 @@ static unsigned long iface_work_flags; static struct semaphore add_remove_card_sem; +static struct memory_type_mapping generic_mem_type_map[] = { + {"DUMP", NULL, 0, 0xDD}, +}; + static struct memory_type_mapping mem_type_mapping_tbl[] = { {"ITCM", NULL, 0, 0xF0}, {"DTCM", NULL, 0, 0xF1}, @@ -108,6 +112,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; card->can_dump_fw = data->can_dump_fw; + card->fw_dump_enh = data->fw_dump_enh; card->can_auto_tdls = data->can_auto_tdls; card->can_ext_scan = data->can_ext_scan; } @@ -1969,8 +1974,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->dev = &func->dev; strcpy(adapter->fw_name, card->firmware); - adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; - adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); + if (card->fw_dump_enh) { + adapter->mem_type_mapping_tbl = generic_mem_type_map; + adapter->num_mem_types = 1; + } else { + adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; + adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); + } return 0; } @@ -2163,8 +2173,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, int ret, tries; u8 ctrl_data = 0; - sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl, - &ret); + sdio_writeb(card->func, card->reg->fw_dump_host_ready, + card->reg->fw_dump_ctrl, &ret); if (ret) { mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n"); return RDWR_STATUS_FAILURE; @@ -2180,10 +2190,10 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, break; if (doneflag && ctrl_data == doneflag) return RDWR_STATUS_DONE; - if (ctrl_data != FW_DUMP_HOST_READY) { + if (ctrl_data != card->reg->fw_dump_host_ready) { mwifiex_dbg(adapter, WARN, - "The ctrl reg was changed, re-try again!\n"); - sdio_writeb(card->func, FW_DUMP_HOST_READY, + "The ctrl reg was changed, re-try again\n"); + sdio_writeb(card->func, card->reg->fw_dump_host_ready, card->reg->fw_dump_ctrl, &ret); if (ret) { mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); @@ -2192,7 +2202,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, } usleep_range(100, 200); } - if (ctrl_data == FW_DUMP_HOST_READY) { + if (ctrl_data == card->reg->fw_dump_host_ready) { mwifiex_dbg(adapter, ERROR, "Fail to pull ctrl_data\n"); return RDWR_STATUS_FAILURE; @@ -2325,10 +2335,129 @@ done: sdio_release_host(card->func); } +static void mwifiex_sdio_generic_fw_dump(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + struct memory_type_mapping *entry = &generic_mem_type_map[0]; + unsigned int reg, reg_start, reg_end; + u8 start_flag = 0, done_flag = 0; + u8 *dbg_ptr, *end_ptr; + enum rdwr_status stat; + int ret = -1, tries; + + if (!card->fw_dump_enh) + return; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + + mwifiex_pm_wakeup_card(adapter); + sdio_claim_host(card->func); + + mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); + + stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg_start = card->reg->fw_dump_start; + reg_end = card->reg->fw_dump_end; + for (reg = reg_start; reg <= reg_end; reg++) { + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + start_flag = sdio_readb(card->func, reg, &ret); + if (ret) { + mwifiex_dbg(adapter, ERROR, + "SDIO read err\n"); + goto done; + } + if (start_flag == 0) + break; + if (tries == MAX_POLL_TRIES) { + mwifiex_dbg(adapter, ERROR, + "FW not ready to dump\n"); + ret = -1; + goto done; + } + } + usleep_range(100, 200); + } + + entry->mem_ptr = vmalloc(0xf0000 + 1); + if (!entry->mem_ptr) { + ret = -1; + goto done; + } + dbg_ptr = entry->mem_ptr; + entry->mem_size = 0xf0000; + end_ptr = dbg_ptr + entry->mem_size; + + done_flag = entry->done_flag; + mwifiex_dbg(adapter, DUMP, + "Start %s output, please wait...\n", entry->mem_name); + + while (true) { + stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + for (reg = reg_start; reg <= reg_end; reg++) { + *dbg_ptr = sdio_readb(card->func, reg, &ret); + if (ret) { + mwifiex_dbg(adapter, ERROR, + "SDIO read err\n"); + goto done; + } + dbg_ptr++; + if (dbg_ptr >= end_ptr) { + u8 *tmp_ptr; + + tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1); + if (!tmp_ptr) + goto done; + + memcpy(tmp_ptr, entry->mem_ptr, + entry->mem_size); + vfree(entry->mem_ptr); + entry->mem_ptr = tmp_ptr; + tmp_ptr = NULL; + dbg_ptr = entry->mem_ptr + entry->mem_size; + entry->mem_size += 0x4000; + end_ptr = entry->mem_ptr + entry->mem_size; + } + } + if (stat == RDWR_STATUS_DONE) { + entry->mem_size = dbg_ptr - entry->mem_ptr; + mwifiex_dbg(adapter, DUMP, "dump %s done size=0x%x\n", + entry->mem_name, entry->mem_size); + ret = 0; + break; + } + } + mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); + +done: + if (ret) { + mwifiex_dbg(adapter, ERROR, "firmware dump failed\n"); + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + sdio_release_host(card->func); +} + static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter) { + struct sdio_mmc_card *card = adapter->card; + mwifiex_drv_info_dump(adapter); - mwifiex_sdio_fw_dump(adapter); + if (card->fw_dump_enh) + mwifiex_sdio_generic_fw_dump(adapter); + else + mwifiex_sdio_fw_dump(adapter); mwifiex_upload_device_dump(adapter); } diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index cd149196042a..b9fbc5cf6262 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -223,6 +223,7 @@ struct mwifiex_sdio_card_reg { u8 cmd_cfg_1; u8 cmd_cfg_2; u8 cmd_cfg_3; + u8 fw_dump_host_ready; u8 fw_dump_ctrl; u8 fw_dump_start; u8 fw_dump_end; @@ -258,6 +259,7 @@ struct sdio_mmc_card { bool supports_sdio_new_mode; bool has_control_mask; bool can_dump_fw; + bool fw_dump_enh; bool can_auto_tdls; bool can_ext_scan; @@ -279,6 +281,7 @@ struct mwifiex_sdio_device { bool supports_sdio_new_mode; bool has_control_mask; bool can_dump_fw; + bool fw_dump_enh; bool can_auto_tdls; bool can_ext_scan; }; @@ -354,6 +357,7 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { .cmd_cfg_1 = 0xb9, .cmd_cfg_2 = 0xba, .cmd_cfg_3 = 0xbb, + .fw_dump_host_ready = 0xee, .fw_dump_ctrl = 0xe2, .fw_dump_start = 0xe3, .fw_dump_end = 0xea, @@ -404,6 +408,10 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = { .cmd_cfg_1 = 0xc5, .cmd_cfg_2 = 0xc6, .cmd_cfg_3 = 0xc7, + .fw_dump_host_ready = 0xcc, + .fw_dump_ctrl = 0xf0, + .fw_dump_start = 0xf1, + .fw_dump_end = 0xf8, .func1_dump_reg_start = 0x10, .func1_dump_reg_end = 0x17, .func1_scratch_reg = 0xe8, @@ -532,7 +540,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, .supports_sdio_new_mode = true, .has_control_mask = false, - .can_dump_fw = false, + .can_dump_fw = true, + .fw_dump_enh = true, .can_auto_tdls = false, .can_ext_scan = true, }; -- cgit v1.2.3-70-g09d2 From 2375fa2b36feaf34c7728ee999dc4d8f4d92031d Mon Sep 17 00:00:00 2001 From: chunfan chen Date: Wed, 5 Aug 2015 06:09:42 -0700 Subject: mwifiex: fix unable to connect hidden SSID AP on DFS channel We will check if any hidden SSID found in passive scan channels and do specific SSID active scan for those channels. Signed-off-by: chunfan chen Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 1 + drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/scan.c | 143 +++++++++++++++++++++++++++++++++--- 4 files changed, 136 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 9a8c1832d068..3ec2ac82e394 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -685,6 +685,7 @@ struct mwifiex_fw_chan_stats { enum mwifiex_chan_scan_mode_bitmasks { MWIFIEX_PASSIVE_SCAN = BIT(0), MWIFIEX_DISABLE_CHAN_FILT = BIT(1), + MWIFIEX_HIDDEN_SSID_REPORT = BIT(4), }; struct mwifiex_chan_scan_param_set { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 7a970c28c557..5d3ae63baea4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -301,7 +301,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM; adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM; adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM; - + adapter->active_scan_triggered = false; setup_timer(&adapter->wakeup_timer, wakeup_timer_fn, (unsigned long)adapter); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index face7478937f..6b9512140e7a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -666,6 +666,7 @@ struct mwifiex_private { struct mwifiex_11h_intf_state state_11h; struct mwifiex_ds_mem_rw mem_rw; struct sk_buff_head bypass_txq; + struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX]; }; @@ -986,6 +987,7 @@ struct mwifiex_adapter { u8 coex_tx_win_size; u8 coex_rx_win_size; bool drcs_enabled; + u8 active_scan_triggered; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index ef8da8ebcbab..5847863a2d6b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -527,7 +527,8 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].chan_scan_mode_bitmap - |= MWIFIEX_PASSIVE_SCAN; + |= (MWIFIEX_PASSIVE_SCAN | + MWIFIEX_HIDDEN_SSID_REPORT); else scan_chan_list[chan_idx].chan_scan_mode_bitmap &= ~MWIFIEX_PASSIVE_SCAN; @@ -1049,7 +1050,8 @@ mwifiex_config_scan(struct mwifiex_private *priv, if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) (scan_chan_list + chan_idx)->chan_scan_mode_bitmap - |= MWIFIEX_PASSIVE_SCAN; + |= (MWIFIEX_PASSIVE_SCAN | + MWIFIEX_HIDDEN_SSID_REPORT); else (scan_chan_list + chan_idx)->chan_scan_mode_bitmap @@ -1600,6 +1602,62 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, return ret; } +/* This function checks if SSID string contains all zeroes or length is zero */ +static bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid) +{ + int idx; + + for (idx = 0; idx < ssid->ssid_len; idx++) { + if (ssid->ssid[idx]) + return false; + } + + return true; +} + +/* This function checks if any hidden SSID found in passive scan channels + * and save those channels for specific SSID active scan + */ +static int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv, + struct cfg80211_bss *bss) +{ + struct mwifiex_bssdescriptor *bss_desc; + int ret; + int chid; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); + if (!bss_desc) + return -ENOMEM; + + ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); + if (ret) + goto done; + + if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) { + mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n"); + for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) { + if (priv->hidden_chan[chid].chan_number == + bss->channel->hw_value) + break; + + if (!priv->hidden_chan[chid].chan_number) { + priv->hidden_chan[chid].chan_number = + bss->channel->hw_value; + priv->hidden_chan[chid].radio_type = + bss->channel->band; + priv->hidden_chan[chid].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + break; + } + } + } + +done: + kfree(bss_desc); + return 0; +} + static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv, struct cfg80211_bss *bss) { @@ -1789,6 +1847,14 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, .mac_address, ETH_ALEN)) mwifiex_update_curr_bss_params(priv, bss); cfg80211_put_bss(priv->wdev.wiphy, bss); + + if ((chan->flags & IEEE80211_CHAN_RADAR) || + (chan->flags & IEEE80211_CHAN_NO_IR)) { + mwifiex_dbg(adapter, INFO, + "radar or passive channel %d\n", + channel); + mwifiex_save_hidden_ssid_channels(priv, bss); + } } } else { mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n"); @@ -1812,6 +1878,57 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv) } } +/* This function checks if any hidden SSID found in passive scan channels + * and do specific SSID active scan for those channels + */ +static int +mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv) +{ + int ret; + struct mwifiex_adapter *adapter = priv->adapter; + u8 id = 0; + struct mwifiex_user_scan_cfg *user_scan_cfg; + + if (adapter->active_scan_triggered) { + adapter->active_scan_triggered = false; + return 0; + } + + if (!priv->hidden_chan[0].chan_number) { + mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n"); + return 0; + } + user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); + + if (!user_scan_cfg) + return -ENOMEM; + + memset(user_scan_cfg, 0, sizeof(*user_scan_cfg)); + + for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) { + if (!priv->hidden_chan[id].chan_number) + break; + memcpy(&user_scan_cfg->chan_list[id], + &priv->hidden_chan[id], + sizeof(struct mwifiex_user_scan_chan)); + } + + adapter->active_scan_triggered = true; + user_scan_cfg->num_ssids = priv->scan_request->n_ssids; + user_scan_cfg->ssid_list = priv->scan_request->ssids; + + ret = mwifiex_scan_networks(priv, user_scan_cfg); + kfree(user_scan_cfg); + + memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan)); + + if (ret) { + dev_err(priv->adapter->dev, "scan failed: %d\n", ret); + return ret; + } + + return 0; +} static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; @@ -1825,6 +1942,8 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + mwifiex_active_scan_req_for_passive_chan(priv); + if (!adapter->ext_scan) mwifiex_complete_scan(priv); @@ -1851,15 +1970,17 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - if (priv->scan_request) { - mwifiex_dbg(adapter, INFO, - "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } else { - priv->scan_aborting = false; - mwifiex_dbg(adapter, INFO, - "info: scan already aborted\n"); + if (!adapter->active_scan_triggered) { + if (priv->scan_request) { + mwifiex_dbg(adapter, INFO, + "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + mwifiex_dbg(adapter, INFO, + "info: scan already aborted\n"); + } } } else { /* Get scan command from scan_pending_q and put to -- cgit v1.2.3-70-g09d2 From cb9d61e5304e2880180e4ccf685a298c868094e0 Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 6 Aug 2015 00:39:16 -0700 Subject: mwifiex: claim sdio bus while downloading the firmware Our 8887 A2 chip can have separate firmware images for bluetooth and WLAN. We observed an issue during parallel downloading of these images by btmrvl and mwifiex drivers. This patch claims sdio bus before starting of the firmware download in mwifiex and releases it after completion to fix the problem. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 7cef27e9d33f..5d05c6fe6429 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -920,6 +920,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, if (!fwbuf) return -ENOMEM; + sdio_claim_host(card->func); + /* Perform firmware data transfer */ do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY @@ -1024,6 +1026,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); + sdio_release_host(card->func); + mwifiex_dbg(adapter, MSG, "info: FW download over, size %d bytes\n", offset); -- cgit v1.2.3-70-g09d2 From 94fdc2e627d1b479a117cd8b9ece5f4613a5c956 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 6 Aug 2015 12:46:31 -0400 Subject: orinoco: Do not call wiphy_unregister() from free_orinocodev() alloc_orinocodev() would allocate the wiphy entry, but it would only get registered much later in orinoco_init(). If something failed in the init process inbetween the call to alloc_orinocodev() and the completion of orinoco_init(), the drivers would end up calling wiphy_unregister() with a NULL pointer causing beautiful OOPS fireworks. Explicitly call wiphy_unregister() instead in the right places. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/orinoco/main.c | 2 -- drivers/net/wireless/orinoco/orinoco_cs.c | 1 + drivers/net/wireless/orinoco/orinoco_nortel.c | 5 ++++- drivers/net/wireless/orinoco/orinoco_pci.c | 5 ++++- drivers/net/wireless/orinoco/orinoco_plx.c | 5 ++++- drivers/net/wireless/orinoco/orinoco_usb.c | 2 ++ 6 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index c410180479e6..7b5c554323c7 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2321,8 +2321,6 @@ void free_orinocodev(struct orinoco_private *priv) struct orinoco_rx_data *rx_data, *temp; struct orinoco_scan_data *sd, *sdtemp; - wiphy_unregister(wiphy); - /* If the tasklet is scheduled when we call tasklet_kill it * will run one final time. However the tasklet will only * drain priv->rx_list if the hw is still available. */ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index c0a27377d9e2..a956f965a1e5 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -118,6 +118,7 @@ static void orinoco_cs_detach(struct pcmcia_device *link) orinoco_cs_release(link); + wiphy_unregister(priv_to_wiphy(priv)); free_orinocodev(priv); } /* orinoco_cs_detach */ diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 1b543e30eff7..048693b6c6c2 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -223,13 +223,15 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, err = orinoco_if_add(priv, 0, 0, NULL); if (err) { printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; + goto fail_wiphy; } pci_set_drvdata(pdev, priv); return 0; + fail_wiphy: + wiphy_unregister(priv_to_wiphy(priv)); fail: free_irq(pdev->irq, priv); @@ -263,6 +265,7 @@ static void orinoco_nortel_remove_one(struct pci_dev *pdev) iowrite16(0, card->bridge_io + 10); orinoco_if_del(priv); + wiphy_unregister(priv_to_wiphy(priv)); free_irq(pdev->irq, priv); free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 74219d59d7e1..4938a2208a37 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -173,13 +173,15 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, err = orinoco_if_add(priv, 0, 0, NULL); if (err) { printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; + goto fail_wiphy; } pci_set_drvdata(pdev, priv); return 0; + fail_wiphy: + wiphy_unregister(priv_to_wiphy(priv)); fail: free_irq(pdev->irq, priv); @@ -203,6 +205,7 @@ static void orinoco_pci_remove_one(struct pci_dev *pdev) struct orinoco_private *priv = pci_get_drvdata(pdev); orinoco_if_del(priv); + wiphy_unregister(priv_to_wiphy(priv)); free_irq(pdev->irq, priv); free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 8b045236b6e0..221352027779 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -262,13 +262,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, err = orinoco_if_add(priv, 0, 0, NULL); if (err) { printk(KERN_ERR PFX "orinoco_if_add() failed\n"); - goto fail; + goto fail_wiphy; } pci_set_drvdata(pdev, priv); return 0; + fail_wiphy: + wiphy_unregister(priv_to_wiphy(priv)); fail: free_irq(pdev->irq, priv); @@ -299,6 +301,7 @@ static void orinoco_plx_remove_one(struct pci_dev *pdev) struct orinoco_pci_card *card = priv->card; orinoco_if_del(priv); + wiphy_unregister(priv_to_wiphy(priv)); free_irq(pdev->irq, priv); free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 91f05442de28..26a57d773d30 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -1502,6 +1502,7 @@ static inline void ezusb_delete(struct ezusb_priv *upriv) if (upriv->dev) { struct orinoco_private *priv = ndev_priv(upriv->dev); orinoco_if_del(priv); + wiphy_unregister(priv_to_wiphy(upriv)); free_orinocodev(priv); } } @@ -1695,6 +1696,7 @@ static int ezusb_probe(struct usb_interface *interface, if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) { upriv->dev = NULL; err("%s: orinoco_if_add() failed", __func__); + wiphy_unregister(priv_to_wiphy(priv)); goto error; } upriv->dev = priv->ndev; -- cgit v1.2.3-70-g09d2 From 2459cd876e2828dc63c19ea5dadf8a94a8f11244 Mon Sep 17 00:00:00 2001 From: Su Kang Yin Date: Fri, 7 Aug 2015 16:54:10 +0800 Subject: mac80211_hwsim: unregister genetlink family properly During hwsim_init_netlink(), we should call genl_unregister_family() if failed on netlink_register_notifier() since the genetlink is already registered. Signed-off-by: Su Kang Yin Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 08022ded6307..dbb46ece6f52 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3121,8 +3121,10 @@ static int hwsim_init_netlink(void) goto failure; rc = netlink_register_notifier(&hwsim_netlink_notifier); - if (rc) + if (rc) { + genl_unregister_family(&hwsim_genl_family); goto failure; + } return 0; -- cgit v1.2.3-70-g09d2 From 80de4321a65c680dd7ce0138d88dc96e0d2a18fb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 16:53:27 +0300 Subject: iwlwifi: make sure d3_suspend/resume ops exist We added calls to d3_suspend/resume trans ops during the suspend/resume flow. However, the wrapper code didn't verify the trans ops were actually defined, resulting in panic when they were not (such as in the case of sdio trans) Fixes: 6dfb36c89dc2 ("iwlwifi: call d3_suspend/resume in d0i3 case as well") Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 9d8b5cb06343..c829c505e141 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -810,7 +810,8 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) { might_sleep(); - trans->ops->d3_suspend(trans, test); + if (trans->ops->d3_suspend) + trans->ops->d3_suspend(trans, test); } static inline int iwl_trans_d3_resume(struct iwl_trans *trans, @@ -818,6 +819,9 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, bool test) { might_sleep(); + if (!trans->ops->d3_resume) + return 0; + return trans->ops->d3_resume(trans, status, test); } -- cgit v1.2.3-70-g09d2 From 9437e9941025bc83d3dd43f2927019149029f667 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Mon, 22 Jun 2015 13:20:00 +0300 Subject: iwlwifi: mvm: simplify calculating scan dwells and other timing values Remove timing values from iwl_mvm_scan_params and use defines and arrays of values instead. While at that fix few values and corner cases and align all OSs to ChromeOS values. Signed-off-by: David Spinadel Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 169 +++++++++++++++++--------------- 1 file changed, 88 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e0c0dd7ef2b3..308a60e7f032 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -72,10 +72,60 @@ #define IWL_DENSE_EBS_SCAN_RATIO 5 #define IWL_SPARSE_EBS_SCAN_RATIO 1 -struct iwl_mvm_scan_params { - u32 max_out_time; +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, + IWL_MVM_TRAFFIC_HIGH, +}; + +struct iwl_mvm_scan_timing_params { + u32 dwell_active; + u32 dwell_passive; + u32 dwell_fragmented; u32 suspend_time; - bool passive_fragmented; + u32 max_out_time; +}; + +static struct iwl_mvm_scan_timing_params scan_timing[] = { + [IWL_SCAN_TYPE_UNASSOC] = { + .dwell_active = 10, + .dwell_passive = 110, + .dwell_fragmented = 44, + .suspend_time = 0, + .max_out_time = 0, + }, + [IWL_SCAN_TYPE_WILD] = { + .dwell_active = 10, + .dwell_passive = 110, + .dwell_fragmented = 44, + .suspend_time = 30, + .max_out_time = 120, + }, + [IWL_SCAN_TYPE_MILD] = { + .dwell_active = 10, + .dwell_passive = 110, + .dwell_fragmented = 44, + .suspend_time = 120, + .max_out_time = 120, + }, + [IWL_SCAN_TYPE_FRAGMENTED] = { + .dwell_active = 10, + .dwell_passive = 110, + .dwell_fragmented = 44, + .suspend_time = 95, + .max_out_time = 44, + }, +}; + +struct iwl_mvm_scan_params { + enum iwl_mvm_scan_type type; u32 n_channels; u16 delay; int n_ssids; @@ -90,9 +140,6 @@ struct iwl_mvm_scan_params { int n_match_sets; struct iwl_scan_probe_req preq; struct cfg80211_match_set *match_sets; - u16 passive_dwell; - u16 active_dwell; - u16 fragmented_dwell; struct { u8 iterations; u8 full_scan_mul; /* not used for UMAC */ @@ -156,76 +203,39 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, *global_cnt += 1; } -static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct iwl_mvm_scan_params *params) +static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) +{ + return IWL_MVM_TRAFFIC_LOW; +} + +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) { int global_cnt = 0; - u8 frag_passive_dwell = 0; + enum iwl_mvm_traffic_load load; + bool low_latency; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_scan_condition_iterator, &global_cnt); if (!global_cnt) - goto not_bound; - - params->suspend_time = 30; - params->max_out_time = 120; - - if (iwl_mvm_low_latency(mvm)) { - if (fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { - - params->suspend_time = 105; - /* - * If there is more than one active interface make - * passive scan more fragmented. - */ - frag_passive_dwell = 40; - params->max_out_time = frag_passive_dwell; - } else { - params->suspend_time = 120; - params->max_out_time = 120; - } - } - - if (frag_passive_dwell && - fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { - /* - * P2P device scan should not be fragmented to avoid negative - * impact on P2P device discovery. Configure max_out_time to be - * equal to dwell time on passive channel. - */ - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - params->max_out_time = 120; - } else { - params->passive_fragmented = true; - } - } - - if ((params->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - (params->max_out_time > 200)) - params->max_out_time = 200; - -not_bound: + return IWL_SCAN_TYPE_UNASSOC; - if (params->passive_fragmented) - params->fragmented_dwell = frag_passive_dwell; + load = iwl_mvm_get_traffic_load(mvm); + low_latency = iwl_mvm_low_latency(mvm); - /* - * use only basic dwell time in scan command, regardless of the band or - * the number of the probes. FW will calculate the actual dwell time. - */ - params->passive_dwell = 110; - params->active_dwell = 10; + if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && + vif->type != NL80211_IFTYPE_P2P_DEVICE && + fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) + return IWL_SCAN_TYPE_FRAGMENTED; + if (load >= IWL_MVM_TRAFFIC_MEDIUM || low_latency) + return IWL_SCAN_TYPE_MILD; - IWL_DEBUG_SCAN(mvm, - "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n", - params->max_out_time, params->suspend_time, - params->passive_fragmented); + return IWL_SCAN_TYPE_WILD; } static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) @@ -699,12 +709,11 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_lmac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->active_dwell; - cmd->passive_dwell = params->passive_dwell; - if (params->passive_fragmented) - cmd->fragmented_dwell = params->fragmented_dwell; - cmd->max_out_time = cpu_to_le32(params->max_out_time); - cmd->suspend_time = cpu_to_le32(params->suspend_time); + 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->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); } @@ -755,7 +764,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; - if (params->passive_fragmented) + if (params->type == IWL_SCAN_TYPE_FRAGMENTED) flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED; if (iwl_mvm_rrm_scan_needed(mvm)) @@ -958,12 +967,11 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_umac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->active_dwell; - cmd->passive_dwell = params->passive_dwell; - if (params->passive_fragmented) - cmd->fragmented_dwell = params->fragmented_dwell; - cmd->max_out_time = cpu_to_le32(params->max_out_time); - cmd->suspend_time = cpu_to_le32(params->suspend_time); + 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->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_priority = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); @@ -1003,7 +1011,7 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; - if (params->passive_fragmented) + if (params->type == IWL_SCAN_TYPE_FRAGMENTED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; if (iwl_mvm_rrm_scan_needed(mvm)) @@ -1177,7 +1185,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, params.schedule[1].iterations = 0; params.schedule[1].full_scan_mul = 0; - iwl_mvm_scan_calc_dwell(mvm, vif, ¶ms); + params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); @@ -1259,6 +1267,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.schedule[0].full_scan_mul = 1; params.schedule[1].iterations = 0xff; params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; + params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); if (req->interval > U16_MAX) { IWL_DEBUG_SCAN(mvm, @@ -1281,8 +1290,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.delay = req->delay; } - iwl_mvm_scan_calc_dwell(mvm, vif, ¶ms); - ret = iwl_mvm_config_sched_scan_profiles(mvm, req); if (ret) return ret; -- cgit v1.2.3-70-g09d2 From 3b44a0ef12b9676914b25dcf3bf7f0cdd07de5b3 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Sun, 21 Jun 2015 11:57:36 +0300 Subject: iwlwifi: mvm: remove partial and full scan lists from lmac sched scan Lmac sched scan supports partial scans, so we can set some channels to be scanned on every scan iteration and others to be scanned only on some iterations. Currently we set all channels to be scanned every iteration, but still have some configuration of which iterations should be partial and which should be full. Remove all partial/full scan configuration to reduce confusions. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 308a60e7f032..f456aad45daf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -140,10 +140,7 @@ struct iwl_mvm_scan_params { int n_match_sets; struct iwl_scan_probe_req preq; struct cfg80211_match_set *match_sets; - struct { - u8 iterations; - u8 full_scan_mul; /* not used for UMAC */ - } schedule[2]; + u8 iterations[2]; }; static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) @@ -750,7 +747,7 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params) { - return params->schedule[0].iterations + params->schedule[1].iterations; + return params->iterations[0] + params->iterations[1]; } static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, @@ -817,11 +814,11 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ssid_bitmap <<= 1; cmd->schedule[0].delay = cpu_to_le16(params->interval); - cmd->schedule[0].iterations = params->schedule[0].iterations; - cmd->schedule[0].full_scan_mul = params->schedule[0].full_scan_mul; + cmd->schedule[0].iterations = params->iterations[0]; + cmd->schedule[0].full_scan_mul = 1; cmd->schedule[1].delay = cpu_to_le16(params->interval); - cmd->schedule[1].iterations = params->schedule[1].iterations; - cmd->schedule[1].full_scan_mul = params->schedule[1].iterations; + cmd->schedule[1].iterations = params->iterations[1]; + cmd->schedule[1].full_scan_mul = 1; if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) { cmd->channel_opt[0].flags = @@ -1180,10 +1177,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, params.n_match_sets = 0; params.match_sets = NULL; - params.schedule[0].iterations = 1; - params.schedule[0].full_scan_mul = 0; - params.schedule[1].iterations = 0; - params.schedule[1].full_scan_mul = 0; + params.iterations[0] = 1; + params.iterations[1] = 0; params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); @@ -1263,10 +1258,9 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.n_match_sets = req->n_match_sets; params.match_sets = req->match_sets; - params.schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS; - params.schedule[0].full_scan_mul = 1; - params.schedule[1].iterations = 0xff; - params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; + params.iterations[0] = 0; + params.iterations[1] = 0xff; + params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms); if (req->interval > U16_MAX) { -- cgit v1.2.3-70-g09d2 From 1a84e7716086be3b90e3b735725d0a14da28a69c Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Wed, 22 Jul 2015 13:54:31 +0300 Subject: iwlwifi: mvm: add debug info to schedule scan complete message. Add more information to schedule scan complete message. Signed-off-by: Ayala Beker Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index f456aad45daf..15055462cd11 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -349,9 +349,13 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR); - IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", + IWL_DEBUG_SCAN(mvm, + "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + iwl_mvm_ebs_status_str(scan_notif->ebs_status), + scan_notif->last_schedule_line, + scan_notif->last_schedule_iteration, + __le32_to_cpu(scan_notif->time_after_last_iter)); mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED; } else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) { @@ -363,9 +367,13 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR); - IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s (FW)\n", + IWL_DEBUG_SCAN(mvm, + "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + iwl_mvm_ebs_status_str(scan_notif->ebs_status), + scan_notif->last_schedule_line, + scan_notif->last_schedule_iteration, + __le32_to_cpu(scan_notif->time_after_last_iter)); mvm->scan_status &= ~IWL_MVM_SCAN_SCHED; ieee80211_sched_scan_stopped(mvm->hw); @@ -1337,13 +1345,14 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, } mvm->scan_status &= ~mvm->scan_uid_status[uid]; - IWL_DEBUG_SCAN(mvm, - "Scan completed, uid %u type %u, status %s, EBS status %s\n", + "Scan completed, uid %u type %u, status %s, EBS status %s, Last line %d, Last iteration %d, Time from last iteration %d\n", uid, mvm->scan_uid_status[uid], notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted", - iwl_mvm_ebs_status_str(notif->ebs_status)); + iwl_mvm_ebs_status_str(notif->ebs_status), + notif->last_schedule, notif->last_iter, + __le32_to_cpu(notif->time_from_last_iter)); if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS && notif->ebs_status != IWL_SCAN_EBS_INACTIVE) -- cgit v1.2.3-70-g09d2 From 1be5d8cc165d56b7267f5adc96d496a33c33219e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jun 2015 16:51:24 +0200 Subject: iwlwifi: pass NAPI struct from transport layer The mac80211 patch to pass the NAPI struct only changed iwlwifi to store the NAPI struct, but we can do better: pass it directly from the lower transport layer to the opmode during RX, and then on to mac80211 from there. When we add multiple RX queues, we can then pass the appropriate NAPI struct properly. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/iwlwifi/dvm/main.c | 13 ------------- drivers/net/wireless/iwlwifi/dvm/rx.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 26 ++++---------------------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/ops.c | 16 ++-------------- drivers/net/wireless/iwlwifi/mvm/rx.c | 8 +++++--- drivers/net/wireless/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 7 +++---- 9 files changed, 20 insertions(+), 61 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 101ef3109292..edc3dd42f8f8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -122,7 +122,7 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) void iwl_down(struct iwl_priv *priv); void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); -void iwl_rx_dispatch(struct iwl_op_mode *op_mode, +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb); bool iwl_check_for_ct_kill(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 644819563cf0..e7616f0ee6e8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2029,18 +2029,6 @@ static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) return false; } -static void iwl_napi_add(struct iwl_op_mode *op_mode, - struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - - netif_napi_add(napi_dev, napi, poll, weight); - priv->napi = napi; -} - static const struct iwl_op_mode_ops iwl_dvm_ops = { .start = iwl_op_mode_dvm_start, .stop = iwl_op_mode_dvm_stop, @@ -2053,7 +2041,6 @@ static const struct iwl_op_mode_ops iwl_dvm_ops = { .cmd_queue_full = iwl_cmd_queue_full, .nic_config = iwl_nic_config, .wimax_active = iwl_wimax_active, - .napi_add = iwl_napi_add, }; /***************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 15176981dc8f..4785203ae203 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -1073,7 +1073,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) iwlagn_bt_rx_handler_setup(priv); } -void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb) +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 71b450adbda0..b47fe9d6b97a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -116,10 +116,6 @@ struct iwl_cfg; * May sleep * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the * HCMD this Rx responds to. Can't sleep. - * @napi_add: NAPI initialization. The transport is fully responsible for NAPI, - * but the higher layers need to know about it (in particular mac80211 to - * to able to call the right NAPI RX functions); this function is needed - * to eventually call netif_napi_add() with higher layer involvement. * @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. @@ -148,12 +144,8 @@ struct iwl_op_mode_ops { const struct iwl_fw *fw, struct dentry *dbgfs_dir); void (*stop)(struct iwl_op_mode *op_mode); - void (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb); - void (*napi_add)(struct iwl_op_mode *op_mode, - struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight); + void (*rx)(struct iwl_op_mode *op_mode, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb); 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); @@ -188,9 +180,10 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) } static inline void iwl_op_mode_rx(struct iwl_op_mode *op_mode, + struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb) { - return op_mode->ops->rx(op_mode, rxb); + return op_mode->ops->rx(op_mode, napi, rxb); } static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, @@ -258,15 +251,4 @@ static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode) return op_mode->ops->exit_d0i3(op_mode); } -static inline void iwl_op_mode_napi_add(struct iwl_op_mode *op_mode, - struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - if (!op_mode->ops->napi_add) - return; - op_mode->ops->napi_add(op_mode, napi, napi_dev, poll, weight); -} - #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 58544f20ddad..b95a07ec9e36 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -563,7 +563,6 @@ struct iwl_mvm { const struct iwl_cfg *cfg; struct iwl_phy_db *phy_db; struct ieee80211_hw *hw; - struct napi_struct *napi; /* for protecting access to iwl_mvm */ struct mutex mutex; @@ -1085,7 +1084,8 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, * Convention: iwl_mvm_rx_ */ 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 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_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, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e7f6c015f7a3..c15c994b6a27 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -717,6 +717,7 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, } static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, + struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -724,7 +725,7 @@ static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, u8 i; if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { - iwl_mvm_rx_rx_mpdu(mvm, rxb); + iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); return; } @@ -1321,18 +1322,6 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) return _iwl_mvm_exit_d0i3(mvm); } -static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, - struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - - netif_napi_add(napi_dev, napi, poll, weight); - mvm->napi = napi; -} - static const struct iwl_op_mode_ops iwl_mvm_ops = { .start = iwl_op_mode_mvm_start, .stop = iwl_op_mode_mvm_stop, @@ -1346,5 +1335,4 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = { .nic_config = iwl_mvm_nic_config, .enter_d0i3 = iwl_mvm_enter_d0i3, .exit_d0i3 = iwl_mvm_exit_d0i3, - .napi_add = iwl_mvm_napi_add, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index a0c27cc19759..c37c10a423ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -94,6 +94,7 @@ void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) * Adds the rxb to a new skb and give it to mac80211 */ 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, @@ -127,7 +128,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, fraglen, rxb->truesize); } - ieee80211_rx_napi(mvm->hw, skb, mvm->napi); + ieee80211_rx_napi(mvm->hw, skb, napi); } /* @@ -253,7 +254,8 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, * * Handles the actual data of the Rx packet from the fw */ -void iwl_mvm_rx_rx_mpdu(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) { struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; @@ -442,7 +444,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) iwl_mvm_update_frame_stats(mvm, rate_n_flags, rx_status->flag & RX_FLAG_AMPDU_DETAILS); #endif - iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status, crypt_len, rxb); } diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 5643ace7b15a..e06591f625c4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -898,7 +898,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, index = SEQ_TO_INDEX(sequence); cmd_index = get_cmd_index(&txq->q, index); - iwl_op_mode_rx(trans->op_mode, &rxcb); + iwl_op_mode_rx(trans->op_mode, &trans_pcie->napi, &rxcb); if (reclaim) { kzfree(txq->entries[cmd_index].free_buf); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index ceea2d5702d3..6ba7d300b08f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1460,11 +1460,10 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, * As this function may be called again in some corner cases don't * do anything if NAPI was already initialized. */ - if (!trans_pcie->napi.poll && trans->op_mode->ops->napi_add) { + if (!trans_pcie->napi.poll) { init_dummy_netdev(&trans_pcie->napi_dev); - iwl_op_mode_napi_add(trans->op_mode, &trans_pcie->napi, - &trans_pcie->napi_dev, - iwl_pcie_dummy_napi_poll, 64); + netif_napi_add(&trans_pcie->napi_dev, &trans_pcie->napi, + iwl_pcie_dummy_napi_poll, 64); } } -- cgit v1.2.3-70-g09d2 From 3cd6e2f768851a760c072f0f84b9688b1755d24d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 16 Jul 2015 15:42:14 +0300 Subject: iwlwifi: convert hex_dump_to_buffer() to %*ph There is no need to use hex_dump_to_buffer() in the cases like this: hexdump_to_buffer(buf, len, 16, 1, outbuf, outlen, false); /* len <= 16 */ sprintf("%s\n", outbuf); since it maybe easily converted to simple: sprintf("%*ph\n", len, buf); Note: it seems in one case the output is groupped by 2 bytes and looks like a typo. Thus, patch changes that to plain byte stream. Signed-off-by: Andy Shevchenko Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 8 ++------ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 7 +------ 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 0ffb6ff1a255..b15e44f8d1bd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -310,12 +310,8 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, pos += scnprintf(buf + pos, buf_size - pos, "NVM version: 0x%x\n", nvm_ver); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { - pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, - buf_size - pos, 0); - pos += strlen(buf + pos); - if (buf_size - pos > 0) - buf[pos++] = '\n'; + pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", + ofs, ptr + ofs); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 17d7a05006fa..ca4a1f8f82a5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1200,12 +1200,7 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, if (ptr) { for (ofs = 0; ofs < len; ofs += 16) { pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, - bufsz - pos, false); - pos += strlen(buf + pos); - if (bufsz - pos > 0) - buf[pos++] = '\n'; + "0x%.4x %16ph\n", ofs, ptr + ofs); } } else { pos += scnprintf(buf + pos, bufsz - pos, -- cgit v1.2.3-70-g09d2 From 5b9d47cdde1aacaac9b9dcefe44ee3493dc5fd87 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Aug 2015 00:45:03 +0300 Subject: iwlwifi: mvm: fix a range check in debugfs code The &mvm->tof_data.range_req.ap[] array has IWL_MVM_TOF_MAX_APS elements so the check should be >= instead of >. Also the test can underflow so I have changed "i" to unsigned. Fixes: ce7929186a39 ('wlwifi: mvm: add basic Time of Flight (802.11mc FTM) support') Signed-off-by: Dan Carpenter Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index ddb1c844827b..383a3162046c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -911,9 +911,9 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, int size = sizeof(struct iwl_tof_range_req_ap_entry); u16 burst_period; u8 *mac = ap.bssid; - int i; + unsigned int i; - if (sscanf(data, "%d %hhd %hhx %hhx" + if (sscanf(data, "%u %hhd %hhx %hhx" "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" "%hhx %hhx %hx" "%hhx %hhx %x" @@ -929,7 +929,7 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, ret = -EINVAL; goto out; } - if (i > IWL_MVM_TOF_MAX_APS) { + if (i >= IWL_MVM_TOF_MAX_APS) { IWL_ERR(mvm, "Invalid AP index %d\n", i); ret = -EINVAL; goto out; -- cgit v1.2.3-70-g09d2 From 7c4f084372ed35aef3e8c6e6b1f1b1dc3235987a Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 30 Apr 2015 18:31:45 +0300 Subject: iwlwifi: mvm: support TDLS wider-bandwidth When TDLS support is declared by the FW, set the bit indicating wider-BW support as well. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 08dd67435189..537a15719d45 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -641,6 +641,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) { IWL_DEBUG_TDLS(mvm, "TDLS supported\n"); hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + ieee80211_hw_set(hw, TDLS_WIDER_BW); } if (fw_has_capa(&mvm->fw->ucode_capa, -- cgit v1.2.3-70-g09d2 From 3c22a0ed597c1ff33eddeafd04be5e6ce544262d Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 5 Aug 2015 23:07:42 +0300 Subject: iwlwifi: mvm: Enable power management on low-latency bss Currently the driver disable power management on all low-latency interfaces, while it should disable it on WiDi interfaces only. Non-P2P interfaces that runs voice and video traffic should enable power management. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index c4e08903366c..4645877882a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -337,8 +337,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); - if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - !mvmvif->pm_enabled) + if (!vif->bss_conf.ps || !mvmvif->pm_enabled || + (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); -- cgit v1.2.3-70-g09d2 From 3a73d1a6f22bf13044056543ad43b2a304ee0022 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 6 Aug 2015 14:46:54 +0200 Subject: ath10k: wake up offchannel queue properly Once HTT Tx queue got full offchannel queue was stopped and never woken up again. This broke, e.g. P2P. This could be reproduced after running a lot of traffic enough to saturate 100% of the driver Tx queue and then trying to send offchannel traffic. Fixes: 96d828d45e16 ("ath10k: rework tx queue locking") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 96f4285e93b8..ed2e8b67d95d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2999,6 +2999,8 @@ void ath10k_mac_tx_unlock(struct ath10k *ar, int reason) IEEE80211_IFACE_ITER_RESUME_ALL, ath10k_mac_tx_unlock_iter, ar); + + ieee80211_wake_queue(ar->hw, ar->hw->offchannel_tx_hw_queue); } void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason) -- cgit v1.2.3-70-g09d2 From 6d2d51ecfff13f5f6ffc476dccf4d5b2668072eb Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 7 Aug 2015 09:08:21 +0200 Subject: ath10k: wake up queue upon vif creation Vif's vdev_id is used as queue number. However due to the tx pausing design in ath10k it was possible for a new interface to be created with its tx queue stopped (via ieee80211_stop_queues). This could in turn leave the interface inoperable until ath10k_mac_tx_unlock() was called. This problem only affected multi-vif scenarios when new interfaces were created some time later after other interfaces have been running for some time and had Tx queue full at some point prior. Possible manifestation of the bug was authentication timeout for a client vif. Fixes: 96d828d45e16 ("ath10k: rework tx queue locking") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ed2e8b67d95d..3bb9ea8a6903 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4342,6 +4342,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, } } + spin_lock_bh(&ar->htt.tx_lock); + if (!ar->tx_paused) + ieee80211_wake_queue(ar->hw, arvif->vdev_id); + spin_unlock_bh(&ar->htt.tx_lock); + mutex_unlock(&ar->conf_mutex); return 0; -- cgit v1.2.3-70-g09d2 From 3d2a2e293e9578f59b182c8e5ad7b54ec4e28318 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 12 Aug 2015 16:24:04 +0530 Subject: ath10k: fix invalid survey reporting for QCA99X0 There are three WMI_CHAN_INFO events reported per channel in QCA99X0 firmware. First one is a notification at the begining of the channel dwell time with cmd_flag as CHAN_INFO_START(cmd_flag = 0), second one is a notification at the end of the dwell time with cmd_flag CHAN_INFO_PRE_COMPLETE (cmd_flag = 2) and the third is the indication with CHAN_INFO_COMPLETE (cmd_flag = 1) which is the last indication for the channel. Since there is a new state before the completion, the handler is to fixed so that the counts are deducted from the ones reported with CHAN_INFO_START rather than the ones reported with CHAN_INFO_PRE_COMPLETE. Without this fix there will be lots of 0 msecs reported as active and busy time. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++-- drivers/net/wireless/ath/ath10k/wmi.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 36b8f7148b51..a0a0b0974302 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2412,8 +2412,10 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) ar->ch_info_can_report_survey = true; } - ar->survey_last_rx_clear_count = rx_clear_count; - ar->survey_last_cycle_count = cycle_count; + if (!(cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) { + ar->survey_last_rx_clear_count = rx_clear_count; + ar->survey_last_cycle_count = cycle_count; + } exit: spin_unlock_bh(&ar->data_lock); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 232500a5d7bd..870265e7867b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5590,6 +5590,7 @@ struct wmi_peer_sta_kickout_event { } __packed; #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) +#define WMI_CHAN_INFO_FLAG_PRE_COMPLETE BIT(1) /* Beacon filter wmi command info */ #define BCN_FLT_MAX_SUPPORTED_IES 256 -- cgit v1.2.3-70-g09d2 From 9c8fb548fb242b462657151eb9c5dd6b6def5b62 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 12 Aug 2015 16:24:05 +0530 Subject: ath10k: add cycle/rx_clear counters frequency to hw_params The frequency at which cycle/rx_clear counters are running might change from one target type to another. QCA99X0 is running the counters at 150Mhz while QCA9888X and QCA6174 are running at 88Mhz. Add a new entry to hw_params to store the target specific frequency and use it in msecs conversion. This change fixes inconsistent channel active/busy time. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 5 +++++ drivers/net/wireless/ath/ath10k/core.h | 2 ++ drivers/net/wireless/ath/ath10k/hw.c | 4 ++-- drivers/net/wireless/ath/ath10k/hw.h | 3 +-- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 25510679fd2e..2efd4e4dd090 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -53,6 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .uart_pin = 7, .has_shifted_cc_wraparound = true, .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -68,6 +69,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, .fw = QCA6174_HW_2_1_FW_FILE, @@ -83,6 +85,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, .fw = QCA6174_HW_3_0_FW_FILE, @@ -98,6 +101,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, .fw = { /* uses same binaries as hw3.0 */ .dir = QCA6174_HW_3_0_FW_DIR, @@ -115,6 +119,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .uart_pin = 7, .otp_exe_param = 0x00000700, .continuous_frag_desc = true, + .channel_counters_freq_hz = 150000, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 6a387bac27b0..862f6d0fac57 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -609,6 +609,8 @@ struct ath10k { */ bool continuous_frag_desc; + u32 channel_counters_freq_hz; + struct ath10k_hw_params_fw { const char *dir; const char *fw; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index fef7ccf6e185..7b84d08a5154 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -152,6 +152,6 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, cc -= cc_prev - cc_fix; rcc -= rcc_prev; - survey->time = CCNT_TO_MSEC(cc); - survey->time_busy = CCNT_TO_MSEC(rcc); + survey->time = CCNT_TO_MSEC(ar, cc); + survey->time_busy = CCNT_TO_MSEC(ar, rcc); } diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index d9de4a738470..23afcda2de96 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -552,8 +552,7 @@ enum ath10k_hw_rate_cck { #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 -/* Cycle counters are running at 88MHz */ -#define CCNT_TO_MSEC(x) ((x) / 88000) +#define CCNT_TO_MSEC(ar, x) ((x) / ar->hw_params.channel_counters_freq_hz) /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address -- cgit v1.2.3-70-g09d2 From 8674d909fabf49140e266f124af68daa3ac93ab3 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 13 Aug 2015 14:10:46 +0200 Subject: ath10k: split ap/ibss wep key install process Apparently it's not safe to install both pairwise and groupwise keys on AP vdevs as it can cause traffic to stop working in some multi-vif (WPA+WEP) cases. Fixes: ce90b27128c2 ("ath10k: fix multiple key static wep with ibss") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3bb9ea8a6903..9bca37820848 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -247,6 +247,10 @@ 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)) + return -EINVAL; + spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find(ar, arvif->vdev_id, addr); spin_unlock_bh(&ar->data_lock); @@ -258,21 +262,34 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, if (arvif->wep_keys[i] == NULL) continue; - flags = 0; - flags |= WMI_KEY_PAIRWISE; + switch (arvif->vif->type) { + case NL80211_IFTYPE_AP: + flags = WMI_KEY_PAIRWISE; - ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, - addr, flags); - if (ret < 0) - return ret; + if (arvif->def_wep_key_idx == i) + flags |= WMI_KEY_TX_USAGE; - flags = 0; - flags |= WMI_KEY_GROUP; + ret = ath10k_install_key(arvif, arvif->wep_keys[i], + SET_KEY, addr, flags); + if (ret < 0) + return ret; + break; + case NL80211_IFTYPE_ADHOC: + ret = ath10k_install_key(arvif, arvif->wep_keys[i], + SET_KEY, addr, + WMI_KEY_PAIRWISE); + if (ret < 0) + return ret; - ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, - addr, flags); - if (ret < 0) - return ret; + ret = ath10k_install_key(arvif, arvif->wep_keys[i], + SET_KEY, addr, WMI_KEY_GROUP); + if (ret < 0) + return ret; + break; + default: + WARN_ON(1); + return -EINVAL; + } spin_lock_bh(&ar->data_lock); peer->keys[i] = arvif->wep_keys[i]; @@ -287,6 +304,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, * * FIXME: Revisit. Perhaps this can be done in a less hacky way. */ + if (arvif->vif->type != NL80211_IFTYPE_ADHOC) + return 0; + if (arvif->def_wep_key_idx == -1) return 0; -- cgit v1.2.3-70-g09d2 From f4bbb8290143b61904a082e9c6d69b6633721925 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 13 Aug 2015 15:38:31 +0300 Subject: wil6210: match wait_for_completion_timeout return type Return type of wait_for_completion_timeout is unsigned long not int. As remain is exclusively used for wait_for_completion_timeout here its type is simply changed to unsigned long. API conformance testing for completions with coccinelle spatches are being used to locate API usage inconsistencies: ./drivers/net/wireless/ath/wil6210/wmi.c:827 int return assigned to unsigned long Patch was compile tested with x86_64_defconfig + CONFIG_ATH_CARDS=m, CONFIG_WIL6210=m Patch is against 4.1-rc3 (localversion-next is -next-20150514) Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 7a257360c420..2f35d4c51f34 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -806,7 +806,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, u16 reply_id, void *reply, u8 reply_size, int to_msec) { int rc; - int remain; + unsigned long remain; mutex_lock(&wil->wmi_mutex); -- cgit v1.2.3-70-g09d2 From 991adf71a6cd993c3e6a1a0d8ea9f88b2fa51b95 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 14 Aug 2015 11:13:29 +0300 Subject: ath10k: refactor phyerr event handlers Existing phyerr event handlers directly uses phyerr header format (ie, struct wmi_phyerr and struct wmi_phyerr_event) in the code exactly on how firmware packs it. This is the problem in 10.4 fw specific phyerr event handling where it uses different phyerror header format. Before adding 10.4 specific handler, little bit of refactor is done in existing phyerr handlers. Two new abstracted structures (struct wmi_phyerr_ev_hdr_arg and struct wmi_phyerr_ev_arg) are introduced to remove dependency of using firmware specific header format in the code. So that firmware specific phyerror handlers can populate values to abstracted structures and the following code can use abstracted struct for further operation. .pull_phyerr_hdr is added newly to pull common phyerr header info like tsf, buf_len, number of phyerr packed. Existing .pull_phyerr handler is changed and called to parse every sub phyerrs in the event. Validated these refactoring on qca988x hw2.0 using fw 10.2.4 version. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/spectral.c | 9 +-- drivers/net/wireless/ath/ath10k/spectral.h | 4 +- drivers/net/wireless/ath/ath10k/wmi-ops.h | 22 ++++-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 17 ++-- drivers/net/wireless/ath/ath10k/wmi.c | 121 ++++++++++++++++++++--------- drivers/net/wireless/ath/ath10k/wmi.h | 43 +++++++--- 6 files changed, 149 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 8dcd424aa502..e4219b1bbdce 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -57,7 +57,7 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len, } int ath10k_spectral_process_fft(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf) { @@ -118,15 +118,14 @@ int ath10k_spectral_process_fft(struct ath10k *ar, fft_sample->total_gain_db = __cpu_to_be16(total_gain_db); fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db); - freq1 = __le16_to_cpu(phyerr->freq1); - freq2 = __le16_to_cpu(phyerr->freq2); + freq1 = phyerr->freq1; + freq2 = phyerr->freq2; fft_sample->freq1 = __cpu_to_be16(freq1); fft_sample->freq2 = __cpu_to_be16(freq2); chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX); - fft_sample->noise = __cpu_to_be16( - __le16_to_cpu(phyerr->nf_chains[chain_idx])); + fft_sample->noise = __cpu_to_be16(phyerr->nf_chains[chain_idx]); bins = (u8 *)fftr; bins += sizeof(*fftr); diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h index 042f5b302c75..89b0ad769d4f 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.h +++ b/drivers/net/wireless/ath/ath10k/spectral.h @@ -47,7 +47,7 @@ enum ath10k_spectral_mode { #ifdef CONFIG_ATH10K_DEBUGFS int ath10k_spectral_process_fft(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf); int ath10k_spectral_start(struct ath10k *ar); @@ -59,7 +59,7 @@ void ath10k_spectral_destroy(struct ath10k *ar); static inline int ath10k_spectral_process_fft(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 2591018c4dc5..248ffc3d6620 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -37,8 +37,10 @@ struct wmi_ops { struct wmi_peer_kick_ev_arg *arg); int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb, struct wmi_swba_ev_arg *arg); - int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb, - struct wmi_phyerr_ev_arg *arg); + int (*pull_phyerr_hdr)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_hdr_arg *arg); + int (*pull_phyerr)(struct ath10k *ar, const void *phyerr_buf, + int left_len, struct wmi_phyerr_ev_arg *arg); int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb, struct wmi_svc_rdy_ev_arg *arg); int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb, @@ -261,13 +263,23 @@ ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb, } static inline int -ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb, - struct wmi_phyerr_ev_arg *arg) +ath10k_wmi_pull_phyerr_hdr(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_hdr_arg *arg) +{ + if (!ar->wmi.ops->pull_phyerr_hdr) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_phyerr_hdr(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_phyerr(struct ath10k *ar, const void *phyerr_buf, + int left_len, struct wmi_phyerr_ev_arg *arg) { if (!ar->wmi.ops->pull_phyerr) return -EOPNOTSUPP; - return ar->wmi.ops->pull_phyerr(ar, skb, arg); + return ar->wmi.ops->pull_phyerr(ar, phyerr_buf, left_len, arg); } static inline int diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 357b5a292a89..b5849b3fd2f0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -838,9 +838,9 @@ static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar, return 0; } -static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, - struct sk_buff *skb, - struct wmi_phyerr_ev_arg *arg) +static int ath10k_wmi_tlv_op_pull_phyerr_ev_hdr(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_phyerr_hdr_arg *arg) { const void **tb; const struct wmi_tlv_phyerr_ev *ev; @@ -862,10 +862,10 @@ static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, return -EPROTO; } - arg->num_phyerrs = ev->num_phyerrs; - arg->tsf_l32 = ev->tsf_l32; - arg->tsf_u32 = ev->tsf_u32; - arg->buf_len = ev->buf_len; + arg->num_phyerrs = __le32_to_cpu(ev->num_phyerrs); + arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); + arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); + arg->buf_len = __le32_to_cpu(ev->buf_len); arg->phyerrs = phyerrs; kfree(tb); @@ -3407,7 +3407,8 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, - .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev, + .pull_phyerr_hdr = ath10k_wmi_tlv_op_pull_phyerr_ev_hdr, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a0a0b0974302..b591ca29dede 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3271,7 +3271,7 @@ void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) } static void ath10k_dfs_radar_report(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_radar_report *rr, u64 tsf) { @@ -3315,7 +3315,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, } /* report event to DFS pattern detector */ - tsf32l = __le32_to_cpu(phyerr->tsf_timestamp); + tsf32l = phyerr->tsf_timestamp; tsf64 = tsf & (~0xFFFFFFFFULL); tsf64 |= tsf32l; @@ -3360,7 +3360,7 @@ radar_detected: } static int ath10k_dfs_fft_report(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_fft_report *fftr, u64 tsf) { @@ -3398,7 +3398,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, } void ath10k_wmi_event_dfs(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, u64 tsf) { int buf_len, tlv_len, res, i = 0; @@ -3407,11 +3407,11 @@ void ath10k_wmi_event_dfs(struct ath10k *ar, const struct phyerr_fft_report *fftr; const u8 *tlv_buf; - buf_len = __le32_to_cpu(phyerr->buf_len); + buf_len = phyerr->buf_len; ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", phyerr->phy_err_code, phyerr->rssi_combined, - __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len); + phyerr->tsf_timestamp, tsf, buf_len); /* Skip event if DFS disabled */ if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) @@ -3463,7 +3463,7 @@ void ath10k_wmi_event_dfs(struct ath10k *ar, } void ath10k_wmi_event_spectral_scan(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, u64 tsf) { int buf_len, tlv_len, res, i = 0; @@ -3472,7 +3472,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar, const struct phyerr_fft_report *fftr; size_t fftr_len; - buf_len = __le32_to_cpu(phyerr->buf_len); + buf_len = phyerr->buf_len; while (i < buf_len) { if (i + sizeof(*tlv) > buf_len) { @@ -3516,65 +3516,110 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar, } } -static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, - struct wmi_phyerr_ev_arg *arg) +static int ath10k_wmi_op_pull_phyerr_ev_hdr(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_phyerr_hdr_arg *arg) { struct wmi_phyerr_event *ev = (void *)skb->data; if (skb->len < sizeof(*ev)) return -EPROTO; - arg->num_phyerrs = ev->num_phyerrs; - arg->tsf_l32 = ev->tsf_l32; - arg->tsf_u32 = ev->tsf_u32; - arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev)); + arg->num_phyerrs = __le32_to_cpu(ev->num_phyerrs); + arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); + arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); + arg->buf_len = skb->len - sizeof(*ev); arg->phyerrs = ev->phyerrs; return 0; } +int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, + const void *phyerr_buf, + int left_len, + struct wmi_phyerr_ev_arg *arg) +{ + const struct wmi_phyerr *phyerr = phyerr_buf; + int i; + + if (left_len < sizeof(*phyerr)) { + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + left_len, sizeof(*phyerr)); + return -EINVAL; + } + + arg->tsf_timestamp = __le32_to_cpu(phyerr->tsf_timestamp); + arg->freq1 = __le16_to_cpu(phyerr->freq1); + arg->freq2 = __le16_to_cpu(phyerr->freq2); + arg->rssi_combined = phyerr->rssi_combined; + arg->chan_width_mhz = phyerr->chan_width_mhz; + arg->buf_len = __le32_to_cpu(phyerr->buf_len); + arg->buf = phyerr->buf; + arg->hdr_len = sizeof(*phyerr); + + for (i = 0; i < 4; i++) + arg->nf_chains[i] = __le16_to_cpu(phyerr->nf_chains[i]); + + switch (phyerr->phy_err_code) { + case PHY_ERROR_GEN_SPECTRAL_SCAN: + arg->phy_err_code = PHY_ERROR_SPECTRAL_SCAN; + break; + case PHY_ERROR_GEN_FALSE_RADAR_EXT: + arg->phy_err_code = PHY_ERROR_FALSE_RADAR_EXT; + break; + case PHY_ERROR_GEN_RADAR: + arg->phy_err_code = PHY_ERROR_RADAR; + break; + default: + arg->phy_err_code = PHY_ERROR_UNKNOWN; + break; + } + + return 0; +} + void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_phyerr_ev_arg arg = {}; - const struct wmi_phyerr *phyerr; + struct wmi_phyerr_hdr_arg hdr_arg = {}; + struct wmi_phyerr_ev_arg phyerr_arg = {}; + const void *phyerr; u32 count, i, buf_len, phy_err_code; u64 tsf; int left_len, ret; ATH10K_DFS_STAT_INC(ar, phy_errors); - ret = ath10k_wmi_pull_phyerr(ar, skb, &arg); + ret = ath10k_wmi_pull_phyerr_hdr(ar, skb, &hdr_arg); if (ret) { - ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); + ath10k_warn(ar, "failed to parse phyerr event hdr: %d\n", ret); return; } - left_len = __le32_to_cpu(arg.buf_len); - /* Check number of included events */ - count = __le32_to_cpu(arg.num_phyerrs); + count = hdr_arg.num_phyerrs; - tsf = __le32_to_cpu(arg.tsf_u32); + left_len = hdr_arg.buf_len; + + tsf = hdr_arg.tsf_u32; tsf <<= 32; - tsf |= __le32_to_cpu(arg.tsf_l32); + tsf |= hdr_arg.tsf_l32; ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event phyerr count %d tsf64 0x%llX\n", count, tsf); - phyerr = arg.phyerrs; + phyerr = hdr_arg.phyerrs; for (i = 0; i < count; i++) { - /* Check if we can read event header */ - if (left_len < sizeof(*phyerr)) { - ath10k_warn(ar, "single event (%d) wrong head len\n", + ret = ath10k_wmi_pull_phyerr(ar, phyerr, left_len, &phyerr_arg); + if (ret) { + ath10k_warn(ar, "failed to parse phyerr event (%d)\n", i); return; } - left_len -= sizeof(*phyerr); - - buf_len = __le32_to_cpu(phyerr->buf_len); - phy_err_code = phyerr->phy_err_code; + left_len -= phyerr_arg.hdr_len; + buf_len = phyerr_arg.buf_len; + phy_err_code = phyerr_arg.phy_err_code; if (left_len < buf_len) { ath10k_warn(ar, "single event (%d) wrong buf len\n", i); @@ -3585,20 +3630,20 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) switch (phy_err_code) { case PHY_ERROR_RADAR: - ath10k_wmi_event_dfs(ar, phyerr, tsf); + ath10k_wmi_event_dfs(ar, &phyerr_arg, tsf); break; case PHY_ERROR_SPECTRAL_SCAN: - ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); + ath10k_wmi_event_spectral_scan(ar, &phyerr_arg, tsf); break; case PHY_ERROR_FALSE_RADAR_EXT: - ath10k_wmi_event_dfs(ar, phyerr, tsf); - ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); + ath10k_wmi_event_dfs(ar, &phyerr_arg, tsf); + ath10k_wmi_event_spectral_scan(ar, &phyerr_arg, tsf); break; default: break; } - phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len; + phyerr = phyerr + phyerr_arg.hdr_len + buf_len; } } @@ -6197,6 +6242,7 @@ static const struct wmi_ops wmi_ops = { .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr, .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, @@ -6268,6 +6314,7 @@ static const struct wmi_ops wmi_10_1_ops = { .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr, .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .pull_roam_ev = ath10k_wmi_op_pull_roam_ev, @@ -6333,6 +6380,7 @@ static const struct wmi_ops wmi_10_2_ops = { .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr, .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .pull_roam_ev = ath10k_wmi_op_pull_roam_ev, @@ -6394,6 +6442,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr, .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .pull_roam_ev = ath10k_wmi_op_pull_roam_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 870265e7867b..54660c3ce893 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2973,9 +2973,16 @@ struct wmi_10_4_mgmt_rx_event { #define WMI_RX_STATUS_ERR_MIC 0x10 #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS 0x20 -#define PHY_ERROR_SPECTRAL_SCAN 0x26 -#define PHY_ERROR_FALSE_RADAR_EXT 0x24 -#define PHY_ERROR_RADAR 0x05 +#define PHY_ERROR_GEN_SPECTRAL_SCAN 0x26 +#define PHY_ERROR_GEN_FALSE_RADAR_EXT 0x24 +#define PHY_ERROR_GEN_RADAR 0x05 + +enum phy_err_type { + PHY_ERROR_UNKNOWN, + PHY_ERROR_SPECTRAL_SCAN, + PHY_ERROR_FALSE_RADAR_EXT, + PHY_ERROR_RADAR +}; struct wmi_phyerr { __le32 tsf_timestamp; @@ -5789,11 +5796,24 @@ struct wmi_swba_ev_arg { }; struct wmi_phyerr_ev_arg { - __le32 num_phyerrs; - __le32 tsf_l32; - __le32 tsf_u32; - __le32 buf_len; - const struct wmi_phyerr *phyerrs; + u32 tsf_timestamp; + u16 freq1; + u16 freq2; + u8 rssi_combined; + u8 chan_width_mhz; + u8 phy_err_code; + u16 nf_chains[4]; + u32 buf_len; + const u8 *buf; + u8 hdr_len; +}; + +struct wmi_phyerr_hdr_arg { + u32 num_phyerrs; + u32 tsf_l32; + u32 tsf_u32; + u32 buf_len; + const void *phyerrs; }; struct wmi_svc_rdy_ev_arg { @@ -6071,9 +6091,9 @@ void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_dfs(struct ath10k *ar, - const struct wmi_phyerr *phyerr, u64 tsf); + struct wmi_phyerr_ev_arg *phyerr, u64 tsf); void ath10k_wmi_event_spectral_scan(struct ath10k *ar, - const struct wmi_phyerr *phyerr, + struct wmi_phyerr_ev_arg *phyerr, u64 tsf); void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb); @@ -6102,5 +6122,6 @@ void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); - +int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, + int left_len, struct wmi_phyerr_ev_arg *arg); #endif /* _WMI_H_ */ -- cgit v1.2.3-70-g09d2 From 2b0a2e0d7c2f12d06575fdc2a0f5cc04b131202d Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 14 Aug 2015 11:13:34 +0300 Subject: ath10k: handle 10.4 firmware phyerr event Header format of 10.4 firmware phyerr event is not alligned with pre 10.4 firmware. Introduce new wmi handlers to parse 10.4 firmware specific phyerror event header. With changes covered in this patch, radar detection works on qca9x0 hw 2.0 which uses 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 64 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 20 +++++++++++ 2 files changed, 84 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b591ca29dede..61af11a07b97 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3534,6 +3534,26 @@ static int ath10k_wmi_op_pull_phyerr_ev_hdr(struct ath10k *ar, return 0; } +static int ath10k_wmi_10_4_op_pull_phyerr_ev_hdr(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_phyerr_hdr_arg *arg) +{ + struct wmi_10_4_phyerr_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + /* 10.4 firmware always reports only one phyerr */ + arg->num_phyerrs = 1; + + arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); + arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); + arg->buf_len = skb->len; + arg->phyerrs = skb->data; + + return 0; +} + int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, int left_len, @@ -3578,6 +3598,45 @@ int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, return 0; } +static int ath10k_wmi_10_4_op_pull_phyerr_ev(struct ath10k *ar, + const void *phyerr_buf, + int left_len, + struct wmi_phyerr_ev_arg *arg) +{ + const struct wmi_10_4_phyerr_event *phyerr = phyerr_buf; + u32 phy_err_mask; + int i; + + if (left_len < sizeof(*phyerr)) { + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + left_len, sizeof(*phyerr)); + return -EINVAL; + } + + arg->tsf_timestamp = __le32_to_cpu(phyerr->tsf_timestamp); + arg->freq1 = __le16_to_cpu(phyerr->freq1); + arg->freq2 = __le16_to_cpu(phyerr->freq2); + arg->rssi_combined = phyerr->rssi_combined; + arg->chan_width_mhz = phyerr->chan_width_mhz; + arg->buf_len = __le32_to_cpu(phyerr->buf_len); + arg->buf = phyerr->buf; + arg->hdr_len = sizeof(*phyerr); + + for (i = 0; i < 4; i++) + arg->nf_chains[i] = __le16_to_cpu(phyerr->nf_chains[i]); + + phy_err_mask = __le32_to_cpu(phyerr->phy_err_mask[0]); + + if (phy_err_mask & PHY_ERROR_10_4_SPECTRAL_SCAN_MASK) + arg->phy_err_code = PHY_ERROR_SPECTRAL_SCAN; + else if (phy_err_mask & PHY_ERROR_10_4_RADAR_MASK) + arg->phy_err_code = PHY_ERROR_RADAR; + else + arg->phy_err_code = PHY_ERROR_UNKNOWN; + + return 0; +} + void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { struct wmi_phyerr_hdr_arg hdr_arg = {}; @@ -4535,6 +4594,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_CHAN_INFO_EVENTID: ath10k_wmi_event_chan_info(ar, skb); break; + case WMI_10_4_PHYERR_EVENTID: + ath10k_wmi_event_phyerr(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -6498,6 +6560,8 @@ static const struct wmi_ops wmi_10_4_ops = { .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, + .pull_phyerr_hdr = ath10k_wmi_10_4_op_pull_phyerr_ev_hdr, + .pull_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 54660c3ce893..52d35032d53e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2977,6 +2977,9 @@ struct wmi_10_4_mgmt_rx_event { #define PHY_ERROR_GEN_FALSE_RADAR_EXT 0x24 #define PHY_ERROR_GEN_RADAR 0x05 +#define PHY_ERROR_10_4_RADAR_MASK 0x4 +#define PHY_ERROR_10_4_SPECTRAL_SCAN_MASK 0x4000000 + enum phy_err_type { PHY_ERROR_UNKNOWN, PHY_ERROR_SPECTRAL_SCAN, @@ -3005,6 +3008,23 @@ struct wmi_phyerr_event { struct wmi_phyerr phyerrs[0]; } __packed; +struct wmi_10_4_phyerr_event { + __le32 tsf_l32; + __le32 tsf_u32; + __le16 freq1; + __le16 freq2; + u8 rssi_combined; + u8 chan_width_mhz; + u8 phy_err_code; + u8 rsvd0; + __le32 rssi_chains[4]; + __le16 nf_chains[4]; + __le32 phy_err_mask[2]; + __le32 tsf_timestamp; + __le32 buf_len; + u8 buf[0]; +} __packed; + #define PHYERR_TLV_SIG 0xBB #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 -- cgit v1.2.3-70-g09d2 From b2887410f0d00f376b250f78d34654b4ac093900 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 13 Aug 2015 21:10:54 +0530 Subject: ath10k: fill in wmi 10.4 command handlers for addba/delba debug commands WMI 10.4 uses the same command interface as QCA988X for addba/delba debug wmi commands. Fill wmi_10_4_ops table with the functions used for QCA988X for these commands. With this change, the following debugfs entries can be used to configure the aggregation mode and to send addba request, addba response and delba respectively in manual aggregation mode for QCA99X0 chip. /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/XX:XX:XX:XX:XX:XX/aggr_mode /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/XX:XX:XX:XX:XX:XX/addba /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/XX:XX:XX:XX:XX:XX/addba_resp /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/XX:XX:XX:XX:XX:XX/delba Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 61af11a07b97..42c0aba04fb2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6597,6 +6597,10 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, /* shared with 10.2 */ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, -- cgit v1.2.3-70-g09d2 From bf27cea49502799be15beab3567ea2bd9901ad2f Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 31 Mar 2015 00:55:32 +0900 Subject: rtlwifi: rtl8192cu: remove duplicated routine in hw.c and mac.c rtl92c_set_xxx_filter is same routine with rtl92cu_set_hw_reg. so i remove those functions that are rtl92c_set_xxx_filter. (rtl92c_get_xxx_filter is also same reason.) also i add code updating struct rtl_mac member variable in the rtl92cu_set_hw_reg. after that, no more _update_mac_setting is not useful. thus i remove that. Signed-off-by: Taehee Yoo Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 38 +++++++++++--------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 41 ---------------------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.h | 9 ------ 3 files changed, 16 insertions(+), 72 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 7cf36619f250..5a3463f89734 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -818,26 +818,29 @@ static void _rtl92cu_init_usb_aggregation(struct ieee80211_hw *hw) static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) { - u16 value16; - + u16 value16; + u32 value32; struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | - RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | - RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); - rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); + value32 = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | + RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | + RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&value32)); /* Accept all multicast address */ rtl_write_dword(rtlpriv, REG_MAR, 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_MAR + 4, 0xFFFFFFFF); /* Accept all management frames */ value16 = 0xFFFF; - rtl92c_set_mgt_filter(hw, value16); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, + (u8 *)(&value16)); /* Reject all control frame - default value is 0 */ - rtl92c_set_ctrl_filter(hw, 0x0); + value16 = 0x0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, + (u8 *)(&value16)); /* Accept all data frames */ value16 = 0xFFFF; - rtl92c_set_data_filter(hw, value16); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DATA_FILTER, + (u8 *)(&value16)); } static void _rtl92cu_init_beacon_parameters(struct ieee80211_hw *hw) @@ -988,17 +991,6 @@ static void _InitPABias(struct ieee80211_hw *hw) } } -static void _update_mac_setting(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - - mac->rx_conf = rtl_read_dword(rtlpriv, REG_RCR); - mac->rx_mgt_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP0); - mac->rx_ctrl_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP1); - mac->rx_data_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP2); -} - int rtl92cu_hw_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1068,7 +1060,6 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) } _rtl92cu_hw_configure(hw); _InitPABias(hw); - _update_mac_setting(hw); rtl92c_dm_init(hw); exit: local_irq_restore(flags); @@ -1999,12 +1990,15 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } case HW_VAR_MGT_FILTER: rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *)val); + mac->rx_mgt_filter = *(u16 *)val; break; case HW_VAR_CTRL_FILTER: rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *)val); + mac->rx_ctrl_filter = *(u16 *)val; break; case HW_VAR_DATA_FILTER: rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *)val); + mac->rx_data_filter = *(u16 *)val; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 1c55a002d4bd..23549f4b0aa0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -644,47 +644,6 @@ void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T) rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, value); } -u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - return rtl_read_word(rtlpriv, REG_RXFLTMAP0); -} - -void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtl_write_word(rtlpriv, REG_RXFLTMAP0, filter); -} - -u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - return rtl_read_word(rtlpriv, REG_RXFLTMAP1); -} - -void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtl_write_word(rtlpriv, REG_RXFLTMAP1, filter); -} - -u16 rtl92c_get_data_filter(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - return rtl_read_word(rtlpriv, REG_RXFLTMAP2); -} - -void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtl_write_word(rtlpriv, REG_RXFLTMAP2, filter); -} /*==============================================================*/ static u8 _rtl92c_query_rxpwrpercentage(char antpower) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h index e34f0f14ccd7..a68710b6c610 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -73,15 +73,6 @@ void rtl92c_init_retry_function(struct ieee80211_hw *hw); void rtl92c_disable_fast_edca(struct ieee80211_hw *hw); void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T); -/* For filter */ -u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw); -void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter); -u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw); -void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter); -u16 rtl92c_get_data_filter(struct ieee80211_hw *hw); -void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter); - - u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw); struct rx_fwinfo_92c { -- cgit v1.2.3-70-g09d2 From 9ff4b6de26a72f76450943548ee7d9d779eeaac5 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 7 Apr 2015 03:13:00 +0900 Subject: rtlwifi: rtl8192cu: Remove and replace routine in hw.c and mac.c I remove duplicated routines which related rtl92cu_set_hw_reg(). 1. rtl92c_set_qos() and HW_VAR_AC_PARAM routine are similar code. so i replace code with rtlpriv->cfg->ops->set_hw_reg(). 2. rtl92c_set_mac_addr() and 'HW_VAR_ETHER_ADDR' case at rtl92cu_set_hw_reg() routine are similar code. so i removed rtl92c_set_mac_addr() function. also it was not used anywhere. 3. remove HW_VAR_ACM_CTRL routine in rtl92cu_set_hw_reg(). if rtl_usb->acm_method is not EACMWAY2_SW, HW_VAR_ACM_CTRL is called from HW_VAR_AC_PARAM. but it never called. because acm_method is always EACMWAY2_SW. so i remove acm_method check routine and HW_VAR_ACM_CTRL routine. both usb and pci interface is not used HW_VAR_ACM_CTRL. but i can't test pci interface module, so i didn't modify pci code. Signed-off-by: Taehee Yoo Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 56 +--------------------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 52 +------------------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.h | 1 - 3 files changed, 2 insertions(+), 107 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 5a3463f89734..25db369b5d18 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1611,7 +1611,6 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); enum wireless_mode wirelessmode = mac->mode; u8 idx = 0; @@ -1820,63 +1819,10 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) u4b_ac_param); break; default: - RT_ASSERT(false, - "SetHwReg8185(): invalid aci: %d !\n", + RT_ASSERT(false, "invalid aci: %d !\n", e_aci); break; } - if (rtlusb->acm_method != EACMWAY2_SW) - rtlpriv->cfg->ops->set_hw_reg(hw, - HW_VAR_ACM_CTRL, &e_aci); - break; - } - case HW_VAR_ACM_CTRL:{ - u8 e_aci = *val; - union aci_aifsn *p_aci_aifsn = (union aci_aifsn *) - (&(mac->ac[0].aifs)); - u8 acm = p_aci_aifsn->f.acm; - u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); - - acm_ctrl = - acm_ctrl | ((rtlusb->acm_method == 2) ? 0x0 : 0x1); - if (acm) { - switch (e_aci) { - case AC0_BE: - acm_ctrl |= AcmHw_BeqEn; - break; - case AC2_VI: - acm_ctrl |= AcmHw_ViqEn; - break; - case AC3_VO: - acm_ctrl |= AcmHw_VoqEn; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n", - acm); - break; - } - } else { - switch (e_aci) { - case AC0_BE: - acm_ctrl &= (~AcmHw_BeqEn); - break; - case AC2_VI: - acm_ctrl &= (~AcmHw_ViqEn); - break; - case AC3_VO: - acm_ctrl &= (~AcmHw_VoqEn); - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "switch case not processed\n"); - break; - } - } - RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, - "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", - acm_ctrl); - rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); break; } case HW_VAR_RCR:{ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 23549f4b0aa0..035713311a4a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -393,59 +393,9 @@ void rtl92c_disable_interrupt(struct ieee80211_hw *hw) void rtl92c_set_qos(struct ieee80211_hw *hw, int aci) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 u4b_ac_param; rtl92c_dm_init_edca_turbo(hw); - u4b_ac_param = (u32) mac->ac[aci].aifs; - u4b_ac_param |= - ((u32) le16_to_cpu(mac->ac[aci].cw_min) & 0xF) << - AC_PARAM_ECW_MIN_OFFSET; - u4b_ac_param |= - ((u32) le16_to_cpu(mac->ac[aci].cw_max) & 0xF) << - AC_PARAM_ECW_MAX_OFFSET; - u4b_ac_param |= (u32) le16_to_cpu(mac->ac[aci].tx_op) << - AC_PARAM_TXOP_OFFSET; - RT_TRACE(rtlpriv, COMP_QOS, DBG_LOUD, "queue:%x, ac_param:%x\n", - aci, u4b_ac_param); - switch (aci) { - case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); - break; - case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); - break; - case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); - break; - case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); - break; - default: - RT_ASSERT(false, "invalid aci: %d !\n", aci); - break; - } -} - -/*------------------------------------------------------------------------- - * HW MAC Address - *-------------------------------------------------------------------------*/ -void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr) -{ - u32 i; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - for (i = 0 ; i < ETH_ALEN ; i++) - rtl_write_byte(rtlpriv, (REG_MACID + i), *(addr+i)); - - RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, - "MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n", - rtl_read_byte(rtlpriv, REG_MACID), - rtl_read_byte(rtlpriv, REG_MACID+1), - rtl_read_byte(rtlpriv, REG_MACID+2), - rtl_read_byte(rtlpriv, REG_MACID+3), - rtl_read_byte(rtlpriv, REG_MACID+4), - rtl_read_byte(rtlpriv, REG_MACID+5)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, (u8 *)&aci); } void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h index a68710b6c610..553a4bfac668 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -48,7 +48,6 @@ void rtl92c_set_qos(struct ieee80211_hw *hw, int aci); /*--------------------------------------------------------------- * Hardware init functions *---------------------------------------------------------------*/ -void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr); void rtl92c_init_interrupt(struct ieee80211_hw *hw); void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size); -- cgit v1.2.3-70-g09d2 From bafc6e4cd897ef14015d8d32a04ee9bfa8d91370 Mon Sep 17 00:00:00 2001 From: John Linville Date: Mon, 10 Aug 2015 12:05:39 -0400 Subject: mwl8k: refactor some conditionals for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/mwl8k.o drivers/net/wireless/mwl8k.c: In function ‘mwl8k_bss_info_changed’: drivers/net/wireless/mwl8k.c:3290:2: warning: ‘ap_mcs_rates’ may be used uninitialized in this function [-Wmaybe-uninitialized] memcpy(cmd->mcs_set, mcs_rates, 16); ^ drivers/net/wireless/mwl8k.c:4987:5: note: ‘ap_mcs_rates’ was declared here u8 ap_mcs_rates[16]; ^ The warning was bogus. But the conditionals were rather complicated, with multiple redundant checks. This consolidates the checking and makes it more readable IMHO. Signed-off-by: John W. Linville Signed-off-by: Kalle Valo --- drivers/net/wireless/mwl8k.c | 49 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 77361af68b18..9420fc61c2e6 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5019,35 +5019,36 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); rcu_read_unlock(); - } - if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && - !priv->ap_fw) { - rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); - if (rc) - goto out; + if (changed & BSS_CHANGED_ASSOC) { + if (!priv->ap_fw) { + rc = mwl8k_cmd_set_rate(hw, vif, + ap_legacy_rates, + ap_mcs_rates); + if (rc) + goto out; - rc = mwl8k_cmd_use_fixed_rate_sta(hw); - if (rc) - goto out; - } else { - if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && - priv->ap_fw) { - int idx; - int rate; + rc = mwl8k_cmd_use_fixed_rate_sta(hw); + if (rc) + goto out; + } else { + int idx; + int rate; - /* Use AP firmware specific rate command. - */ - idx = ffs(vif->bss_conf.basic_rates); - if (idx) - idx--; + /* Use AP firmware specific rate command. + */ + idx = ffs(vif->bss_conf.basic_rates); + if (idx) + idx--; - if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) - rate = mwl8k_rates_24[idx].hw_value; - else - rate = mwl8k_rates_50[idx].hw_value; + if (hw->conf.chandef.chan->band == + IEEE80211_BAND_2GHZ) + rate = mwl8k_rates_24[idx].hw_value; + else + rate = mwl8k_rates_50[idx].hw_value; - mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); + mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); + } } } -- cgit v1.2.3-70-g09d2 From f10746fef3dfa8546808989f71c3543db832f374 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Tue, 11 Aug 2015 00:25:53 +0200 Subject: rt2x00: adjust EEPROM_SIZE for rt2500usb rt2500usb_validate_eeprom() read data up to 0x6e (EEPROM_CALIBRATE_OFFSET) but only 0x6a bytes has been allocated and read from the eeprom. This lead to out-of-bound accesses and invalid values for EEPROM_BBPTUNE_R17 and EEPROM_CALIBRATE_OFFSET. Change the EEPROM_SIZE to 0x6e in order to retrieve all the fields. Tested with a rt2570 device. Signed-off-by: Adrien Schildknecht Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2500usb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index afba0739c3b8..78cc035b2d17 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -54,7 +54,7 @@ #define CSR_REG_BASE 0x0400 #define CSR_REG_SIZE 0x0100 #define EEPROM_BASE 0x0000 -#define EEPROM_SIZE 0x006a +#define EEPROM_SIZE 0x006e #define BBP_BASE 0x0000 #define BBP_SIZE 0x0060 #define RF_BASE 0x0004 -- cgit v1.2.3-70-g09d2 From c48276cbbeaedd49cdf32f2b734b4a1ec6d6ccad Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Aug 2015 10:02:56 +0300 Subject: wl18xx: update statistics acx and debugfs files Sync the driver statistics acx and debugfs representation with the current fw api. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/acx.h | 78 +++++++++++---- drivers/net/wireless/ti/wl18xx/debugfs.c | 159 ++++++++++++++++++------------- 2 files changed, 156 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index c8a33f43916e..6c5fef33b0be 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -93,11 +93,23 @@ struct wl18xx_acx_checksum_state { struct wl18xx_acx_error_stats { - u32 error_frame; - u32 error_null_Frame_tx_start; - u32 error_numll_frame_cts_start; - u32 error_bar_retry; - u32 error_frame_cts_nul_flid; + u32 error_frame_non_ctrl; + u32 error_frame_ctrl; + u32 error_frame_during_protection; + u32 null_frame_tx_start; + u32 null_frame_cts_start; + u32 bar_retry; + u32 num_frame_cts_nul_flid; + u32 tx_abort_failure; + u32 tx_resume_failure; + u32 rx_cmplt_db_overflow_cnt; + u32 elp_while_rx_exch; + u32 elp_while_tx_exch; + u32 elp_while_tx; + u32 elp_while_nvic_pending; + u32 rx_excessive_frame_len; + u32 burst_mismatch; + u32 tbc_exch_mismatch; } __packed; struct wl18xx_acx_debug_stats { @@ -114,6 +126,7 @@ struct wl18xx_acx_ring_stats { u32 tx_cmplt; } __packed; +#define NUM_OF_RATES_INDEXES 30 struct wl18xx_acx_tx_stats { u32 tx_prepared_descs; u32 tx_cmplt; @@ -123,7 +136,7 @@ struct wl18xx_acx_tx_stats { u32 tx_data_programmed; u32 tx_burst_programmed; u32 tx_starts; - u32 tx_imm_resp; + u32 tx_stop; u32 tx_start_templates; u32 tx_start_int_templates; u32 tx_start_fw_gen; @@ -132,13 +145,14 @@ struct wl18xx_acx_tx_stats { u32 tx_exch; u32 tx_retry_template; u32 tx_retry_data; + u32 tx_retry_per_rate[NUM_OF_RATES_INDEXES]; u32 tx_exch_pending; u32 tx_exch_expiry; u32 tx_done_template; u32 tx_done_data; u32 tx_done_int_template; - u32 tx_frame_checksum; - u32 tx_checksum_result; + u32 tx_cfe1; + u32 tx_cfe2; u32 frag_called; u32 frag_mpdu_alloc_failed; u32 frag_init_called; @@ -166,11 +180,8 @@ struct wl18xx_acx_rx_stats { u32 rx_cmplt_task; u32 rx_phy_hdr; u32 rx_timeout; + u32 rx_rts_timeout; u32 rx_timeout_wa; - u32 rx_wa_density_dropped_frame; - u32 rx_wa_ba_not_expected; - u32 rx_frame_checksum; - u32 rx_checksum_result; u32 defrag_called; u32 defrag_init_called; u32 defrag_in_process_called; @@ -180,6 +191,7 @@ struct wl18xx_acx_rx_stats { u32 decrypt_key_not_found; u32 defrag_need_decrypt; u32 rx_tkip_replays; + u32 rx_xfr; } __packed; struct wl18xx_acx_isr_stats { @@ -194,6 +206,13 @@ struct wl18xx_acx_pwr_stats { u32 connection_out_of_sync; u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD]; u32 rcvd_awake_bcns_cnt; + u32 sleep_time_count; + u32 sleep_time_avg; + u32 sleep_cycle_avg; + u32 sleep_percent; + u32 ap_sleep_active_conf; + u32 ap_sleep_user_conf; + u32 ap_sleep_counter; } __packed; struct wl18xx_acx_event_stats { @@ -228,11 +247,11 @@ struct wl18xx_acx_rx_rate_stats { } __packed; #define AGGR_STATS_TX_AGG 16 -#define AGGR_STATS_TX_RATE 16 #define AGGR_STATS_RX_SIZE_LEN 16 struct wl18xx_acx_aggr_stats { - u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE]; + u32 tx_agg_rate[AGGR_STATS_TX_AGG]; + u32 tx_agg_len[AGGR_STATS_TX_AGG]; u32 rx_size[AGGR_STATS_RX_SIZE_LEN]; } __packed; @@ -258,6 +277,7 @@ struct wl18xx_acx_pipeline_stats { u32 cs_rx_packet_in; u32 cs_rx_packet_out; u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO]; + u16 padding; } __packed; struct wl18xx_acx_mem_stats { @@ -267,21 +287,45 @@ struct wl18xx_acx_mem_stats { u32 fw_gen_free_mem_blks; } __packed; +struct wl18xx_acx_thermal_stats { + u16 irq_thr_low; + u16 irq_thr_high; + u16 tx_stop; + u16 tx_resume; + u16 false_irq; + u16 adc_source_unexpected; +} __packed; + +#define WL18XX_NUM_OF_CALIBRATIONS_ERRORS 18 +struct wl18xx_acx_calib_failure_stats { + u16 fail_count[WL18XX_NUM_OF_CALIBRATIONS_ERRORS]; + u32 calib_count; +} __packed; + +struct wl18xx_roaming_stats { + s32 rssi_level; +} __packed; + +struct wl18xx_dfs_stats { + u32 num_of_radar_detections; +} __packed; + struct wl18xx_acx_statistics { struct acx_header header; struct wl18xx_acx_error_stats error; - struct wl18xx_acx_debug_stats debug; struct wl18xx_acx_tx_stats tx; struct wl18xx_acx_rx_stats rx; struct wl18xx_acx_isr_stats isr; struct wl18xx_acx_pwr_stats pwr; - struct wl18xx_acx_ps_poll_stats ps_poll; struct wl18xx_acx_rx_filter_stats rx_filter; struct wl18xx_acx_rx_rate_stats rx_rate; struct wl18xx_acx_aggr_stats aggr_size; struct wl18xx_acx_pipeline_stats pipeline; - struct wl18xx_acx_mem_stats mem; + struct wl18xx_acx_thermal_stats thermal; + struct wl18xx_acx_calib_failure_stats calib; + struct wl18xx_roaming_stats roaming; + struct wl18xx_dfs_stats dfs; } __packed; struct wl18xx_acx_clear_statistics { diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 8c6a1c86f526..cf71005d6512 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -36,18 +36,23 @@ DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics) -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u"); - -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_non_ctrl, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_ctrl, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_during_protection, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, null_frame_tx_start, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, null_frame_cts_start, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, bar_retry, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, num_frame_cts_nul_flid, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tx_abort_failure, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tx_resume_failure, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, rx_cmplt_db_overflow_cnt, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_rx_exch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_tx_exch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_tx, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_nvic_pending, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, rx_excessive_frame_len, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, burst_mismatch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tbc_exch_mismatch, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u"); @@ -57,7 +62,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_stop, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u"); @@ -66,13 +71,15 @@ WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(tx, tx_retry_per_rate, + NUM_OF_RATES_INDEXES); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cfe1, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cfe2, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u"); @@ -97,11 +104,8 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_rts_timeout, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u"); @@ -111,6 +115,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_xfr, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); @@ -120,14 +125,13 @@ WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread, PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD); WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u"); - - -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_time_count, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_time_avg, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_cycle_avg, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_percent, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_active_conf, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_user_conf, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_counter, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u"); @@ -141,8 +145,10 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(rx_rate, rx_frames_per_rates, 50); -WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate, - AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_rate, + AGGR_STATS_TX_AGG); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_len, + AGGR_STATS_TX_AGG); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size, AGGR_STATS_RX_SIZE_LEN); @@ -167,10 +173,20 @@ WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full, PIPE_STATS_HW_FIFO); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_low, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_high, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, tx_stop, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, tx_resume, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, false_irq, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, adc_source_unexpected, "%u"); + +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(calib, fail_count, + WL18XX_NUM_OF_CALIBRATIONS_ERRORS); +WL18XX_DEBUGFS_FWSTATS_FILE(calib, calib_count, "%u"); + +WL18XX_DEBUGFS_FWSTATS_FILE(roaming, rssi_level, "%d"); + +WL18XX_DEBUGFS_FWSTATS_FILE(dfs, num_of_radar_detections, "%d"); static ssize_t conf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -350,18 +366,23 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(clear_fw_stats, stats); - DEBUGFS_FWSTATS_ADD(debug, debug1); - DEBUGFS_FWSTATS_ADD(debug, debug2); - DEBUGFS_FWSTATS_ADD(debug, debug3); - DEBUGFS_FWSTATS_ADD(debug, debug4); - DEBUGFS_FWSTATS_ADD(debug, debug5); - DEBUGFS_FWSTATS_ADD(debug, debug6); - - DEBUGFS_FWSTATS_ADD(error, error_frame); - DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start); - DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start); - DEBUGFS_FWSTATS_ADD(error, error_bar_retry); - DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid); + DEBUGFS_FWSTATS_ADD(error, error_frame_non_ctrl); + DEBUGFS_FWSTATS_ADD(error, error_frame_ctrl); + DEBUGFS_FWSTATS_ADD(error, error_frame_during_protection); + DEBUGFS_FWSTATS_ADD(error, null_frame_tx_start); + DEBUGFS_FWSTATS_ADD(error, null_frame_cts_start); + DEBUGFS_FWSTATS_ADD(error, bar_retry); + DEBUGFS_FWSTATS_ADD(error, num_frame_cts_nul_flid); + DEBUGFS_FWSTATS_ADD(error, tx_abort_failure); + DEBUGFS_FWSTATS_ADD(error, tx_resume_failure); + DEBUGFS_FWSTATS_ADD(error, rx_cmplt_db_overflow_cnt); + DEBUGFS_FWSTATS_ADD(error, elp_while_rx_exch); + DEBUGFS_FWSTATS_ADD(error, elp_while_tx_exch); + DEBUGFS_FWSTATS_ADD(error, elp_while_tx); + DEBUGFS_FWSTATS_ADD(error, elp_while_nvic_pending); + DEBUGFS_FWSTATS_ADD(error, rx_excessive_frame_len); + DEBUGFS_FWSTATS_ADD(error, burst_mismatch); + DEBUGFS_FWSTATS_ADD(error, tbc_exch_mismatch); DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs); DEBUGFS_FWSTATS_ADD(tx, tx_cmplt); @@ -371,7 +392,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed); DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed); DEBUGFS_FWSTATS_ADD(tx, tx_starts); - DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp); + DEBUGFS_FWSTATS_ADD(tx, tx_stop); DEBUGFS_FWSTATS_ADD(tx, tx_start_templates); DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates); DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen); @@ -380,13 +401,14 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(tx, tx_exch); DEBUGFS_FWSTATS_ADD(tx, tx_retry_template); DEBUGFS_FWSTATS_ADD(tx, tx_retry_data); + DEBUGFS_FWSTATS_ADD(tx, tx_retry_per_rate); DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending); DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry); DEBUGFS_FWSTATS_ADD(tx, tx_done_template); DEBUGFS_FWSTATS_ADD(tx, tx_done_data); DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template); - DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum); - DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result); + DEBUGFS_FWSTATS_ADD(tx, tx_cfe1); + DEBUGFS_FWSTATS_ADD(tx, tx_cfe2); DEBUGFS_FWSTATS_ADD(tx, frag_called); DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed); DEBUGFS_FWSTATS_ADD(tx, frag_init_called); @@ -411,11 +433,8 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task); DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr); DEBUGFS_FWSTATS_ADD(rx, rx_timeout); + DEBUGFS_FWSTATS_ADD(rx, rx_rts_timeout); DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa); - DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame); - DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected); - DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum); - DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result); DEBUGFS_FWSTATS_ADD(rx, defrag_called); DEBUGFS_FWSTATS_ADD(rx, defrag_init_called); DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called); @@ -425,6 +444,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found); DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt); DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays); + DEBUGFS_FWSTATS_ADD(rx, rx_xfr); DEBUGFS_FWSTATS_ADD(isr, irqs); @@ -433,13 +453,13 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync); DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread); DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt); - - DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts); - DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts); - DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn); - DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn); - DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization); - DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization); + DEBUGFS_FWSTATS_ADD(pwr, sleep_time_count); + DEBUGFS_FWSTATS_ADD(pwr, sleep_time_avg); + DEBUGFS_FWSTATS_ADD(pwr, sleep_cycle_avg); + DEBUGFS_FWSTATS_ADD(pwr, sleep_percent); + DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_active_conf); + DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_user_conf); + DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_counter); DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter); DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter); @@ -453,7 +473,8 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates); - DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate); + DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_rate); + DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_len); DEBUGFS_FWSTATS_ADD(aggr_size, rx_size); DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int); @@ -475,10 +496,20 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out); DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full); - DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks); - DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks); - DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks); - DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks); + DEBUGFS_FWSTATS_ADD(thermal, irq_thr_low); + DEBUGFS_FWSTATS_ADD(thermal, irq_thr_high); + DEBUGFS_FWSTATS_ADD(thermal, tx_stop); + DEBUGFS_FWSTATS_ADD(thermal, tx_resume); + DEBUGFS_FWSTATS_ADD(thermal, false_irq); + DEBUGFS_FWSTATS_ADD(thermal, adc_source_unexpected); + + DEBUGFS_FWSTATS_ADD(calib, fail_count); + + DEBUGFS_FWSTATS_ADD(calib, calib_count); + + DEBUGFS_FWSTATS_ADD(roaming, rssi_level); + + DEBUGFS_FWSTATS_ADD(dfs, num_of_radar_detections); DEBUGFS_ADD(conf, moddir); DEBUGFS_ADD(radar_detection, moddir); -- cgit v1.2.3-70-g09d2 From fc645df093926d8cd33a9dd9b6532ff3fd937193 Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Tue, 11 Aug 2015 10:02:57 +0300 Subject: wl18xx: add diversity statistics Add diversity statistics and sync the driver statistics acx and debugfs representation with the current fw api. Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/acx.h | 47 +++++--------------------------- drivers/net/wireless/ti/wl18xx/debugfs.c | 21 ++++++-------- 2 files changed, 16 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 6c5fef33b0be..342a2993ef98 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -112,20 +112,6 @@ struct wl18xx_acx_error_stats { u32 tbc_exch_mismatch; } __packed; -struct wl18xx_acx_debug_stats { - u32 debug1; - u32 debug2; - u32 debug3; - u32 debug4; - u32 debug5; - u32 debug6; -} __packed; - -struct wl18xx_acx_ring_stats { - u32 prepared_descs; - u32 tx_cmplt; -} __packed; - #define NUM_OF_RATES_INDEXES 30 struct wl18xx_acx_tx_stats { u32 tx_prepared_descs; @@ -215,21 +201,6 @@ struct wl18xx_acx_pwr_stats { u32 ap_sleep_counter; } __packed; -struct wl18xx_acx_event_stats { - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; -} __packed; - -struct wl18xx_acx_ps_poll_stats { - u32 ps_poll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_ap_turn; - u32 ps_poll_max_ap_turn; - u32 ps_poll_utilization; - u32 upsd_utilization; -} __packed; - struct wl18xx_acx_rx_filter_stats { u32 beacon_filter; u32 arp_filter; @@ -260,8 +231,6 @@ struct wl18xx_acx_aggr_stats { struct wl18xx_acx_pipeline_stats { u32 hs_tx_stat_fifo_int; u32 hs_rx_stat_fifo_int; - u32 tcp_tx_stat_fifo_int; - u32 tcp_rx_stat_fifo_int; u32 enc_tx_stat_fifo_int; u32 enc_rx_stat_fifo_int; u32 rx_complete_stat_fifo_int; @@ -269,22 +238,19 @@ struct wl18xx_acx_pipeline_stats { u32 post_proc_swi; u32 sec_frag_swi; u32 pre_to_defrag_swi; - u32 defrag_to_csum_swi; - u32 csum_to_rx_xfer_swi; + u32 defrag_to_rx_xfer_swi; u32 dec_packet_in; u32 dec_packet_in_fifo_full; u32 dec_packet_out; - u32 cs_rx_packet_in; - u32 cs_rx_packet_out; u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO]; u16 padding; } __packed; -struct wl18xx_acx_mem_stats { - u32 rx_free_mem_blks; - u32 tx_free_mem_blks; - u32 fwlog_free_mem_blks; - u32 fw_gen_free_mem_blks; +#define DIVERSITY_STATS_NUM_OF_ANT 2 + +struct wl18xx_acx_diversity_stats { + u32 num_of_packets_per_ant[DIVERSITY_STATS_NUM_OF_ANT]; + u32 total_num_of_toggles; } __packed; struct wl18xx_acx_thermal_stats { @@ -322,6 +288,7 @@ struct wl18xx_acx_statistics { struct wl18xx_acx_rx_rate_stats rx_rate; struct wl18xx_acx_aggr_stats aggr_size; struct wl18xx_acx_pipeline_stats pipeline; + struct wl18xx_acx_diversity_stats diversity; struct wl18xx_acx_thermal_stats thermal; struct wl18xx_acx_calib_failure_stats calib; struct wl18xx_roaming_stats roaming; diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index cf71005d6512..4edfe28395f0 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -153,8 +153,6 @@ WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size, AGGR_STATS_RX_SIZE_LEN); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u"); @@ -162,17 +160,18 @@ WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_rx_xfer_swi, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full, PIPE_STATS_HW_FIFO); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(diversity, num_of_packets_per_ant, + DIVERSITY_STATS_NUM_OF_ANT); +WL18XX_DEBUGFS_FWSTATS_FILE(diversity, total_num_of_toggles, "%u"); + WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_low, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_high, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(thermal, tx_stop, "%u"); @@ -478,8 +477,6 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(aggr_size, rx_size); DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int); - DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int); - DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int); DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int); DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int); DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int); @@ -487,15 +484,15 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi); DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi); DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi); - DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi); - DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi); + DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_rx_xfer_swi); DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in); DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full); DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out); - DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in); - DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out); DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full); + DEBUGFS_FWSTATS_ADD(diversity, num_of_packets_per_ant); + DEBUGFS_FWSTATS_ADD(diversity, total_num_of_toggles); + DEBUGFS_FWSTATS_ADD(thermal, irq_thr_low); DEBUGFS_FWSTATS_ADD(thermal, irq_thr_high); DEBUGFS_FWSTATS_ADD(thermal, tx_stop); -- cgit v1.2.3-70-g09d2 From 1165dd900cc8de3addbc8bef7e6196b07799d25e Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 12 Aug 2015 14:20:46 +0800 Subject: ath9k: add correct MAC/BB name for ar9561 MAC/BB name is"????" if the MAC/BB is unknown. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a31a6804dc34..1dd0339de372 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3186,6 +3186,7 @@ static struct { { AR_SREV_VERSION_9550, "9550" }, { AR_SREV_VERSION_9565, "9565" }, { AR_SREV_VERSION_9531, "9531" }, + { AR_SREV_VERSION_9561, "9561" }, }; /* For devices with external radios */ -- cgit v1.2.3-70-g09d2 From 783eaee6dbf475827b5fbdb13c17c54510aaa95e Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Tue, 28 Jul 2015 16:50:51 +0300 Subject: iwlwifi: rs: disable MIMO only if allowed in configuration Fix bug where MIMO is disabled for low latency TX on P2P VIF regardless of configuration. Make it dependent on IWL_MVM_RS_DISABLE_P2P_MIMO compilation option. Change configuration so that MIMO will be disabled only in SDIO platforms. Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 19a79262e0a0..5ae9c8aa868f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -177,7 +177,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, mvmsta = iwl_mvm_sta_from_mac80211(sta); mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - if (iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p) + if (IWL_MVM_RS_DISABLE_P2P_MIMO && + iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p) return false; if (mvm->nvm_data->sku_cap_mimo_disabled) -- cgit v1.2.3-70-g09d2 From da0fa5ebb254d1617455ace9af1ce2f1d375a95d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 16 Aug 2015 10:39:49 +0300 Subject: iwlwifi: bump mvm firmware API to 16 The driver is now able to handle -16.ucode. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index fa35da4edda2..413b63e09717 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 15 +#define IWL7260_UCODE_API_MAX 16 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 12 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 92709ad5de44..8324bc8987a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 15 +#define IWL8000_UCODE_API_MAX 16 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 12 -- cgit v1.2.3-70-g09d2 From e192cd121dbe009f67eddd5171d588994b15486c Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Fri, 14 Aug 2015 02:35:32 +0200 Subject: iwlwifi: out-of-bounds access in iwl_init_sband_channels KASan error report: ================================================================== BUG: KASan: out of bounds access in iwl_init_sband_channels+0x207/0x260 [iwlwifi] at addr ffff8800c2d0aac8 Read of size 4 by task modprobe/329 ================================================================== Both loops of this function compare data from the 'chan' array and then check if the index is valid. The 2 conditions should be inverted to avoid an out-of-bounds access. Signed-off-by: Adrien Schildknecht Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 21302b6f2bfd..acc3d186c5c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -713,12 +713,12 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data, struct ieee80211_channel *chan = &data->channels[0]; int n = 0, idx = 0; - while (chan->band != band && idx < n_channels) + while (idx < n_channels && chan->band != band) chan = &data->channels[++idx]; sband->channels = &data->channels[idx]; - while (chan->band == band && idx < n_channels) { + while (idx < n_channels && chan->band == band) { chan = &data->channels[++idx]; n++; } -- cgit v1.2.3-70-g09d2 From b3df22475423a99cc1f6c4b202970fa89a4d9716 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 6 Aug 2015 10:26:50 +0300 Subject: iwlwifi: mvm: don't disconnect on beacon loss in D0I3 Currently if we wake up during D0I3 due to beacon loss we disconnect immediately. This behaviour causes redundant disconnection, which could be prevented by polling as it is usually done in mac80211. Instead, we prefer reporting beacon loss and let mac80211 try polling before disconnection. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 37 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index c15c994b6a27..02ce18419f20 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1170,15 +1170,25 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); } -static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) +struct iwl_mvm_wakeup_reason_iter_data { + struct iwl_mvm *mvm; + u32 wakeup_reasons; +}; + +static void iwl_mvm_d0i3_wakeup_reason_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) { - struct iwl_mvm *mvm = data; + struct iwl_mvm_wakeup_reason_iter_data *data = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && - mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) - iwl_mvm_connection_loss(mvm, vif, "D0i3"); + 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); + } } void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) @@ -1246,7 +1256,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) }; struct iwl_wowlan_status *status; int ret; - u32 disconnection_reasons, wakeup_reasons; + u32 handled_reasons, wakeup_reasons; __le16 *qos_seq = NULL; mutex_lock(&mvm->mutex); @@ -1263,13 +1273,18 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); - disconnection_reasons = - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; - if (wakeup_reasons & disconnection_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_disconnect_iter, mvm); + iwl_mvm_d0i3_wakeup_reason_iter, &data); + } out: iwl_mvm_d0i3_enable_tx(mvm, qos_seq); -- cgit v1.2.3-70-g09d2 From ecc7c518b3017821a6b26fb5fdaa548afa8ee236 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 17 Aug 2015 15:54:41 +0300 Subject: iwlwifi: mvm: fix a race in D0i3 vs. Tx path When we enter D0i3, we must stop TXing otherwise the sequence number we use might conflict with the firmware's internal TX. In order to do so, we have IWL_MVM_STATUS_IN_D0I3 which should prevent any Tx while we enter D0i3. There is a bug in this code since we may Tx even if IWL_MVM_STATUS_IN_D0I3 is set. This can happen as long as mvm->d0i3_ap_sta_id is not set. To make sure that we don't have any packet in the Tx path while we set mvm->d0i3_ap_sta_id, call synchronize_net only after we already set mvm->d0i3_ap_sta_id. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 02ce18419f20..07e68929b005 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1114,9 +1114,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); - /* make sure we have no running tx while configuring the qos */ set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); - synchronize_net(); /* * iwl_mvm_ref_sync takes a reference before checking the flag. @@ -1144,6 +1142,9 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) mvm->d0i3_offloading = false; } + /* make sure we have no running tx while configuring the seqno */ + synchronize_net(); + iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data); ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, sizeof(wowlan_config_cmd), -- cgit v1.2.3-70-g09d2 From 3a9c0a1bb82aef17468f4aff492421c875fff71c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 18 Aug 2015 10:30:42 +0200 Subject: net: hostap: convert to using IFF_NO_QUEUE Signed-off-by: Phil Sutter Cc: Jouni Malinen Signed-off-by: David S. Miller --- drivers/net/wireless/hostap/hostap_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 01de1a3bf94e..80d4228ba754 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -865,7 +865,7 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, switch(type) { case HOSTAP_INTERFACE_AP: - dev->tx_queue_len = 0; /* use main radio device queue */ + dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ dev->netdev_ops = &hostap_mgmt_netdev_ops; dev->type = ARPHRD_IEEE80211; dev->header_ops = &hostap_80211_ops; @@ -874,7 +874,7 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, dev->netdev_ops = &hostap_master_ops; break; default: - dev->tx_queue_len = 0; /* use main radio device queue */ + dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */ dev->netdev_ops = &hostap_netdev_ops; } -- cgit v1.2.3-70-g09d2 From 3db6da1f07b4ee3c0657973f504a44d38b5c04a1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 18 Aug 2015 10:30:43 +0200 Subject: net: mac80211_hwsim: convert to using IFF_NO_QUEUE Signed-off-by: Phil Sutter Cc: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index dbb46ece6f52..520bef80747f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2677,7 +2677,7 @@ static void hwsim_mon_setup(struct net_device *dev) dev->netdev_ops = &hwsim_netdev_ops; dev->destructor = free_netdev; ether_setup(dev); - dev->tx_queue_len = 0; + dev->priv_flags |= IFF_NO_QUEUE; dev->type = ARPHRD_IEEE80211_RADIOTAP; eth_zero_addr(dev->dev_addr); dev->dev_addr[0] = 0x12; -- cgit v1.2.3-70-g09d2 From f1ee2682ef8dffe6d6ec6f7788d6bf33d6bab7a6 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Thu, 9 Jul 2015 14:19:42 +0530 Subject: ath10k: ensure pktlog disable cmd reaches fw before pdev suspend Found incorrect sequence in ath10k_core_stop() where wmi pktlog disable cmd is passed from ath10k_debug_stop() to firmware immediately after wmi pdev suspend cmd. Firmware will not accept any wmi cmd after receiving wmi pdev suspend cmd. Fix this issue in ath10k_core_stop() by moving ath10k_debug_stop() just before sending pdev suspend cmd. So that pktlog disable cmd will get passed before pdev suspend cmd. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2efd4e4dd090..7e378c2fa414 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1416,13 +1416,13 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + ath10k_debug_stop(ar); /* try to suspend target */ if (ar->state != ATH10K_STATE_RESTARTING && ar->state != ATH10K_STATE_UTF) ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); - ath10k_debug_stop(ar); ath10k_hif_stop(ar); ath10k_htt_tx_free(&ar->htt); ath10k_htt_rx_free(&ar->htt); -- cgit v1.2.3-70-g09d2 From 5db879aefa0ef6dea4fdda268dd94016bc165f3d Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Thu, 9 Jul 2015 14:19:43 +0530 Subject: ath10k: free collected fw stats memory if .pull_fw_stats fails If .pull_fw_stats() fails for some reason while processing fw stats event, collected pdev/vdev/peer stats just before the failure should be freed. This is unlikely to happen, just code review catch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index f7aa1c73b481..bf033f46f8aa 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -323,7 +323,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); if (ret) { ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); - goto unlock; + goto free; } /* Stat data may exceed htc-wmi buffer limit. In such case firmware @@ -386,7 +386,6 @@ free: ath10k_debug_fw_stats_vdevs_free(&stats.vdevs); ath10k_debug_fw_stats_peers_free(&stats.peers); -unlock: spin_unlock_bh(&ar->data_lock); } -- cgit v1.2.3-70-g09d2 From 46f26ddf562e7495ffa37144be5e447aeb13795e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2015 09:46:20 +0200 Subject: ath5k: use DECLARE_EWMA This reduces code size slightly (at least on x86/64) while also removing memory consumption by two unsigned long values for each ath5k device. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/ath/ath5k/Kconfig | 1 - drivers/net/wireless/ath/ath5k/ani.c | 4 ++-- drivers/net/wireless/ath/ath5k/ath5k.h | 4 +++- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- drivers/net/wireless/ath/ath5k/debug.c | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 2399a3921762..b1278f9f24ba 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -5,7 +5,6 @@ config ATH5K select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS - select AVERAGE select ATH5K_AHB if ATH25 select ATH5K_PCI if !ATH25 ---help--- diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 5c008757662b..38be2702c0e2 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -223,7 +223,7 @@ static void ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, bool ofdm_trigger) { - int rssi = ewma_read(&ah->ah_beacon_rssi_avg); + int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "raise immunity (%s)", ofdm_trigger ? "ODFM" : "CCK"); @@ -309,7 +309,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, static void ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) { - int rssi = ewma_read(&ah->ah_beacon_rssi_avg); + int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "lower immunity"); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index e22b0e778927..fa6e89e5c421 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1252,6 +1252,8 @@ struct ath5k_statistics { #define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */ #define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */ +DECLARE_EWMA(beacon_rssi, 1024, 8) + /* Driver state associated with an instance of a device */ struct ath5k_hw { struct ath_common common; @@ -1432,7 +1434,7 @@ struct ath5k_hw { struct ath5k_nfcal_hist ah_nfcal_hist; /* average beacon RSSI in our BSS (used by ANI) */ - struct ewma ah_beacon_rssi_avg; + struct ewma_beacon_rssi ah_beacon_rssi_avg; /* noise floor from last periodic calibration */ s32 ah_noise_floor; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 23552f43d125..342563a3706f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1430,7 +1430,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, trace_ath5k_rx(ah, skb); if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { - ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); + ewma_beacon_rssi_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); /* check beacons in IBSS mode */ if (ah->opmode == NL80211_IFTYPE_ADHOC) @@ -2936,7 +2936,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ah->ah_cal_next_short = jiffies + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); - ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); + ewma_beacon_rssi_init(&ah->ah_beacon_rssi_avg); /* clear survey data and cycle counters */ memset(&ah->survey, 0, sizeof(ah->survey)); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index c70782e8f07b..654a1e33f827 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -722,7 +722,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, st->mib_intr); len += snprintf(buf + len, sizeof(buf) - len, "beacon RSSI average:\t%d\n", - (int)ewma_read(&ah->ah_beacon_rssi_avg)); + (int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg)); #define CC_PRINT(_struct, _field) \ _struct._field, \ -- cgit v1.2.3-70-g09d2 From 11ab35ed0457a4b7914358986a67064ecb467e7d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2015 09:46:21 +0200 Subject: rt2x00: use DECLARE_EWMA Instead of using the out-of-line EWMA calculation, use DECLARE_EWMA() to create static inlines. On x86/64 this results in code that's one byte larger (for me), but reduces struct link_ant and struct link size by the two unsigned long values that store the parameters each. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/rt2x00/Kconfig | 1 - drivers/net/wireless/rt2x00/rt2x00.h | 6 ++++-- drivers/net/wireless/rt2x00/rt2x00link.c | 18 ++++++------------ 3 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 2b4ef256c6b9..de62f5dcb62f 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -240,7 +240,6 @@ config RT2X00_LIB_USB config RT2X00_LIB tristate - select AVERAGE config RT2X00_LIB_FIRMWARE bool diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9bb398bed9bb..3282ddb766f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -254,6 +254,8 @@ struct link_qual { int tx_failed; }; +DECLARE_EWMA(rssi, 1024, 8) + /* * Antenna settings about the currently active link. */ @@ -285,7 +287,7 @@ struct link_ant { * Similar to the avg_rssi in the link_qual structure * this value is updated by using the walking average. */ - struct ewma rssi_ant; + struct ewma_rssi rssi_ant; }; /* @@ -314,7 +316,7 @@ struct link { /* * Currently active average RSSI value */ - struct ewma avg_rssi; + struct ewma_rssi avg_rssi; /* * Work structure for scheduling periodic link tuning. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 9b941c0c1264..017188e5a736 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -33,15 +33,11 @@ */ #define DEFAULT_RSSI -128 -/* Constants for EWMA calculations. */ -#define RT2X00_EWMA_FACTOR 1024 -#define RT2X00_EWMA_WEIGHT 8 - -static inline int rt2x00link_get_avg_rssi(struct ewma *ewma) +static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma) { unsigned long avg; - avg = ewma_read(ewma); + avg = ewma_rssi_read(ewma); if (avg) return -avg; @@ -76,8 +72,7 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) { - ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR, - RT2X00_EWMA_WEIGHT); + ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant); } static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) @@ -225,12 +220,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, /* * Update global RSSI */ - ewma_add(&link->avg_rssi, -rxdesc->rssi); + ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi); /* * Update antenna RSSI */ - ewma_add(&ant->rssi_ant, -rxdesc->rssi); + ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi); } void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) @@ -285,8 +280,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) */ rt2x00dev->link.count = 0; memset(qual, 0, sizeof(*qual)); - ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR, - RT2X00_EWMA_WEIGHT); + ewma_rssi_init(&rt2x00dev->link.avg_rssi); /* * Restore the VGC level as stored in the registers, -- cgit v1.2.3-70-g09d2 From 8e8114dee2a9a767ca8abc1c2d6a94a3ca5d4c7f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Aug 2015 11:48:21 +0300 Subject: iwlwifi: mvm: catch underflow error earlier My static checker complains that we don't check for underflows in iwl_dbgfs_fw_dbg_conf_write(). This is harmless because we have a sanity check in iwl_mvm_start_fw_dbg_conf(), but we may as well make this unsigned and silence the underflow warning. Signed-off-by: Dan Carpenter Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ca4a1f8f82a5..7d69a556bcc8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -949,9 +949,10 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret, conf_id; + unsigned int conf_id; + int ret; - ret = kstrtoint(buf, 0, &conf_id); + ret = kstrtouint(buf, 0, &conf_id); if (ret) return ret; -- cgit v1.2.3-70-g09d2 From ba537f98b5296cdb08ea98c23963201b3db14ed9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 19 Aug 2015 16:29:31 +0300 Subject: iwlwifi: mvm: update wakeup reason enum when waking from d0i3 there is a wakeup reason. Enum in driver is not up to date with FW api - fix it. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index d7658d16e965..20521bebb0b1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -339,8 +339,13 @@ enum iwl_wowlan_wakeup_reason { IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), - /* BIT(11) reserved */ + IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), + IWL_WOWLAN_WAKEUP_BY_IOAC_MAGIC_PACKET = BIT(13), + IWL_WOWLAN_WAKEUP_BY_D3_WAKEUP_HOST_TIMER = BIT(14), + IWL_WOWLAN_WAKEUP_BY_RXFRAME_FILTERED_IN = BIT(15), + IWL_WOWLAN_WAKEUP_BY_BEACON_FILTERED_IN = BIT(16), + }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ struct iwl_wowlan_gtk_status { -- cgit v1.2.3-70-g09d2 From 32c93a7057d600a06f96ff8997da1fadca65795a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2015 16:51:33 +0200 Subject: iwlwifi: correctly size command string arrays The command string array is assumed to be indexable by a full u8, so it must have 256 entries (0-255), not just 255. A recent firmware change (apparently) started using the command 0xff for a notification to the host, causing the driver to crash in debug message/tracing code. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index edc3dd42f8f8..991def878881 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -473,7 +473,7 @@ do { \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ -extern const char *const iwl_dvm_cmd_strings[REPLY_MAX]; +extern const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1]; static inline const char *iwl_dvm_get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 4785203ae203..4a45b0b594c7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -39,7 +39,7 @@ #define IWL_CMD_ENTRY(x) [x] = #x -const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { +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), diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 07e68929b005..a37de3f410a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -268,7 +268,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { #undef RX_HANDLER_GRP #define CMD(x) [x] = #x -static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { +static const char *const iwl_mvm_cmd_strings[REPLY_MAX + 1] = { CMD(MVM_ALIVE), CMD(REPLY_ERROR), CMD(INIT_COMPLETE_NOTIF), -- cgit v1.2.3-70-g09d2 From a7b3bc91c5b0a6a7eecfd33ac71e266c6fe897f8 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 20 Aug 2015 04:00:38 +0300 Subject: iwlwifi: mvm: split debug message to avoid exceeding 110 characters split long debug messages that may result warning in tracing. Fixes: 1a84e7716086 ("iwlwifi: mvm: add debug info to schedule scan complete message.") Signed-off-by: Ayala Beker Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 15055462cd11..56559d4d34ad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -349,10 +349,11 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR); - IWL_DEBUG_SCAN(mvm, - "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d\n", + IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status), + iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time after last iteration %d\n", scan_notif->last_schedule_line, scan_notif->last_schedule_iteration, __le32_to_cpu(scan_notif->time_after_last_iter)); @@ -367,10 +368,11 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR); - IWL_DEBUG_SCAN(mvm, - "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", + IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status), + iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", scan_notif->last_schedule_line, scan_notif->last_schedule_iteration, __le32_to_cpu(scan_notif->time_after_last_iter)); @@ -1346,11 +1348,13 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->scan_status &= ~mvm->scan_uid_status[uid]; IWL_DEBUG_SCAN(mvm, - "Scan completed, uid %u type %u, status %s, EBS status %s, Last line %d, Last iteration %d, Time from last iteration %d\n", + "Scan completed, uid %u type %u, status %s, EBS status %s\n", uid, mvm->scan_uid_status[uid], notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted", - iwl_mvm_ebs_status_str(notif->ebs_status), + iwl_mvm_ebs_status_str(notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time from last iteration %d\n", notif->last_schedule, notif->last_iter, __le32_to_cpu(notif->time_from_last_iter)); -- cgit v1.2.3-70-g09d2 From da03f0296c0c122cb91ed3c87a7efa4ea5127f22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Aug 2015 15:15:36 +0200 Subject: iwlwifi: mvm: support new TX power command Add support for the new (bigger) TX power command. This doesn't actually take advantage of the new capabilities (to set per-chain TX power limits) but makes the code compatible with newer firmware images expecting the larger command. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 29 +++++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 ++++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 75809abee759..84653e3d02ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -259,6 +259,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority * instead of 3. + * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size + * (command version 3) that supports per-chain limits */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3, @@ -274,6 +276,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_STATS_V10 = (__force iwl_ucode_tlv_api_t)19, IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24, + IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27, }; typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index b86b1697d56f..7005fa4be74a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.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 @@ -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 @@ -310,17 +312,22 @@ struct iwl_reduce_tx_power_cmd { __le16 pwr_restriction; } __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ +enum iwl_dev_tx_power_cmd_mode { + IWL_TX_POWER_MODE_SET_MAC = 0, + IWL_TX_POWER_MODE_SET_DEVICE = 1, + IWL_TX_POWER_MODE_SET_CHAINS = 2, +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */; + /** - * struct iwl_dev_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @set_mode: 0 - MAC tx power, 1 - device tx power + * struct iwl_dev_tx_power_cmd_v2 - TX power reduction command + * @set_mode: see &enum iwl_dev_tx_power_cmd_mode * @mac_context_id: id of the mac ctx for which we are reducing TX power. * @pwr_restriction: TX power restriction in 1/8 dBms. * @dev_24: device TX power restriction in 1/8 dBms * @dev_52_low: device TX power restriction upper band - low * @dev_52_high: device TX power restriction upper band - high */ -struct iwl_dev_tx_power_cmd { +struct iwl_dev_tx_power_cmd_v2 { __le32 set_mode; __le32 mac_context_id; __le16 pwr_restriction; @@ -329,6 +336,20 @@ struct iwl_dev_tx_power_cmd { __le16 dev_52_high; } __packed; /* TX_REDUCED_POWER_API_S_VER_2 */ +#define IWL_NUM_CHAIN_LIMITS 2 +#define IWL_NUM_SUB_BANDS 5 + +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * @v2: version 2 of the command, embedded here for easier software handling + * @per_chain_restriction: per chain restrictions + */ +struct iwl_dev_tx_power_cmd { + /* v3 is just an extension of v2 - keep this here */ + struct iwl_dev_tx_power_cmd_v2 v2; + __le16 per_chain_restriction[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS]; +} __packed; /* TX_REDUCED_POWER_API_S_VER_3 */ + #define IWL_DEV_MAX_TX_POWER 0x7FFF /** diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 537a15719d45..aa8c2b7f23c7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1595,20 +1595,23 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, s16 tx_power) { struct iwl_dev_tx_power_cmd cmd = { - .set_mode = 0, - .mac_context_id = + .v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), + .v2.mac_context_id = cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), - .pwr_restriction = cpu_to_le16(8 * tx_power), + .v2.pwr_restriction = cpu_to_le16(8 * tx_power), }; + int len = sizeof(cmd); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_DEV)) return iwl_mvm_set_tx_power_old(mvm, vif, tx_power); if (tx_power == IWL_DEFAULT_MAX_TX_POWER) - cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); - return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, - sizeof(cmd), &cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN)) + len = sizeof(cmd.v2); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, -- cgit v1.2.3-70-g09d2 From 5865f3658ba37c54e346b0fdee08a1c7a152681b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 23 Aug 2015 12:54:16 +0300 Subject: iwlwifi: mvm: bump firmware API to 17 The driver is now able to handle -17.ucode. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 413b63e09717..6951aba620eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 16 +#define IWL7260_UCODE_API_MAX 17 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 12 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 8324bc8987a9..197abe43ddc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 16 +#define IWL8000_UCODE_API_MAX 17 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 12 -- cgit v1.2.3-70-g09d2 From 14250640cd52bf12831799c35502184c4ae8963b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 14 Aug 2015 07:16:39 +0200 Subject: ath9k_htc: do ani shortcalibratio if we got -ETIMEDOUT current code will handle -ETIMEDOUT as success which is probalbly wrong. According to this comment I assume it is safe to handle -ETIMEDOUT as false: drivers/net/wireless/ath/ath9k/calib.c 290 /* 291 * We timed out waiting for the noisefloor to load, probably due to an 292 * in-progress rx. Simply return here and allow the load plenty of time 293 * to complete before the next calibration interval. We need to avoid 294 * trying to load -50 (which happens below) while the previous load is 295 * still in progress as this can cause rx deafness. Instead by returning 296 * here, the baseband nf cal will just be capped by our present 297 * noisefloor until the next calibration timer. 298 */ Since no other error wariants are present, this patch is checking only for (ret <= 0). Reported-by: Dan Carpenter Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index dab1323dfec7..172a9ff4aaab 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -794,8 +794,11 @@ void ath9k_htc_ani_work(struct work_struct *work) common->ani.longcal_timer = timestamp; } - /* Short calibration applies only while caldone is false */ - if (!common->ani.caldone) { + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) { if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; @@ -844,7 +847,11 @@ set_timer: */ cal_interval = ATH_LONG_CALINTERVAL; cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!common->ani.caldone) + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) cal_interval = min(cal_interval, (u32)short_cal_interval); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, -- cgit v1.2.3-70-g09d2 From 12ff7288bfed9d6d62186f0dd782b7b5a43670cd Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 15 Aug 2015 18:36:37 +0800 Subject: rtlwifi: rtl8192ee: fix semicolon.cocci warnings drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:856:2-3: Unneeded semicolon drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:492:3-4: Unneeded semicolon drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:452:3-4: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Larry Finger Signed-off-by: Fengguang Wu Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c index a863a44f9e16..018340aedf09 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c @@ -449,7 +449,7 @@ static void _rtl92ee_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw, "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n", rate_section, path, txnum); break; - }; + } } else { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Invalid Band %d\n", band); @@ -489,7 +489,7 @@ static u8 _rtl92ee_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw, "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n", rate_section, path, txnum); break; - }; + } } else { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Invalid Band %d()\n", band); @@ -853,7 +853,7 @@ static u8 _rtl92ee_get_rate_section_index(u32 regaddr) else if (regaddr >= 0xE20 && regaddr <= 0xE4C) index = (u8)((regaddr - 0xE20) / 4); break; - }; + } return index; } -- cgit v1.2.3-70-g09d2 From 1642d09fb9b128e8e538b2a4179962a34f38dff9 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Wed, 19 Aug 2015 17:33:12 +0200 Subject: rtlwifi: rtl8192cu: Add new device ID The v2 of NetGear WNA1000M uses a different idProduct: USB ID 0846:9043 Signed-off-by: Adrien Schildknecht Cc: Stable Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 23806c243a53..fd4a5353d216 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -321,6 +321,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/ {RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ -- cgit v1.2.3-70-g09d2 From 50f32e2d1044b1f1658a1e40c8831969a30ca6a1 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 20 Aug 2015 00:16:42 +0200 Subject: brcmfmac: check all combinations when setting wiphy's addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom is working on better reflection of interface combinations. With upcoming patches we may have 1st combination supporting less interfaces than others. To don't run out of addresses check all combinations to find the one with the greatest max_interfaces value. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index ffe526070d6f..c85e2db75f1d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5786,7 +5786,9 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; + const struct ieee80211_iface_combination *combo; struct ieee80211_supported_band *band; + u16 max_interfaces = 0; __le32 bandlist[3]; u32 n_bands; int err, i; @@ -5799,8 +5801,13 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) if (err) return err; - for (i = 0; i < wiphy->iface_combinations->max_interfaces && - i < ARRAY_SIZE(drvr->addresses); i++) { + for (i = 0, combo = wiphy->iface_combinations; + i < wiphy->n_iface_combinations; i++, combo++) { + max_interfaces = max(max_interfaces, combo->max_interfaces); + } + + for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses); + i++) { u8 *addr = drvr->addresses[i].addr; memcpy(addr, drvr->mac, ETH_ALEN); -- cgit v1.2.3-70-g09d2 From 0882dda3bcbb51e63c2fd25705ec8541bf86378e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:03 +0200 Subject: brcmfmac: correct interface combination info The interface combination provided by brcmfmac did not truly reflect the combinations supported by driver and/or firmware. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Pontus Fuchs Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 151 +++++++++++++++------ 1 file changed, 112 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index c85e2db75f1d..26e1fe8c132c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5695,63 +5695,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { } }; +/** + * brcmf_setup_ifmodes() - determine interface modes and combinations. + * + * @wiphy: wiphy object. + * @ifp: interface object needed for feat module api. + * + * The interface modes and combinations are determined dynamically here + * based on firmware functionality. + * + * no p2p and no mbss: + * + * #STA <= 1, #AP <= 1, channels = 1, 2 total + * + * no p2p and mbss: + * + * #STA <= 1, #AP <= 1, channels = 1, 2 total + * #AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, no mchan, and mbss: + * + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + * #AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, mchan, and mbss: + * + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + * #AP <= 4, matching BI, channels = 1, 4 total + */ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) { struct ieee80211_iface_combination *combo = NULL; - struct ieee80211_iface_limit *limits = NULL; - int i = 0, max_iface_cnt; + struct ieee80211_iface_limit *c0_limits = NULL; + struct ieee80211_iface_limit *p2p_limits = NULL; + struct ieee80211_iface_limit *mbss_limits = NULL; + bool mbss, p2p; + int i, c, n_combos; + + mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); + p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); - combo = kzalloc(sizeof(*combo), GFP_KERNEL); + n_combos = 1 + !!p2p + !!mbss; + combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL); if (!combo) goto err; - limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL); - if (!limits) + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); + if (!c0_limits) goto err; + if (p2p) { + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); + if (!p2p_limits) + goto err; + } + + if (mbss) { + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); + if (!mbss_limits) + goto err; + } + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - combo->num_different_channels = 2; - else - combo->num_different_channels = 1; - - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_STATION); - limits[i].max = 4; - limits[i++].types = BIT(NL80211_IFTYPE_AP); - max_iface_cnt = 5; - } else { - limits[i].max = 2; - limits[i++].types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); - max_iface_cnt = 2; - } - - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) { + c = 0; + i = 0; + combo[c].num_different_channels = 1; + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); + if (p2p) { + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) + combo[c].num_different_channels = 2; wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); - max_iface_cnt += 2; - } - combo->max_interfaces = max_iface_cnt; - combo->limits = limits; - combo->n_limits = i; - + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + } else { + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); + } + combo[c].max_interfaces = i; + combo[c].n_limits = i; + combo[c].limits = c0_limits; + + if (p2p) { + c++; + i = 0; + combo[c].num_different_channels = 1; + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + combo[c].max_interfaces = i; + combo[c].n_limits = i; + combo[c].limits = p2p_limits; + } + + if (mbss) { + c++; + combo[c].beacon_int_infra_match = true; + combo[c].num_different_channels = 1; + mbss_limits[0].max = 4; + mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); + combo[c].max_interfaces = 4; + combo[c].n_limits = 1; + combo[c].limits = mbss_limits; + } + wiphy->n_iface_combinations = n_combos; wiphy->iface_combinations = combo; - wiphy->n_iface_combinations = 1; return 0; err: - kfree(limits); + kfree(c0_limits); + kfree(p2p_limits); + kfree(mbss_limits); kfree(combo); return -ENOMEM; } @@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, static void brcmf_free_wiphy(struct wiphy *wiphy) { + int i; + if (!wiphy) return; - if (wiphy->iface_combinations) - kfree(wiphy->iface_combinations->limits); + if (wiphy->iface_combinations) { + for (i = 0; i < wiphy->n_iface_combinations; i++) + kfree(wiphy->iface_combinations[i].limits); + } kfree(wiphy->iface_combinations); if (wiphy->bands[IEEE80211_BAND_2GHZ]) { kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); -- cgit v1.2.3-70-g09d2 From 2bb66a8183d6396babde51e558b1ab35733f275f Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 20 Aug 2015 22:06:04 +0200 Subject: brcmfmac: add debugfs entry for msgbuf statistics Expose ring buffer read/write pointers and other useful statistics through debugfs. Reviewed-by: Arend Van Spriel Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 898c3801e658..7b2136c9badb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) } } +#ifdef DEBUG +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_commonring *commonring; + u16 i; + struct brcmf_flowring_ring *ring; + struct brcmf_flowring_hash *hash; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT]; + seq_printf(seq, "h2d_rx_submit: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE]; + seq_printf(seq, "d2h_ctl_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE]; + seq_printf(seq, "d2h_tx_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; + seq_printf(seq, "d2h_rx_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + + seq_printf(seq, "\nh2d_flowrings: depth %u\n", + BRCMF_H2D_TXFLOWRING_MAX_ITEM); + seq_puts(seq, "Active flowrings:\n"); + hash = msgbuf->flow->hash; + for (i = 0; i < msgbuf->flow->nrofrings; i++) { + if (!msgbuf->flow->rings[i]) + continue; + ring = msgbuf->flow->rings[i]; + if (ring->status != RING_OPEN) + continue; + commonring = msgbuf->flowrings[i]; + hash = &msgbuf->flow->hash[ring->hash_id]; + seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n" + " ifidx %u, fifo %u, da %pM\n", + i, commonring->r_ptr, commonring->w_ptr, + skb_queue_len(&ring->skblist), ring->blocked, + hash->ifidx, hash->fifo, hash->mac); + } + + return 0; +} +#else +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ + return 0; +} +#endif int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) { @@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) spin_lock_init(&msgbuf->flowring_work_lock); INIT_LIST_HEAD(&msgbuf->work_queue); + brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); + return 0; fail: -- cgit v1.2.3-70-g09d2 From 39504a2d21adde4748b5ce8c057e09edf3fe17bb Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:05 +0200 Subject: brcmfmac: make use of cfg80211_check_combinations() Use cfg80211_check_combinations() so we can bail out early when an interface add or change results in an invalid combination. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 44 +++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 26e1fe8c132c..a293275c1b0b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 len) return NULL; } +static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif, + enum nl80211_iftype new_type) +{ + int iftype_num[NUM_NL80211_IFTYPES]; + struct brcmf_cfg80211_vif *pos; + + memset(&iftype_num[0], 0, sizeof(iftype_num)); + list_for_each_entry(pos, &cfg->vif_list, list) + if (pos == vif) + iftype_num[new_type]++; + else + iftype_num[pos->wdev.iftype]++; + + return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +} + +static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, + enum nl80211_iftype new_type) +{ + int iftype_num[NUM_NL80211_IFTYPES]; + struct brcmf_cfg80211_vif *pos; + + memset(&iftype_num[0], 0, sizeof(iftype_num)); + list_for_each_entry(pos, &cfg->vif_list, list) + iftype_num[pos->wdev.iftype]++; + + iftype_num[new_type]++; + return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +} static void convert_key_from_CPU(struct brcmf_wsec_key *key, struct brcmf_wsec_key_le *key_le) @@ -663,8 +693,14 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, struct vif_params *params) { struct wireless_dev *wdev; + int err; brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); + err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); + if (err) { + brcmf_err("iface validation failed: err=%d\n", err); + return ERR_PTR(err); + } switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: @@ -823,8 +859,12 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, s32 ap = 0; s32 err = 0; - brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type); - + brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type); + err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type); + if (err) { + brcmf_err("iface validation failed: err=%d\n", err); + return err; + } switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: -- cgit v1.2.3-70-g09d2 From b02bf1932a4855dc860ed20cdab94f1ea9b1c56f Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 20 Aug 2015 22:06:06 +0200 Subject: brcmfmac: block the correct flowring when backup queue overflow brcmf_flowring_block blocks the last active flowring under the same interface instead of the one provided by caller. This could lead to a dead lock of netif stop if there are more than one flowring under the interface and the traffic is high enough so brcmf_flowring_enqueue can not unblock the ring right away. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 59440631fec5..8d1ab4ab5be8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, spin_lock_irqsave(&flow->block_lock, flags); ring = flow->rings[flowid]; + if (ring->blocked == blocked) { + spin_unlock_irqrestore(&flow->block_lock, flags); + return; + } ifidx = brcmf_flowring_ifidx_get(flow, flowid); currently_blocked = false; for (i = 0; i < flow->nrofrings; i++) { - if (flow->rings[i]) { + if ((flow->rings[i]) && (i != flowid)) { ring = flow->rings[i]; if ((ring->status == RING_OPEN) && (brcmf_flowring_ifidx_get(flow, i) == ifidx)) { @@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, } } } - ring->blocked = blocked; - if (currently_blocked == blocked) { + flow->rings[flowid]->blocked = blocked; + if (currently_blocked) { spin_unlock_irqrestore(&flow->block_lock, flags); return; } -- cgit v1.2.3-70-g09d2 From fc7c3ad5251cf76fc78b7f4701e35a0af6375335 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:07 +0200 Subject: brcmfmac: bump highest event number for 4339 firmware The event mask length is determined by the highest event number that is specified in the driver. When this length is shorter than firmware expects setting event mask will fail and device becomes pretty useless. This issue was reported with bcm4339 firmware that was recently released. Reported-by: Pontus Fuchs Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Pontus Fuchs Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/fweh.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index cbf033f59109..1326898d608e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -85,7 +85,6 @@ struct brcmf_event; BRCMF_ENUM_DEF(IF, 54) \ BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ BRCMF_ENUM_DEF(RSSI, 56) \ - BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ BRCMF_ENUM_DEF(ACTION_FRAME, 59) \ BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \ @@ -103,8 +102,7 @@ struct brcmf_event; BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ - BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ - BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128) + BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) #define BRCMF_ENUM_DEF(id, val) \ BRCMF_E_##id = (val), @@ -112,7 +110,11 @@ struct brcmf_event; /* firmware event codes sent by the dongle */ enum brcmf_fweh_event_code { BRCMF_FWEH_EVENT_ENUM_DEFLIST - BRCMF_E_LAST + /* this determines event mask length which must match + * minimum length check in device firmware so it is + * hard-coded here. + */ + BRCMF_E_LAST = 139 }; #undef BRCMF_ENUM_DEF -- cgit v1.2.3-70-g09d2 From 4e70f2144db01f7214ed5846e47abf128fbfb5af Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Thu, 20 Aug 2015 22:06:08 +0200 Subject: brcmfmac: Add support for host platform NVRAM loading. Host platforms such as routers supported by OpenWRT can support NVRAM reading directly from internal NVRAM store. With this patch the nvram load routines will fall back to this method when there is no nvram file and support is available in the kernel. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/firmware.c | 39 +++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 743f16b6a072..971920f77b68 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "debug.h" #include "firmware.h" @@ -426,18 +427,32 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) struct brcmf_fw *fwctx = ctx; u32 nvram_length = 0; void *nvram = NULL; + u8 *data = NULL; + size_t data_len; + bool raw_nvram; brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); - if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) - goto fail; + if (fw && fw->data) { + data = (u8 *)fw->data; + data_len = fw->size; + raw_nvram = false; + } else { + data = bcm47xx_nvram_get_contents(&data_len); + if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; + raw_nvram = true; + } - if (fw) { - nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length, + if (data) + nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, fwctx->domain_nr, fwctx->bus_nr); + + if (raw_nvram) + bcm47xx_nvram_release_contents(data); + if (fw) release_firmware(fw); - if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) - goto fail; - } + if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length); kfree(fwctx); @@ -473,15 +488,9 @@ static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx) if (!ret) return; - /* when nvram is optional call .done() callback here */ - if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) { - fwctx->done(fwctx->dev, fw, NULL, 0); - kfree(fwctx); - return; - } + brcmf_fw_request_nvram_done(NULL, fwctx); + return; - /* failed nvram request */ - release_firmware(fw); fail: brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); device_release_driver(fwctx->dev); -- cgit v1.2.3-70-g09d2 From a8b9774571d46506a0774b1ced3493b1245cf893 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Fri, 21 Aug 2015 23:14:26 +0200 Subject: rsi: Fix possible leak when loading firmware Commit 5d5cd85ff441 ("rsi: Fix failure to load firmware after memory leak fix and fix the leak") also added a check on the allocation of DMA-accessible memory that may directly return. In that case the already allocated firmware data is leaked. Make sure the data is always freed correctly. Detected by Coverity CID 1316519. Fixes: 5d5cd85ff441 ("rsi: Fix failure to load firmware after memory leak fix and fix the leak") Signed-off-by: Christian Engelmayer Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 8 ++++++-- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 1c6788aecc62..40d72312f3df 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -203,8 +203,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) - return -ENOMEM; + if (!fw) { + status = -ENOMEM; + goto out; + } len = fw_entry->size; if (len % 4) @@ -217,6 +219,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) status = rsi_copy_to_card(common, fw, len, num_blocks); kfree(fw); + +out: release_firmware(fw_entry); return status; } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 30c2cf7fa93b..de4900862836 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -148,8 +148,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) - return -ENOMEM; + if (!fw) { + status = -ENOMEM; + goto out; + } len = fw_entry->size; if (len % 4) @@ -162,6 +164,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) status = rsi_copy_to_card(common, fw, len, num_blocks); kfree(fw); + +out: release_firmware(fw_entry); return status; } -- cgit v1.2.3-70-g09d2 From 503422d95248c1d9698735bb5803b70aa51b18ef Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 19 Aug 2015 13:08:53 +0200 Subject: ath10k: add missing mutex unlock on failpath Kernel would complain about leaving a held lock after going back to userspace and would subsequently deadlock. Fixes: e04cafbc38c7 ("ath10k: fix peer limit enforcement") Reported-by: Dan Carpenter Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9bca37820848..64674c955d44 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4144,7 +4144,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (ar->num_peers >= ar->max_num_peers) { ath10k_warn(ar, "refusing vdev creation due to insufficient peer entry resources in firmware\n"); - return -ENOBUFS; + ret = -ENOBUFS; + goto err; } if (ar->free_vdev_map == 0) { -- cgit v1.2.3-70-g09d2 From 5e55e3cbd1042cffa6249f22c10585e63f8a29bf Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 19 Aug 2015 13:10:43 +0200 Subject: ath10k: fix dma_mapping_error() handling The function returns 1 when DMA mapping fails. The driver would return bogus values and could possibly confuse itself if DMA failed. Fixes: 767d34fc67af ("ath10k: remove DMA mapping wrappers") Reported-by: Dan Carpenter Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 4 +++- drivers/net/wireless/ath/ath10k/htt_tx.c | 8 ++++++-- drivers/net/wireless/ath/ath10k/pci.c | 8 ++++++-- drivers/net/wireless/ath/ath10k/wmi.c | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 85bfa2acb801..32d9ff1b19dc 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -145,8 +145,10 @@ int ath10k_htc_send(struct ath10k_htc *htc, skb_cb->eid = eid; skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); ret = dma_mapping_error(dev, skb_cb->paddr); - if (ret) + if (ret) { + ret = -EIO; goto err_credits; + } sg_item.transfer_id = ep->eid; sg_item.transfer_context = skb; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 704bb5e07193..43aa5e2d1b87 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -442,8 +442,10 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); - if (res) + if (res) { + res = -EIO; goto err_free_txdesc; + } skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; @@ -533,8 +535,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); - if (res) + if (res) { + res = -EIO; goto err_free_txbuf; + } switch (skb_cb->txmode) { case ATH10K_HW_TXRX_RAW: diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index f00b251ec9ce..826220f795c7 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1667,8 +1667,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, req_paddr = dma_map_single(ar->dev, treq, req_len, DMA_TO_DEVICE); ret = dma_mapping_error(ar->dev, req_paddr); - if (ret) + if (ret) { + ret = -EIO; goto err_dma; + } if (resp && resp_len) { tresp = kzalloc(*resp_len, GFP_KERNEL); @@ -1680,8 +1682,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, resp_paddr = dma_map_single(ar->dev, tresp, *resp_len, DMA_FROM_DEVICE); ret = dma_mapping_error(ar->dev, resp_paddr); - if (ret) + if (ret) { + ret = EIO; goto err_req; + } xfer.wait_for_resp = true; xfer.resp_len = 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 42c0aba04fb2..6ac016dc28f8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3238,6 +3238,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_warn(ar, "failed to map beacon: %d\n", ret); dev_kfree_skb_any(bcn); + ret = -EIO; goto skip; } -- cgit v1.2.3-70-g09d2 From 4535edbd4214ce21328655434c0b75da404e29b7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Thu, 20 Aug 2015 10:29:05 +0530 Subject: ath10k: add spectral scan support for 10.4 fw To enable/configure spectral scan parameters in 10.4 firmware, existing wmi spectral related functions can be reused. Link those functions in 10.4 wmi ops table. In addition, adjust bin size (only when size is 68 bytes) before reporting bin samples to user space. The background for this adjustment is that qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in report mode 2. First 64 bytes carries in-band tones (-32 to +31) and last 4 byte carries band edge detection data (+32) mainly used in radar detection purpose. Additional last 4 bytes are stripped to make bin size valid one. This bin size adjustment will happen only for qca99x0, all other chipsets will report proper bin sizes (64/128) without extra 4 bytes being added at the end. The changes are validated in qca99x0 using 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/spectral.c | 9 +++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++ 2 files changed, 11 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index e4219b1bbdce..4671cfbcd8f7 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -73,6 +73,15 @@ int ath10k_spectral_process_fft(struct ath10k *ar, if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS) return -EINVAL; + /* qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in + * report mode 2. First 64 bytes carries inband tones (-32 to +31) + * and last 4 byte carries band edge detection data (+32) mainly + * used in radar detection purpose. Strip last 4 byte to make bin + * size is valid one. + */ + if (bin_len == 68) + bin_len -= 4; + reg0 = __le32_to_cpu(fftr->reg0); reg1 = __le32_to_cpu(fftr->reg1); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6ac016dc28f8..7f8fa636b95a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6582,6 +6582,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, .gen_peer_create = ath10k_wmi_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, -- cgit v1.2.3-70-g09d2 From 36582e5d4daeccf68a8a3cef9bc37b60fb7d45b9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 13 Aug 2015 14:32:26 +0200 Subject: ath10k: add qca6164 support This adds additional 0x0041 PCI Device ID definition to ath10k for QCA6164 which is a 1 spatial stream sibling of the QCA6174 (which is 2 spatial stream chip). The QCA6164 needs a dedicated board.bin file which is different than the one used for QCA6174. If the board.bin is wrong the device will crash early while trying to boot firmware. The register dump will look like this: ath10k_pci 0000:02:00.0: firmware register dump: ath10k_pci 0000:02:00.0: [00]: 0x05010000 0x000015B3 0x000A012D 0x00955B31 ... Note the value 0x000A012D. Special credit goes to Alan Liu for providing support help which enabled me to come up with this patch. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 13 +++++++++++++ 3 files changed, 25 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7e378c2fa414..b87b98617073 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -236,6 +236,17 @@ static int ath10k_init_configure_target(struct ath10k *ar) return ret; } + /* Some devices have a special sanity check that verifies the PCI + * Device ID is written to this host interest var. It is known to be + * required to boot QCA6164. + */ + ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext, + ar->dev_id); + if (ret) { + ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret); + return ret; + } + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 862f6d0fac57..12542144fe12 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -554,6 +554,7 @@ struct ath10k { u8 mac_addr[ETH_ALEN]; enum ath10k_hw_rev hw_rev; + u16 dev_id; u32 chip_id; u32 target_version; u8 fw_version_major; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 826220f795c7..1046ab65b9ab 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,11 +58,13 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 #define QCA988X_2_0_DEVICE_ID (0x003c) +#define QCA6164_2_1_DEVICE_ID (0x0041) #define QCA6174_2_1_DEVICE_ID (0x003e) #define QCA99X0_2_0_DEVICE_ID (0x0040) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ + { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ {0} @@ -74,11 +76,19 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { * because of that. */ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, + + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, }; @@ -1814,6 +1824,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) case QCA988X_2_0_DEVICE_ID: case QCA99X0_2_0_DEVICE_ID: return 1; + case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { case QCA6174_HW_1_0_CHIP_ID_REV: @@ -2902,6 +2913,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; break; + case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; break; @@ -2926,6 +2938,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->pdev = pdev; ar_pci->dev = &pdev->dev; ar_pci->ar = ar; + ar->dev_id = pci_dev->device; if (pdev->subsystem_vendor || pdev->subsystem_device) scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id), -- cgit v1.2.3-70-g09d2 From ee92a2099f79d47e1d6d4857ab308f5b15a00549 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 21 Aug 2015 18:42:36 +0530 Subject: ath10k: fix compilation warnings in wmi phyerr pull function Below compilation warnings are observed in gcc version 4.8.2. Even though it's not seen in bit older gcc versions (for ex, 4.7.3), It's good to fix it by changing format specifier from %d to %zd in wmi pull phyerr functions. wmi.c: In function 'ath10k_wmi_op_pull_phyerr_ev': wmi.c:3567:8: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=] left_len, sizeof(*phyerr)); ^ wmi.c: In function 'ath10k_wmi_10_4_op_pull_phyerr_ev': wmi.c:3612:8: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=] left_len, sizeof(*phyerr)); ^ Fixes: 991adf71a6cd ("ath10k: refactor phyerr event handlers") Fixes: 2b0a2e0d7c2f ("ath10k: handle 10.4 firmware phyerr event") Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7f8fa636b95a..ce01107ef37a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3564,7 +3564,7 @@ int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, int i; if (left_len < sizeof(*phyerr)) { - ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", left_len, sizeof(*phyerr)); return -EINVAL; } @@ -3609,7 +3609,7 @@ static int ath10k_wmi_10_4_op_pull_phyerr_ev(struct ath10k *ar, int i; if (left_len < sizeof(*phyerr)) { - ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", left_len, sizeof(*phyerr)); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From a202fbbf56e819de83876827c4bf5da2bfbac5ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:48 -0700 Subject: drivers/net/wireless/ath/wil6210: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. Signed-off-by: Andy Shevchenko Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Helge Deller Cc: Ingo Tuchscherer Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/wireless/ath/wil6210/debugfs.c | 35 ++++++------------------------ 1 file changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 613ca2b2527b..d1a1e160ef31 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -156,6 +156,12 @@ static const struct file_operations fops_vring = { .llseek = seq_lseek, }; +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, + const char *prefix) +{ + seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false); +} + static void wil_print_ring(struct seq_file *s, const char *prefix, void __iomem *off) { @@ -212,8 +218,6 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); if (len <= MAX_MBOXITEM_SIZE) { - int n = 0; - char printbuf[16 * 3 + 2]; unsigned char databuf[MAX_MBOXITEM_SIZE]; void __iomem *src = wmi_buffer(wil, d.addr) + sizeof(struct wil6210_mbox_hdr); @@ -223,16 +227,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, * reading header */ wil_memcpy_fromio_32(databuf, src, len); - while (n < len) { - int l = min(len - n, 16); - - hex_dump_to_buffer(databuf + n, l, - 16, 1, printbuf, - sizeof(printbuf), - false); - seq_printf(s, " : %s\n", printbuf); - n += l; - } + wil_seq_hexdump(s, databuf, len, " : "); } } else { seq_puts(s, "\n"); @@ -867,22 +862,6 @@ static const struct file_operations fops_wmi = { .open = simple_open, }; -static void wil_seq_hexdump(struct seq_file *s, void *p, int len, - const char *prefix) -{ - char printbuf[16 * 3 + 2]; - int i = 0; - - while (i < len) { - int l = min(len - i, 16); - - hex_dump_to_buffer(p + i, l, 16, 1, printbuf, - sizeof(printbuf), false); - seq_printf(s, "%s%s\n", prefix, printbuf); - i += l; - } -} - static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) { int i = 0; -- cgit v1.2.3-70-g09d2