diff options
author | David S. Miller <davem@davemloft.net> | 2015-06-23 01:03:18 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-06-23 01:03:18 -0700 |
commit | fa433354f042105fc7a299253f904bb48dae0950 (patch) | |
tree | 7dc747d4f994713699a37080b0774f8315a1e1ef | |
parent | 10ea5165e44ec8467e393a84ecfbf5732605d504 (diff) | |
parent | 40b503c76481aecf811a29a14a80c13b429b5e14 (diff) | |
download | linux-stable-fa433354f042105fc7a299253f904bb48dae0950.tar.gz linux-stable-fa433354f042105fc7a299253f904bb48dae0950.tar.bz2 linux-stable-fa433354f042105fc7a299253f904bb48dae0950.zip |
Merge tag 'wireless-drivers-next-for-davem-2015-06-18' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
Major changes:
mwifiex:
* enhancements for AP mode: support verbose information in station
dump command and also information about AP link.
* enable power save by default
brcmfmac:
* fix module reload issue for PCIe
* improving msgbuf protocol for PCIe devices
* rework .get_station() cfg80211 callback operation
* determine interface combinations upon device feature support
ath9k:
* ath9k_htc: add support of channel switch
wil6210:
* add modparam for bcast ring size
* support hidden SSID
* add per-MCS Rx stats
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
86 files changed, 1740 insertions, 902 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index a7d9bfe04c6b..2e122946692c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8169,8 +8169,6 @@ P: rt2x00 project M: Stanislaw Gruszka <sgruszka@redhat.com> M: Helmut Schaa <helmut.schaa@googlemail.com> L: linux-wireless@vger.kernel.org -L: users@rt2x00.serialmonkey.com (moderated for non-subscribers) -W: http://rt2x00.serialmonkey.com/ S: Maintained F: drivers/net/wireless/rt2x00/ diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index fc6ffcfa8061..be5fffb6da24 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -29,12 +29,6 @@ config BCMA_HOST_PCI select BCMA_DRIVER_PCI default y -config BCMA_DRIVER_PCI_HOSTMODE - bool "Driver for PCI core working in hostmode" - depends on BCMA && MIPS && BCMA_HOST_PCI - help - PCI core hostmode operation (external PCI bus). - config BCMA_HOST_SOC bool "Support for BCMA in a SoC" depends on BCMA @@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI This driver is also prerequisite for a hostmode PCIe core support. +config BCMA_DRIVER_PCI_HOSTMODE + bool "Driver for PCI core working in hostmode" + depends on BCMA && MIPS && BCMA_DRIVER_PCI + help + PCI core hostmode operation (external PCI bus). + config BCMA_DRIVER_MIPS bool "BCMA Broadcom MIPS core driver" depends on BCMA && MIPS diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bcccae19325d..59496a90ad5e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .has_shifted_cc_wraparound = true, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -1084,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) if (status) goto err; + /* Some of of qca988x solutions are having global reset issue + * during target initialization. Bypassing PLL setting before + * downloading firmware and letting the SoC run on REF_CLK is + * fixing the problem. Corresponding firmware change is also needed + * to set the clock source once the target is initialized. + */ + if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, + ar->fw_features)) { + status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); + if (status) { + ath10k_err(ar, "could not write to skip_clock_init: %d\n", + status); + goto err; + } + } + status = ath10k_download_fw(ar, mode); if (status) goto err; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 70fcdc9c2758..78094f23c9dd 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -284,15 +284,6 @@ struct ath10k_sta { #endif }; -struct ath10k_chanctx { - /* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally - * mac80211 should allow some sort of explicit locking to guarantee - * that the publicly available chanctx_conf can be accessed safely at - * all times. - */ - struct ieee80211_chanctx_conf conf; -}; - #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) enum ath10k_beacon_state { @@ -468,6 +459,9 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, + /* Firmware supports bypassing PLL setting on init. */ + ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -577,6 +571,13 @@ struct ath10k { u32 patch_load_addr; int uart_pin; + /* This is true if given HW chip has a quirky Cycle Counter + * wraparound which resets to 0x7fffffff instead of 0. All + * other CC related counters (e.g. Rx Clear Count) are divided + * by 2 so they never wraparound themselves. + */ + bool has_shifted_cc_wraparound; + struct ath10k_hw_params_fw { const char *dir; const char *fw; @@ -694,6 +695,14 @@ struct ath10k { u32 survey_last_cycle_count; struct survey_info survey[ATH10K_NUM_CHANS]; + /* Channel info events are expected to come in pairs without and with + * COMPLETE flag set respectively for each channel visit during scan. + * + * However there are deviations from this rule. This flag is used to + * avoid reporting garbage data. + */ + bool ch_info_can_report_survey; + struct dfs_pattern_detector *dfs_detector; unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */ diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 839a8791fb9e..5997f00afe3b 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -15,6 +15,7 @@ */ #include <linux/types.h> +#include "core.h" #include "hw.h" const struct ath10k_hw_regs qca988x_regs = { @@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_chip_id_address = 0x000f0, .scratch_3_address = 0x0028, }; + +void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, + u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) +{ + u32 cc_fix = 0; + + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; + + if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) { + cc_fix = 0x7fffffff; + survey->filled &= ~SURVEY_INFO_TIME_BUSY; + } + + cc -= cc_prev - cc_fix; + rcc -= rcc_prev; + + survey->time = CCNT_TO_MSEC(cc); + survey->time_busy = CCNT_TO_MSEC(rcc); +} diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 89e09cbeac19..85cca29375fe 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -169,6 +169,9 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +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) @@ -449,6 +452,9 @@ 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) + /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_IND_EVENT_PENDING 1 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 609ca8619ebd..218b6af63447 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3949,83 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } -static void ath10k_mac_chan_reconfigure(struct ath10k *ar) -{ - struct ath10k_vif *arvif; - struct cfg80211_chan_def def; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chan reconfigure\n"); - - /* First stop monitor interface. Some FW versions crash if there's a - * lone monitor interface. */ - if (ar->monitor_started) - ath10k_monitor_stop(ar); - - list_for_each_entry(arvif, &ar->arvifs, list) { - if (!arvif->is_started) - continue; - - if (!arvif->is_up) - continue; - - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - continue; - - ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath10k_warn(ar, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } - } - - /* all vdevs are downed now - attempt to restart and re-up them */ - - list_for_each_entry(arvif, &ar->arvifs, list) { - if (!arvif->is_started) - continue; - - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - continue; - - ret = ath10k_mac_setup_bcn_tmpl(arvif); - if (ret) - ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", - ret); - - ret = ath10k_mac_setup_prb_tmpl(arvif); - if (ret) - ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", - ret); - - if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) - continue; - - ret = ath10k_vdev_restart(arvif, &def); - if (ret) { - ath10k_warn(ar, "failed to restart vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } - - if (!arvif->is_up) - continue; - - ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, - arvif->bssid); - if (ret) { - ath10k_warn(ar, "failed to bring vdev up %d: %d\n", - arvif->vdev_id, ret); - continue; - } - } - - ath10k_monitor_recalc(ar); -} - static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) { int ret; @@ -6144,7 +6067,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw, } static void -ath10k_mac_update_rx_channel(struct ath10k *ar) +ath10k_mac_update_rx_channel(struct ath10k *ar, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs) { struct cfg80211_chan_def *def = NULL; @@ -6154,6 +6080,9 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->data_lock); + WARN_ON(ctx && vifs); + WARN_ON(vifs && n_vifs != 1); + /* FIXME: Sort of an optimization and a workaround. Peers and vifs are * on a linked list now. Doing a lookup peer -> vif -> chanctx for each * ppdu on Rx may reduce performance on low-end systems. It should be @@ -6165,36 +6094,28 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) * affected much. */ rcu_read_lock(); - if (ath10k_mac_num_chanctxs(ar) == 1) { + if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { ieee80211_iter_chan_contexts_atomic(ar->hw, ath10k_mac_get_any_chandef_iter, &def); + + if (vifs) + def = &vifs[0].new_ctx->def; + ar->rx_channel = def->chan; + } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) { + ar->rx_channel = ctx->def.chan; } else { ar->rx_channel = NULL; } rcu_read_unlock(); } -static void -ath10k_mac_chan_ctx_init(struct ath10k *ar, - struct ath10k_chanctx *arctx, - struct ieee80211_chanctx_conf *conf) -{ - lockdep_assert_held(&ar->conf_mutex); - lockdep_assert_held(&ar->data_lock); - - memset(arctx, 0, sizeof(*arctx)); - - arctx->conf = *conf; -} - static int ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; - struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx add freq %hu width %d ptr %p\n", @@ -6203,8 +6124,7 @@ ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); - ath10k_mac_chan_ctx_init(ar, arctx, ctx); - ath10k_mac_update_rx_channel(ar); + ath10k_mac_update_rx_channel(ar, ctx, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); @@ -6228,7 +6148,7 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); - ath10k_mac_update_rx_channel(ar); + ath10k_mac_update_rx_channel(ar, NULL, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); @@ -6243,16 +6163,12 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; - struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; mutex_lock(&ar->conf_mutex); ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac chanctx change freq %hu->%hu width %d->%d ptr %p changed %x\n", - arctx->conf.def.chan->center_freq, - ctx->def.chan->center_freq, - arctx->conf.def.width, ctx->def.width, - ctx, changed); + "mac chanctx change freq %hu width %d ptr %p changed %x\n", + ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use * switch_vif_chanctx(). @@ -6260,10 +6176,6 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) goto unlock; - spin_lock_bh(&ar->data_lock); - arctx->conf = *ctx; - spin_unlock_bh(&ar->data_lock); - ath10k_recalc_radar_detection(ar); /* FIXME: How to configure Rx chains properly? */ @@ -6283,7 +6195,6 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; - struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; int ret; @@ -6298,11 +6209,11 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, return -EBUSY; } - ret = ath10k_vdev_start(arvif, &arctx->conf.def); + ret = ath10k_vdev_start(arvif, &ctx->def); if (ret) { ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n", arvif->vdev_id, vif->addr, - arctx->conf.def.chan->center_freq, ret); + ctx->def.chan->center_freq, ret); goto err; } @@ -6377,7 +6288,7 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif; - struct ath10k_chanctx *arctx_new, *arctx_old; + int ret; int i; mutex_lock(&ar->conf_mutex); @@ -6386,38 +6297,81 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); - spin_lock_bh(&ar->data_lock); + /* First stop monitor interface. Some FW versions crash if there's a + * lone monitor interface. + */ + if (ar->monitor_started) + ath10k_monitor_stop(ar); + for (i = 0; i < n_vifs; i++) { arvif = ath10k_vif_to_arvif(vifs[i].vif); - arctx_new = (void *)vifs[i].new_ctx->drv_priv; - arctx_old = (void *)vifs[i].old_ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d ptr %p->%p\n", + "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n", arvif->vdev_id, vifs[i].old_ctx->def.chan->center_freq, vifs[i].new_ctx->def.chan->center_freq, vifs[i].old_ctx->def.width, - vifs[i].new_ctx->def.width, - arctx_old, arctx_new); + vifs[i].new_ctx->def.width); - if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { - ath10k_mac_chan_ctx_init(ar, arctx_new, - vifs[i].new_ctx); - } + if (WARN_ON(!arvif->is_started)) + continue; - arctx_new->conf = *vifs[i].new_ctx; + if (WARN_ON(!arvif->is_up)) + continue; - /* FIXME: ath10k_mac_chan_reconfigure() uses current, i.e. not - * yet updated chanctx_conf pointer. - */ - arctx_old->conf = *vifs[i].new_ctx; + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); + if (ret) { + ath10k_warn(ar, "failed to down vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } } - ath10k_mac_update_rx_channel(ar); + + /* All relevant vdevs are downed and associated channel resources + * should be available for the channel switch now. + */ + + spin_lock_bh(&ar->data_lock); + ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs); spin_unlock_bh(&ar->data_lock); - /* FIXME: Reconfigure only affected vifs */ - ath10k_mac_chan_reconfigure(ar); + for (i = 0; i < n_vifs; i++) { + arvif = ath10k_vif_to_arvif(vifs[i].vif); + + if (WARN_ON(!arvif->is_started)) + continue; + + if (WARN_ON(!arvif->is_up)) + continue; + + ret = ath10k_mac_setup_bcn_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", + ret); + + ret = ath10k_mac_setup_prb_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", + ret); + + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); + if (ret) { + ath10k_warn(ar, "failed to bring vdev up %d: %d\n", + arvif->vdev_id, ret); + continue; + } + } + + ath10k_monitor_recalc(ar); mutex_unlock(&ar->conf_mutex); return 0; @@ -6914,7 +6868,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->sta_data_size = sizeof(struct ath10k_sta); - ar->hw->chanctx_data_size = sizeof(struct ath10k_chanctx); ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 17a060e8efa2..ea656e011a96 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1424,7 +1424,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) struct ath10k_ce_ring *ce_ring; struct ce_desc *ce_desc; struct sk_buff *skb; - unsigned int id; int i; ar = pci_pipe->hif_ce_state; @@ -1448,8 +1447,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) continue; ce_ring->per_transfer_context[i] = NULL; - id = MS(__le16_to_cpu(ce_desc[i].flags), - CE_DESC_FLAGS_META_DATA); ar_pci->msg_callbacks_current.tx_completion(ar, skb); } @@ -2850,6 +2847,7 @@ err_free_pipes: ath10k_pci_free_pipes(ar); err_sleep: + ath10k_pci_sleep_sync(ar); ath10k_pci_release(ar); err_core_destroy: @@ -2927,8 +2925,10 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); /* QCA6174 2.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); +MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); /* QCA6174 3.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); +MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 563fde73623c..8fdba3865c96 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -402,7 +402,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) - return; + goto out; trace_ath10k_wmi_event(ar, id, skb->data, skb->len); @@ -521,6 +521,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) break; } +out: dev_kfree_skb(skb); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0fabe689179c..6c046c244705 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -27,6 +27,7 @@ #include "testmode.h" #include "wmi-ops.h" #include "p2p.h" +#include "hw.h" /* MAIN WMI cmd track */ static struct wmi_cmd_map wmi_cmd_map = { @@ -1450,6 +1451,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); + dev_kfree_skb(skb); return ret; } @@ -1636,20 +1638,22 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) } if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) { - /* During scanning chan info is reported twice for each - * visited channel. The reported cycle count is global - * and per-channel cycle count must be calculated */ - - cycle_count -= ar->survey_last_cycle_count; - rx_clear_count -= ar->survey_last_rx_clear_count; - - survey = &ar->survey[idx]; - survey->time = WMI_CHAN_INFO_MSEC(cycle_count); - survey->time_busy = WMI_CHAN_INFO_MSEC(rx_clear_count); - survey->noise = noise_floor; - survey->filled = SURVEY_INFO_TIME | - SURVEY_INFO_TIME_BUSY | - SURVEY_INFO_NOISE_DBM; + if (ar->ch_info_can_report_survey) { + survey = &ar->survey[idx]; + survey->noise = noise_floor; + survey->filled = SURVEY_INFO_NOISE_DBM; + + ath10k_hw_fill_survey_time(ar, + survey, + cycle_count, + rx_clear_count, + ar->survey_last_cycle_count, + ar->survey_last_rx_clear_count); + } + + ar->ch_info_can_report_survey = false; + } else { + ar->ch_info_can_report_survey = true; } ar->survey_last_rx_clear_count = rx_clear_count; @@ -3219,7 +3223,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) - return; + goto out; trace_ath10k_wmi_event(ar, id, skb->data, skb->len); @@ -3323,6 +3327,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) break; } +out: dev_kfree_skb(skb); } @@ -3336,7 +3341,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) - return; + goto out; trace_ath10k_wmi_event(ar, id, skb->data, skb->len); @@ -3459,7 +3464,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) - return; + goto out; trace_ath10k_wmi_event(ar, id, skb->data, skb->len); @@ -3567,6 +3572,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) break; } +out: dev_kfree_skb(skb); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cad72ae76253..cf44a3d080a3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4665,7 +4665,6 @@ struct wmi_peer_sta_kickout_event { } __packed; #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) -#define WMI_CHAN_INFO_MSEC(x) ((x) / 88000) /* Beacon filter wmi command info */ #define BCN_FLT_MAX_SUPPORTED_IES 256 diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 19f88b4a24fb..05d25a94c781 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1527,8 +1527,8 @@ struct wmi_connect_event { __le32 nw_type; } sta; struct { - u8 phymode; u8 aid; + u8 phymode; u8 mac_addr[ETH_ALEN]; u8 auth; u8 keymgmt; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 5dbc617ecf8a..16dff4b89a86 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -531,6 +531,7 @@ struct ath9k_htc_priv { struct ath9k_debug debug; #endif struct mutex mutex; + struct ieee80211_vif *csa_vif; }; static inline void ath_read_cachesize(struct ath_common *common, int *csz) @@ -584,6 +585,7 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); void ath9k_tx_failed_tasklet(unsigned long data); void ath9k_htc_tx_cleanup_timer(unsigned long data); +bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index e8b6ec3c1dbb..e6bcb4c90fa0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -257,6 +257,8 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, } spin_unlock_bh(&priv->beacon_lock); + + ath9k_htc_csa_is_finished(priv); } static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, @@ -503,3 +505,20 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) return; } } + +bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) +{ + struct ieee80211_vif *vif; + + vif = priv->csa_vif; + if (!vif || !vif->csa_active) + return false; + + if (!ieee80211_csa_is_complete(vif)) + return false; + + ieee80211_csa_finish(vif); + + priv->csa_vif = NULL; + return true; +} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 36218ee2bdbe..39eaf9b6e9b4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -744,7 +744,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index b71f3072fd9a..dab1323dfec7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1134,6 +1134,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, priv->nvifs--; priv->vif_slot &= ~(1 << avp->index); + if (priv->csa_vif == vif) + priv->csa_vif = NULL; + ath9k_htc_remove_station(priv, vif, NULL); DEC_VIF(priv, vif->type); @@ -1841,6 +1844,19 @@ static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, return 0; } +static void ath9k_htc_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct ath9k_htc_priv *priv = hw->priv; + + /* mac80211 does not support CSA in multi-if cases (yet) */ + if (WARN_ON(priv->csa_vif)) + return; + + priv->csa_vif = vif; +} + struct ieee80211_ops ath9k_htc_ops = { .tx = ath9k_htc_tx, .start = ath9k_htc_start, @@ -1867,6 +1883,7 @@ struct ieee80211_ops ath9k_htc_ops = { .set_bitrate_mask = ath9k_htc_set_bitrate_mask, .get_stats = ath9k_htc_get_stats, .get_antenna = ath9k_htc_get_antenna, + .channel_switch_beacon = ath9k_htc_channel_switch_beacon, #ifdef CONFIG_ATH9K_HTC_DEBUGFS .get_et_sset_count = ath9k_htc_get_et_sset_count, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d285e3a89853..cfd45cb8ccfc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -216,11 +216,13 @@ static bool ath_prepare_reset(struct ath_softc *sc) ath_stop_ani(sc); ath9k_hw_disable_interrupts(ah); - if (!ath_drain_all_txq(sc)) - ret = false; - - if (!ath_stoprecv(sc)) - ret = false; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ret &= ath_stoprecv(sc); + ret &= ath_drain_all_txq(sc); + } else { + ret &= ath_drain_all_txq(sc); + ret &= ath_stoprecv(sc); + } return ret; } diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index dbfcdd16628a..c79cfe02ec80 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -289,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); + wil_dbg_misc(wil, "SSID count: %d", request->n_ssids); + + for (i = 0; i < request->n_ssids; i++) { + wil_dbg_misc(wil, "SSID[%d]", i); + print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, + request->ssids[i].ssid, + request->ssids[i].ssid_len); + } + + if (request->n_ssids) + rc = wmi_set_ssid(wil, request->ssids[0].ssid_len, + request->ssids[0].ssid); + else + rc = wmi_set_ssid(wil, 0, NULL); + + if (rc) { + wil_err(wil, "set SSID for scan request failed: %d\n", rc); + return rc; + } + wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); @@ -778,6 +798,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, 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__); @@ -790,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", info->privacy, info->auth_type); + wil_dbg_misc(wil, "Hidden SSID mode: %d\n", + info->hidden_ssid); wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, info->dtim_period); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, @@ -835,10 +858,28 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, 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); + channel->hw_value, hidden_ssid); if (rc) goto err_pcp_start; @@ -1023,8 +1064,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { static void wil_wiphy_init(struct wiphy *wiphy) { - /* TODO: set real value */ - wiphy->max_scan_ssids = 10; + wiphy->max_scan_ssids = 1; wiphy->max_scan_ie_len = WMI_MAX_IE_LEN; wiphy->max_num_pmkids = 0 /* TODO: */; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8f9c0722a801..75219a1b8805 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1360,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { struct wil6210_priv *wil = s->private; - int i, tid; + int i, tid, mcs; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -1390,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) } } spin_unlock_bh(&p->tid_rx_lock); + seq_puts(s, "Rx/MCS:"); + for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); + mcs++) + seq_printf(s, " %lld", + p->stats.rx_per_mcs[mcs]); + seq_puts(s, "\n"); } } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6d704aee3afd..b9febab89167 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -100,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO); MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order"); module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO); MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); +module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO); +MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order"); #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 6042f61b016c..8ef18ace110f 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -132,7 +132,7 @@ static void wil_dev_setup(struct net_device *dev) dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; } -void *wil_if_alloc(struct device *dev, void __iomem *csr) +void *wil_if_alloc(struct device *dev) { struct net_device *ndev; struct wireless_dev *wdev; @@ -147,7 +147,6 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) } wil = wdev_to_wil(wdev); - wil->csr = csr; wil->wdev = wdev; wil_dbg_misc(wil, "%s()\n", __func__); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 58c79166a6d1..aa3ecc607ca3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -163,7 +163,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct wil6210_priv *wil; struct device *dev = &pdev->dev; - void __iomem *csr; int rc; /* check HW */ @@ -178,9 +177,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } + wil = wil_if_alloc(dev); + if (IS_ERR(wil)) { + rc = (int)PTR_ERR(wil); + dev_err(dev, "wil_if_alloc failed: %d\n", rc); + return rc; + } + wil->pdev = pdev; + pci_set_drvdata(pdev, wil); + /* rollback to if_free */ + + wil->platform_handle = + wil_platform_init(&pdev->dev, &wil->platform_ops); + if (!wil->platform_handle) { + rc = -ENODEV; + wil_err(wil, "wil_platform_init failed\n"); + goto if_free; + } + /* rollback to err_plat */ + rc = pci_enable_device(pdev); if (rc) { - dev_err(&pdev->dev, + wil_err(wil, "pci_enable_device failed, retry with MSI only\n"); /* Work around for platforms that can't allocate IRQ: * retry with MSI only @@ -188,47 +206,37 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pdev->msi_enabled = 1; rc = pci_enable_device(pdev); } - if (rc) - return -ENODEV; + if (rc) { + wil_err(wil, + "pci_enable_device failed, even with MSI only\n"); + goto err_plat; + } /* rollback to err_disable_pdev */ rc = pci_request_region(pdev, 0, WIL_NAME); if (rc) { - dev_err(&pdev->dev, "pci_request_region failed\n"); + wil_err(wil, "pci_request_region failed\n"); goto err_disable_pdev; } /* rollback to err_release_reg */ - csr = pci_ioremap_bar(pdev, 0); - if (!csr) { - dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); + wil->csr = pci_ioremap_bar(pdev, 0); + if (!wil->csr) { + wil_err(wil, "pci_ioremap_bar failed\n"); rc = -ENODEV; goto err_release_reg; } /* rollback to err_iounmap */ - dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr); + wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); - wil = wil_if_alloc(dev, csr); - if (IS_ERR(wil)) { - rc = (int)PTR_ERR(wil); - dev_err(dev, "wil_if_alloc failed: %d\n", rc); - goto err_iounmap; - } - /* rollback to if_free */ - - pci_set_drvdata(pdev, wil); - wil->pdev = pdev; wil_set_capabilities(wil); wil6210_clear_irq(wil); - wil->platform_handle = - wil_platform_init(&pdev->dev, &wil->platform_ops); - /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { wil_err(wil, "Enable device failed\n"); - goto if_free; + goto err_iounmap; } /* rollback to bus_disable */ @@ -243,18 +251,19 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; - bus_disable: +bus_disable: wil_if_pcie_disable(wil); - if_free: +err_iounmap: + pci_iounmap(pdev, wil->csr); +err_release_reg: + pci_release_region(pdev, 0); +err_disable_pdev: + pci_disable_device(pdev); +err_plat: if (wil->platform_ops.uninit) wil->platform_ops.uninit(wil->platform_handle); +if_free: wil_if_free(wil); - err_iounmap: - pci_iounmap(pdev, csr); - err_release_reg: - pci_release_region(pdev, 0); - err_disable_pdev: - pci_disable_device(pdev); return rc; } @@ -269,12 +278,12 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil6210_debugfs_remove(wil); wil_if_remove(wil); wil_if_pcie_disable(wil); - if (wil->platform_ops.uninit) - wil->platform_ops.uninit(wil->platform_handle); - wil_if_free(wil); pci_iounmap(pdev, csr); pci_release_region(pdev, 0); pci_disable_device(pdev); + if (wil->platform_ops.uninit) + wil->platform_ops.uninit(wil->platform_handle); + wil_if_free(wil); } static const struct pci_device_id wil6210_pcie_ids[] = { @@ -291,7 +300,27 @@ static struct pci_driver wil6210_driver = { .name = WIL_NAME, }; -module_pci_driver(wil6210_driver); +static int __init wil6210_driver_init(void) +{ + int rc; + + rc = wil_platform_modinit(); + if (rc) + return rc; + + rc = pci_register_driver(&wil6210_driver); + if (rc) + wil_platform_modexit(); + return rc; +} +module_init(wil6210_driver_init); + +static void __exit wil6210_driver_exit(void) +{ + pci_unregister_driver(&wil6210_driver); + wil_platform_modexit(); +} +module_exit(wil6210_driver_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0113dac3a9a9..aa20af86e1d6 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -427,6 +427,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, cid = wil_rxdesc_cid(d); stats = &wil->sta[cid].stats; stats->last_mcs_rx = wil_rxdesc_mcs(d); + if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs)) + stats->rx_per_mcs[stats->last_mcs_rx]++; /* use radiotap header only if required */ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f3513a1fa424..275355d46a36 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -281,7 +281,7 @@ struct fw_map { }; /* array size should be in sync with actual definition in the wmi.c */ -extern const struct fw_map fw_mapping[7]; +extern const struct fw_map fw_mapping[8]; /** * mk_cidxtid - construct @cidxtid field @@ -464,6 +464,7 @@ enum wil_sta_status { }; #define WIL_STA_TID_NUM (16) +#define WIL_MCS_MAX (12) /* Maximum MCS supported */ struct wil_net_stats { unsigned long rx_packets; @@ -473,6 +474,7 @@ struct wil_net_stats { unsigned long tx_errors; unsigned long rx_dropped; u16 last_mcs_rx; + u64 rx_per_mcs[WIL_MCS_MAX + 1]; }; /** @@ -684,7 +686,7 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count); -void *wil_if_alloc(struct device *dev, void __iomem *csr); +void *wil_if_alloc(struct device *dev); void wil_if_free(struct wil6210_priv *wil); int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); @@ -762,7 +764,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev); void wil_wdev_free(struct wil6210_priv *wil); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); -int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); +int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, + u8 chan, u8 hidden_ssid); int wmi_pcp_stop(struct wil6210_priv *wil); void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, u16 reason_code, bool from_event); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 976a071ba74e..de15f1422fe9 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -17,6 +17,15 @@ #include "linux/device.h" #include "wil_platform.h" +int __init wil_platform_modinit(void) +{ + return 0; +} + +void wil_platform_modexit(void) +{ +} + /** * wil_platform_init() - wil6210 platform module init * @@ -26,10 +35,11 @@ */ void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) { - void *handle = NULL; + void *handle = ops; /* to return some non-NULL for 'void' impl. */ if (!ops) { - dev_err(dev, "Invalid parameter. Cannot init platform module\n"); + dev_err(dev, + "Invalid parameter. Cannot init platform module\n"); return NULL; } diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index 158c73b049a9..d7fa19b7886d 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -31,4 +31,7 @@ struct wil_platform_ops { void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); +int __init wil_platform_modinit(void); +void wil_platform_modexit(void); + #endif /* __WIL_PLATFORM_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 3dc8daf69bd2..c759759afbb2 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -85,6 +85,7 @@ const struct fw_map fw_mapping[] = { {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */ {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ + {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */ {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ /* * 920000..930000 ucode code RAM @@ -824,7 +825,8 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); } -int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) +int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, + u8 chan, u8 hidden_ssid) { int rc; @@ -834,6 +836,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) .disable_sec_offload = 1, .channel = chan - 1, .pcp_max_assoc_sta = max_assoc_sta, + .hidden_ssid = hidden_ssid, }; struct { struct wil6210_mbox_hdr_wmi wmi; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index cc04ab73b398..6e90e78f1554 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -495,10 +495,18 @@ struct wmi_power_mgmt_cfg_cmd { /* * WMI_PCP_START_CMDID */ + +enum wmi_hidden_ssid { + WMI_HIDDEN_SSID_DISABLED = 0, + WMI_HIDDEN_SSID_SEND_EMPTY = 1, + WMI_HIDDEN_SSID_CLEAR = 2, +}; + struct wmi_pcp_start_cmd { __le16 bcon_interval; u8 pcp_max_assoc_sta; - u8 reserved0[9]; + u8 hidden_ssid; + u8 reserved0[8]; u8 network_type; u8 channel; u8 disable_sec_offload; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 575b9f4b5589..28490702124a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5361,6 +5361,10 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy, *have_5ghz_phy = true; return; case 0x4321: /* BCM4306 */ + /* There are 14e4:4321 PCI devs with 2.4 GHz BCM4321 (N-PHY) */ + if (dev->phy.type != B43_PHYTYPE_G) + break; + /* fall through */ case 0x4313: /* BCM4311 */ case 0x431a: /* BCM4318 */ case 0x432a: /* BCM4321 */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 71779b9e4bbe..410a6645d316 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -988,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev) static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) { + sdiodev->state = BRCMF_SDIOD_DOWN; if (sdiodev->bus) { brcmf_sdio_remove(sdiodev->bus); sdiodev->bus = NULL; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index e10fa67010c0..d86d1f1f1c91 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -52,8 +52,6 @@ #define BRCMF_PNO_SCAN_COMPLETE 1 #define BRCMF_PNO_SCAN_INCOMPLETE 0 -#define BRCMF_IFACE_MAX_CNT 3 - #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ #define WPA_OUI_TYPE 1 #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ @@ -2398,27 +2396,80 @@ brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) brcmf_err("set wsec error (%d)\n", err); } +static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si) +{ + struct nl80211_sta_flag_update *sfu; + + brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags); + si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + sfu = &si->sta_flags; + sfu->mask = BIT(NL80211_STA_FLAG_WME) | + BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_ASSOCIATED) | + BIT(NL80211_STA_FLAG_AUTHORIZED); + if (fw_sta_flags & BRCMF_STA_WME) + sfu->set |= BIT(NL80211_STA_FLAG_WME); + if (fw_sta_flags & BRCMF_STA_AUTHE) + sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + if (fw_sta_flags & BRCMF_STA_ASSOC) + sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED); + if (fw_sta_flags & BRCMF_STA_AUTHO) + sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED); +} + +static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si) +{ + struct { + __le32 len; + struct brcmf_bss_info_le bss_le; + } *buf; + u16 capability; + int err; + + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (!buf) + return; + + buf->len = cpu_to_le32(WL_BSS_INFO_MAX); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf, + WL_BSS_INFO_MAX); + if (err) { + brcmf_err("Failed to get bss info (%d)\n", err); + return; + } + si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period); + si->bss_param.dtim_period = buf->bss_le.dtim_period; + capability = le16_to_cpu(buf->bss_le.capability); + if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT) + si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; +} + static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; - struct brcmf_scb_val_le scb_val; - int rssi; - s32 rate; s32 err = 0; - u8 *bssid = profile->bssid; struct brcmf_sta_info_le sta_info_le; - u32 beacon_period; - u32 dtim_period; + u32 sta_flags; + u32 is_tdls_peer; brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); if (!check_vif_up(ifp->vif)) return -EIO; - if (brcmf_is_apmode(ifp->vif)) { - memcpy(&sta_info_le, mac, ETH_ALEN); + memset(&sta_info_le, 0, sizeof(sta_info_le)); + memcpy(&sta_info_le, mac, ETH_ALEN); + err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info", + &sta_info_le, + sizeof(sta_info_le)); + is_tdls_peer = !err; + if (err) { err = brcmf_fil_iovar_data_get(ifp, "sta_info", &sta_info_le, sizeof(sta_info_le)); @@ -2426,73 +2477,48 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("GET STA INFO failed, %d\n", err); goto done; } - sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); - sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; - if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) { - sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); - sinfo->connected_time = le32_to_cpu(sta_info_le.in); - } - brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", - sinfo->inactive_time, sinfo->connected_time); - } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) { - if (memcmp(mac, bssid, ETH_ALEN)) { - brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", - mac, bssid); - err = -ENOENT; - goto done; - } - /* Report the current tx rate */ - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); - if (err) { - brcmf_err("Could not get rate (%d)\n", err); - goto done; - } else { + } + brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver)); + sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; + sta_flags = le32_to_cpu(sta_info_le.flags); + brcmf_convert_sta_flags(sta_flags, sinfo); + sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER); + if (is_tdls_peer) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + else + sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); + if (sta_flags & BRCMF_STA_ASSOC) { + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); + sinfo->connected_time = le32_to_cpu(sta_info_le.in); + brcmf_fill_bss_param(ifp, sinfo); + } + if (sta_flags & BRCMF_STA_SCBSTATS) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures); + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts); + sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts); + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts); + sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts); + if (sinfo->tx_packets) { sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); - sinfo->txrate.legacy = rate * 5; - brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2); + sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate); + sinfo->txrate.legacy /= 100; } - - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) { - memset(&scb_val, 0, sizeof(scb_val)); - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, - &scb_val, sizeof(scb_val)); - if (err) { - brcmf_err("Could not get rssi (%d)\n", err); - goto done; - } else { - rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); - sinfo->signal = rssi; - brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); - } - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD, - &beacon_period); - if (err) { - brcmf_err("Could not get beacon period (%d)\n", - err); - goto done; - } else { - sinfo->bss_param.beacon_interval = - beacon_period; - brcmf_dbg(CONN, "Beacon peroid %d\n", - beacon_period); - } - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD, - &dtim_period); - if (err) { - brcmf_err("Could not get DTIM period (%d)\n", - err); - goto done; - } else { - sinfo->bss_param.dtim_period = dtim_period; - brcmf_dbg(CONN, "DTIM peroid %d\n", - dtim_period); - } - sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + if (sinfo->rx_packets) { + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate); + sinfo->rxrate.legacy /= 100; } - } else - err = -EPERM; + if (le16_to_cpu(sta_info_le.ver) >= 4) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes); + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES); + sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes); + } + } done: brcmf_dbg(TRACE, "Exit\n"); return err; @@ -5640,53 +5666,6 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy) return 0; } -static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = { - { - .max = 1, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) - }, - { - .max = 4, - .types = BIT(NL80211_IFTYPE_AP) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE) - } -}; - -static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE) - } -}; -static struct ieee80211_iface_combination brcmf_iface_combos[] = { - { - .max_interfaces = BRCMF_IFACE_MAX_CNT, - .num_different_channels = 1, - .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss), - .limits = brcmf_iface_limits_sbss, - } -}; - static const struct ieee80211_txrx_stypes brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -5716,6 +5695,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { } }; +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; + + combo = kzalloc(sizeof(*combo), GFP_KERNEL); + if (!combo) + goto err; + + limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL); + if (!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)) { + 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; + + wiphy->iface_combinations = combo; + wiphy->n_iface_combinations = 1; + return 0; + +err: + kfree(limits); + kfree(combo); + return -ENOMEM; +} + static void brcmf_wiphy_pno_params(struct wiphy *wiphy) { /* scheduled scan settings */ @@ -5746,7 +5786,6 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { struct ieee80211_supported_band *band; - struct ieee80211_iface_combination ifc_combo; __le32 bandlist[3]; u32 n_bands; int err, i; @@ -5754,24 +5793,11 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; - wiphy->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_P2P_DEVICE); - /* need VSDB firmware feature for concurrent channels */ - ifc_combo = brcmf_iface_combos[0]; - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - ifc_combo.num_different_channels = 2; - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { - ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss), - ifc_combo.limits = brcmf_iface_limits_mbss; - } - wiphy->iface_combinations = kmemdup(&ifc_combo, - sizeof(ifc_combo), - GFP_KERNEL); - wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); + + err = brcmf_setup_ifmodes(wiphy, ifp); + if (err) + return err; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -6036,6 +6062,8 @@ static void brcmf_free_wiphy(struct wiphy *wiphy) if (!wiphy) return; + if (wiphy->iface_combinations) + kfree(wiphy->iface_combinations->limits); kfree(wiphy->iface_combinations); if (wiphy->bands[IEEE80211_BAND_2GHZ]) { kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); @@ -6071,6 +6099,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, brcmf_err("Could not allocate wiphy device\n"); return NULL; } + memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN); set_wiphy_dev(wiphy, busdev); cfg = wiphy_priv(wiphy); @@ -6178,10 +6207,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) if (!cfg) return; - WARN_ON(!list_empty(&cfg->vif_list)); - wiphy_unregister(cfg->wiphy); brcmf_btcoex_detach(cfg); - brcmf_p2p_detach(&cfg->p2p); + wiphy_unregister(cfg->wiphy); wl_deinit_priv(cfg); brcmf_free_wiphy(cfg->wiphy); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c index 26c65872dae3..7b0e52195a85 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c @@ -223,8 +223,6 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring, void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, u16 *n_items) { - void *ret_addr; - if (commonring->cr_update_wptr) commonring->cr_update_wptr(commonring->cr_ctx); @@ -235,19 +233,18 @@ void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, if (*n_items == 0) return NULL; - ret_addr = commonring->buf_addr + - (commonring->r_ptr * commonring->item_len); - - commonring->r_ptr += *n_items; - if (commonring->r_ptr == commonring->depth) - commonring->r_ptr = 0; - - return ret_addr; + return commonring->buf_addr + + (commonring->r_ptr * commonring->item_len); } -int brcmf_commonring_read_complete(struct brcmf_commonring *commonring) +int brcmf_commonring_read_complete(struct brcmf_commonring *commonring, + u16 n_items) { + commonring->r_ptr += n_items; + if (commonring->r_ptr == commonring->depth) + commonring->r_ptr = 0; + if (commonring->cr_write_rptr) return commonring->cr_write_rptr(commonring->cr_ctx); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h index 3d404016a92e..b85033611c8d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h @@ -62,7 +62,8 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring, u16 n_items); void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, u16 *n_items); -int brcmf_commonring_read_complete(struct brcmf_commonring *commonring); +int brcmf_commonring_read_complete(struct brcmf_commonring *commonring, + u16 n_items); #define brcmf_commonring_n_items(commonring) (commonring->depth) #define brcmf_commonring_len_item(commonring) (commonring->item_len) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index f8f47dcfa886..fe9d3fbf5fe2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -867,8 +867,6 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) } /* unregister will take care of freeing it */ unregister_netdev(ifp->ndev); - } else { - kfree(ifp); } } @@ -1100,6 +1098,8 @@ void brcmf_detach(struct device *dev) /* stop firmware event handling */ brcmf_fweh_detach(drvr); + if (drvr->config) + brcmf_p2p_detach(&drvr->config->p2p); brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/brcm80211/brcmfmac/debug.c index 9b473d50b005..2d6d00553858 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c @@ -41,15 +41,6 @@ void brcmf_debugfs_exit(void) root_folder = NULL; } -static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data) -{ - struct brcmf_bus *bus = dev_get_drvdata(seq->private); - - seq_printf(seq, "chip: %x(%u) rev %u\n", - bus->chip, bus->chip, bus->chiprev); - return 0; -} - int brcmf_debugfs_attach(struct brcmf_pub *drvr) { struct device *dev = drvr->bus_if->dev; @@ -58,7 +49,6 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr) return -ENODEV; drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); - brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read); return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } @@ -74,44 +64,12 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) return drvr->dbgfs_dir; } -struct brcmf_debugfs_entry { - int (*read)(struct seq_file *seq, void *data); - struct brcmf_pub *drvr; -}; - -static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f) -{ - struct brcmf_debugfs_entry *entry = inode->i_private; - - return single_open(f, entry->read, entry->drvr->bus_if->dev); -} - -static const struct file_operations brcmf_debugfs_def_ops = { - .owner = THIS_MODULE, - .open = brcmf_debugfs_entry_open, - .release = single_release, - .read = seq_read, - .llseek = seq_lseek -}; - int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, int (*read_fn)(struct seq_file *seq, void *data)) { - struct dentry *dentry = drvr->dbgfs_dir; - struct brcmf_debugfs_entry *entry; - - if (IS_ERR_OR_NULL(dentry)) - return -ENOENT; - - entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - entry->read = read_fn; - entry->drvr = drvr; - - dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry, - &brcmf_debugfs_def_ops); + struct dentry *e; - return PTR_ERR_OR_ZERO(dentry); + e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn, + drvr->dbgfs_dir, read_fn); + return PTR_ERR_OR_ZERO(e); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c index 2c5fad3a3aa2..1e94e94e01dc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c @@ -129,6 +129,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID) brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p"); /* set chip related quirks */ switch (drvr->bus_if->chip) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h index 546962525cd2..6b381f799f22 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h @@ -23,12 +23,14 @@ * MCHAN: multi-channel for concurrent P2P. * PNO: preferred network offload. * WOWL: Wake-On-WLAN. + * P2P: peer-to-peer */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ BRCMF_FEAT_DEF(MCHAN) \ BRCMF_FEAT_DEF(PNO) \ - BRCMF_FEAT_DEF(WOWL) + BRCMF_FEAT_DEF(WOWL) \ + BRCMF_FEAT_DEF(P2P) /* * Quirks: * diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 7ae6461df932..743f16b6a072 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -43,7 +43,7 @@ enum nvram_parser_state { * struct nvram_parser - internal info for parser. * * @state: current parser state. - * @fwnv: input buffer being parsed. + * @data: input buffer being parsed. * @nvram: output buffer with parse result. * @nvram_len: lenght of parse result. * @line: current line. @@ -55,7 +55,7 @@ enum nvram_parser_state { */ struct nvram_parser { enum nvram_parser_state state; - const struct firmware *fwnv; + const u8 *data; u8 *nvram; u32 nvram_len; u32 line; @@ -91,7 +91,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp) { char c; - c = nvp->fwnv->data[nvp->pos]; + c = nvp->data[nvp->pos]; if (c == '\n') return COMMENT; if (is_whitespace(c)) @@ -115,16 +115,16 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp) enum nvram_parser_state st = nvp->state; char c; - c = nvp->fwnv->data[nvp->pos]; + c = nvp->data[nvp->pos]; if (c == '=') { /* ignore RAW1 by treating as comment */ - if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0) + if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0) st = COMMENT; else st = VALUE; - if (strncmp(&nvp->fwnv->data[nvp->entry], "devpath", 7) == 0) + if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0) nvp->multi_dev_v1 = true; - if (strncmp(&nvp->fwnv->data[nvp->entry], "pcie/", 5) == 0) + if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0) nvp->multi_dev_v2 = true; } else if (!is_nvram_char(c) || c == ' ') { brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", @@ -145,11 +145,11 @@ brcmf_nvram_handle_value(struct nvram_parser *nvp) char *ekv; u32 cplen; - c = nvp->fwnv->data[nvp->pos]; + c = nvp->data[nvp->pos]; if (!is_nvram_char(c)) { /* key,value pair complete */ - ekv = (u8 *)&nvp->fwnv->data[nvp->pos]; - skv = (u8 *)&nvp->fwnv->data[nvp->entry]; + ekv = (u8 *)&nvp->data[nvp->pos]; + skv = (u8 *)&nvp->data[nvp->entry]; cplen = ekv - skv; if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE) return END; @@ -170,7 +170,7 @@ brcmf_nvram_handle_comment(struct nvram_parser *nvp) { char *eoc, *sol; - sol = (char *)&nvp->fwnv->data[nvp->pos]; + sol = (char *)&nvp->data[nvp->pos]; eoc = strchr(sol, '\n'); if (!eoc) { eoc = strchr(sol, '\0'); @@ -201,17 +201,17 @@ static enum nvram_parser_state }; static int brcmf_init_nvram_parser(struct nvram_parser *nvp, - const struct firmware *nv) + const u8 *data, size_t data_len) { size_t size; memset(nvp, 0, sizeof(*nvp)); - nvp->fwnv = nv; + nvp->data = data; /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */ - if (nv->size > BRCMF_FW_MAX_NVRAM_SIZE) + if (data_len > BRCMF_FW_MAX_NVRAM_SIZE) size = BRCMF_FW_MAX_NVRAM_SIZE; else - size = nv->size; + size = data_len; /* Alloc for extra 0 byte + roundup by 4 + length field */ size += 1 + 3 + sizeof(u32); nvp->nvram = kzalloc(size, GFP_KERNEL); @@ -232,6 +232,8 @@ static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr, u16 bus_nr) { /* Device path with a leading '=' key-value separator */ + char pci_path[] = "=pci/?/?"; + size_t pci_len; char pcie_path[] = "=pcie/?/?"; size_t pcie_len; @@ -251,6 +253,9 @@ static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr, /* First search for the devpathX and see if it is the configuration * for domain_nr/bus_nr. Search complete nvp */ + snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr, + bus_nr); + pci_len = strlen(pci_path); snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr, bus_nr); pcie_len = strlen(pcie_path); @@ -260,8 +265,9 @@ static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr, /* Format: devpathX=pcie/Y/Z/ * Y = domain_nr, Z = bus_nr, X = virtual ID */ - if ((strncmp(&nvp->nvram[i], "devpath", 7) == 0) && - (strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len) == 0)) { + if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 && + (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) || + !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) { id = nvp->nvram[i + 7] - '0'; found = true; break; @@ -356,18 +362,18 @@ fail: * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. * End of buffer is completed with token identifying length of buffer. */ -static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length, - u16 domain_nr, u16 bus_nr) +static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len, + u32 *new_length, u16 domain_nr, u16 bus_nr) { struct nvram_parser nvp; u32 pad; u32 token; __le32 token_le; - if (brcmf_init_nvram_parser(&nvp, nv) < 0) + if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0) return NULL; - while (nvp.pos < nv->size) { + while (nvp.pos < data_len) { nvp.state = nv_parser_states[nvp.state](&nvp); if (nvp.state == END) break; @@ -426,7 +432,7 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) goto fail; if (fw) { - nvram = brcmf_fw_nvram_strip(fw, &nvram_length, + nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length, fwctx->domain_nr, fwctx->bus_nr); release_firmware(fw); if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 374920965108..297911f38fa0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -32,7 +32,11 @@ #define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ #define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002 -#define BRCMF_STA_ASSOC 0x10 /* Associated */ +#define BRCMF_STA_WME 0x00000002 /* WMM association */ +#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */ +#define BRCMF_STA_ASSOC 0x00000010 /* Associated */ +#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */ +#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ /* size of brcmf_scan_params not including variable length array */ #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 @@ -113,6 +117,7 @@ #define BRCMF_WOWL_MAXPATTERNSIZE 128 #define BRCMF_COUNTRY_BUF_SZ 4 +#define BRCMF_ANT_MAX 4 /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { @@ -456,25 +461,61 @@ struct brcmf_channel_info_le { }; struct brcmf_sta_info_le { - __le16 ver; /* version of this struct */ - __le16 len; /* length in bytes of this structure */ - __le16 cap; /* sta's advertised capabilities */ - __le32 flags; /* flags defined below */ - __le32 idle; /* time since data pkt rx'd from sta */ - u8 ea[ETH_ALEN]; /* Station address */ - __le32 count; /* # rates in this set */ - u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */ + __le16 ver; /* version of this struct */ + __le16 len; /* length in bytes of this structure */ + __le16 cap; /* sta's advertised capabilities */ + __le32 flags; /* flags defined below */ + __le32 idle; /* time since data pkt rx'd from sta */ + u8 ea[ETH_ALEN]; /* Station address */ + __le32 count; /* # rates in this set */ + u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */ /* w/hi bit set if basic */ - __le32 in; /* seconds elapsed since associated */ - __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ - __le32 tx_pkts; /* # of packets transmitted */ - __le32 tx_failures; /* # of packets failed */ - __le32 rx_ucast_pkts; /* # of unicast packets received */ - __le32 rx_mcast_pkts; /* # of multicast packets received */ - __le32 tx_rate; /* Rate of last successful tx frame */ - __le32 rx_rate; /* Rate of last successful rx frame */ - __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ - __le32 rx_decrypt_failures; /* # of packet decrypted failed */ + __le32 in; /* seconds elapsed since associated */ + __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ + __le32 tx_pkts; /* # of packets transmitted */ + __le32 tx_failures; /* # of packets failed */ + __le32 rx_ucast_pkts; /* # of unicast packets received */ + __le32 rx_mcast_pkts; /* # of multicast packets received */ + __le32 tx_rate; /* Rate of last successful tx frame */ + __le32 rx_rate; /* Rate of last successful rx frame */ + __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ + __le32 rx_decrypt_failures; /* # of packet decrypted failed */ + __le32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */ + __le32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */ + __le32 tx_mcast_pkts; /* # of mcast pkts txed */ + __le64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */ + __le64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */ + __le64 tx_ucast_bytes; /* data bytes txed (ucast) */ + __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */ + __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */ + __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */ + s8 rssi[BRCMF_ANT_MAX]; /* per antenna rssi */ + s8 nf[BRCMF_ANT_MAX]; /* per antenna noise floor */ + __le16 aid; /* association ID */ + __le16 ht_capabilities; /* advertised ht caps */ + __le16 vht_flags; /* converted vht flags */ + __le32 tx_pkts_retry_cnt; /* # of frames where a retry was + * exhausted. + */ + __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry + * was exhausted + */ + s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last + * received data frame. + */ + /* TX WLAN retry/failure statistics: + * Separated for host requested frames and locally generated frames. + * Include unicast frame only where the retries/failures can be counted. + */ + __le32 tx_pkts_total; /* # user frames sent successfully */ + __le32 tx_pkts_retries; /* # user frames retries */ + __le32 tx_pkts_fw_total; /* # FW generated sent successfully */ + __le32 tx_pkts_fw_retries; /* # retries for FW generated frames */ + __le32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry + * was exhausted + */ + __le32 rx_pkts_retried; /* # rx with retry bit set */ + __le32 tx_rate_fallback; /* lowest fallback TX rate */ }; struct brcmf_chanspec_list { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 1b47de067d25..898c3801e658 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -75,6 +75,8 @@ #define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 96 #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32 +#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS 48 + struct msgbuf_common_hdr { u8 msgtype; @@ -1257,19 +1259,27 @@ static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf, { void *buf; u16 count; + u16 processed; again: buf = brcmf_commonring_get_read_ptr(commonring, &count); if (buf == NULL) return; + processed = 0; while (count) { brcmf_msgbuf_process_msgtype(msgbuf, buf + msgbuf->rx_dataoffset); buf += brcmf_commonring_len_item(commonring); + processed++; + if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) { + brcmf_commonring_read_complete(commonring, processed); + processed = 0; + } count--; } - brcmf_commonring_read_complete(commonring); + if (processed) + brcmf_commonring_read_complete(commonring, processed); if (commonring->r_ptr == 0) goto again; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 710fbe570eb2..a9ba775a24c1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/rtnetlink.h> #include <net/cfg80211.h> #include <brcmu_wifi.h> @@ -1908,105 +1909,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, /** - * brcmf_p2p_attach() - attach for P2P. - * - * @cfg: driver private data for cfg80211 interface. - */ -s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_if *pri_ifp; - struct brcmf_if *p2p_ifp; - struct brcmf_cfg80211_vif *p2p_vif; - struct brcmf_p2p_info *p2p; - struct brcmf_pub *drvr; - s32 bssidx; - s32 err = 0; - - p2p = &cfg->p2p; - p2p->cfg = cfg; - - drvr = cfg->pub; - - pri_ifp = drvr->iflist[0]; - p2p_ifp = drvr->iflist[1]; - - p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; - - if (p2p_ifp) { - p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, - false); - if (IS_ERR(p2p_vif)) { - brcmf_err("could not create discovery vif\n"); - err = -ENOMEM; - goto exit; - } - - p2p_vif->ifp = p2p_ifp; - p2p_ifp->vif = p2p_vif; - p2p_vif->wdev.netdev = p2p_ifp->ndev; - p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; - SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); - - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; - - brcmf_p2p_generate_bss_mac(p2p, NULL); - memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); - brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); - - /* Initialize P2P Discovery in the firmware */ - err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); - if (err < 0) { - brcmf_err("set p2p_disc error\n"); - brcmf_free_vif(p2p_vif); - goto exit; - } - /* obtain bsscfg index for P2P discovery */ - err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); - if (err < 0) { - brcmf_err("retrieving discover bsscfg index failed\n"); - brcmf_free_vif(p2p_vif); - goto exit; - } - /* Verify that firmware uses same bssidx as driver !! */ - if (p2p_ifp->bssidx != bssidx) { - brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", - bssidx, p2p_ifp->bssidx); - brcmf_free_vif(p2p_vif); - goto exit; - } - - init_completion(&p2p->send_af_done); - INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); - init_completion(&p2p->afx_hdl.act_frm_scan); - init_completion(&p2p->wait_next_af); - } -exit: - return err; -} - - -/** - * brcmf_p2p_detach() - detach P2P. - * - * @p2p: P2P specific data. - */ -void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) -{ - struct brcmf_cfg80211_vif *vif; - - vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - if (vif != NULL) { - brcmf_p2p_cancel_remain_on_channel(vif->ifp); - brcmf_p2p_deinit_discovery(p2p); - /* remove discovery interface */ - brcmf_free_vif(vif); - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - } - /* just set it all to zero */ - memset(p2p, 0, sizeof(*p2p)); -} - -/** * brcmf_p2p_get_current_chanspec() - Get current operation channel. * * @p2p: P2P specific data. @@ -2238,6 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p, { cfg80211_unregister_wdev(&vif->wdev); p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; + brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx); brcmf_free_vif(vif); } @@ -2364,6 +2267,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) break; case NL80211_IFTYPE_P2P_DEVICE: + brcmf_p2p_cancel_remain_on_channel(vif->ifp); + brcmf_p2p_deinit_discovery(p2p); brcmf_p2p_delete_p2pdev(p2p, vif); return 0; default: @@ -2425,3 +2330,103 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev) clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state); mutex_unlock(&cfg->usr_sync); } + +/** + * brcmf_p2p_attach() - attach for P2P. + * + * @cfg: driver private data for cfg80211 interface. + */ +s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_if *pri_ifp; + struct brcmf_if *p2p_ifp; + struct brcmf_cfg80211_vif *p2p_vif; + struct brcmf_p2p_info *p2p; + struct brcmf_pub *drvr; + s32 bssidx; + s32 err = 0; + + p2p = &cfg->p2p; + p2p->cfg = cfg; + + drvr = cfg->pub; + + pri_ifp = drvr->iflist[0]; + p2p_ifp = drvr->iflist[1]; + + p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; + + if (p2p_ifp) { + p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, + false); + if (IS_ERR(p2p_vif)) { + brcmf_err("could not create discovery vif\n"); + err = -ENOMEM; + goto exit; + } + + p2p_vif->ifp = p2p_ifp; + p2p_ifp->vif = p2p_vif; + p2p_vif->wdev.netdev = p2p_ifp->ndev; + p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; + SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); + + p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; + + brcmf_p2p_generate_bss_mac(p2p, NULL); + memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); + brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); + + /* Initialize P2P Discovery in the firmware */ + err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); + if (err < 0) { + brcmf_err("set p2p_disc error\n"); + brcmf_free_vif(p2p_vif); + goto exit; + } + /* obtain bsscfg index for P2P discovery */ + err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); + if (err < 0) { + brcmf_err("retrieving discover bsscfg index failed\n"); + brcmf_free_vif(p2p_vif); + goto exit; + } + /* Verify that firmware uses same bssidx as driver !! */ + if (p2p_ifp->bssidx != bssidx) { + brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", + bssidx, p2p_ifp->bssidx); + brcmf_free_vif(p2p_vif); + goto exit; + } + + init_completion(&p2p->send_af_done); + INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); + init_completion(&p2p->afx_hdl.act_frm_scan); + init_completion(&p2p->wait_next_af); + } +exit: + return err; +} + +/** + * brcmf_p2p_detach() - detach P2P. + * + * @p2p: P2P specific data. + */ +void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) +{ + struct brcmf_cfg80211_vif *vif; + + vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + if (vif != NULL) { + brcmf_p2p_cancel_remain_on_channel(vif->ifp); + brcmf_p2p_deinit_discovery(p2p); + /* remove discovery interface */ + rtnl_lock(); + brcmf_p2p_delete_p2pdev(p2p, vif); + rtnl_unlock(); + } + /* just set it all to zero */ + memset(p2p, 0, sizeof(*p2p)); +} + diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 37a2624d7bba..3a98c4306d1d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -1629,20 +1629,7 @@ static void brcmf_pcie_buscore_write32(void *ctx, u32 addr, u32 value) static int brcmf_pcie_buscoreprep(void *ctx) { - struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; - int err; - - err = brcmf_pcie_get_resource(devinfo); - if (err == 0) { - /* Set CC watchdog to reset all the cores on the chip to bring - * back dongle to a sane state. - */ - brcmf_pcie_buscore_write32(ctx, CORE_CC_REG(SI_ENUM_BASE, - watchdog), 4); - msleep(100); - } - - return err; + return brcmf_pcie_get_resource(ctx); } @@ -1824,6 +1811,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) brcmf_pcie_intr_disable(devinfo); brcmf_detach(&pdev->dev); + brcmf_pcie_reset_device(devinfo); kfree(bus->bus_priv.pcie); kfree(bus->msgbuf->flowrings); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index bf7a8b1ad914..d36f5f3d931b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2820,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len); + if (sdiodev->state != BRCMF_SDIOD_DATA) + return -EIO; /* Add space for the header */ skb_push(pkt, bus->tx_hdrlen); @@ -2948,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) int ret; brcmf_dbg(TRACE, "Enter\n"); + if (sdiodev->state != BRCMF_SDIOD_DATA) + return -EIO; /* Send from dpc */ bus->ctrl_frame_buf = msg; @@ -3238,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); + if (sdiodev->state != BRCMF_SDIOD_DATA) + return -EIO; /* Wait until control frame is available */ timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending); diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 9c9e1288644b..7217da4f1543 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -34,56 +34,32 @@ static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len) static struct sk_buff * mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, - u8 *data, u32 seg_len) + void *data, u32 seg_len, u32 truesize, struct page *p) { struct sk_buff *skb; - u32 true_len; + u32 true_len, hdr_len = 0, copy, frag; - if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) - seg_len -= 2; - - skb = alloc_skb(seg_len, GFP_ATOMIC); - if (!skb) - return NULL; - - if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { - int hdr_len = ieee80211_get_hdrlen_from_buf(data, seg_len); - - memcpy(skb_put(skb, hdr_len), data, hdr_len); - data += hdr_len + 2; - seg_len -= hdr_len; - } - - memcpy(skb_put(skb, seg_len), data, seg_len); - - true_len = mt76_mac_process_rx(dev, skb, skb->data, rxwi); - skb_trim(skb, true_len); - - return skb; -} - -static struct sk_buff * -mt7601u_rx_skb_from_seg_paged(struct mt7601u_dev *dev, - struct mt7601u_rxwi *rxwi, void *data, - u32 seg_len, u32 truesize, struct page *p) -{ - unsigned int hdr_len = ieee80211_get_hdrlen_from_buf(data, seg_len); - unsigned int true_len, copy, frag; - struct sk_buff *skb; - - skb = alloc_skb(128, GFP_ATOMIC); + skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC); if (!skb) return NULL; true_len = mt76_mac_process_rx(dev, skb, data, rxwi); + if (!true_len || true_len > seg_len) + goto bad_frame; + + hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len); + if (!hdr_len) + goto bad_frame; if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { memcpy(skb_put(skb, hdr_len), data, hdr_len); + data += hdr_len + 2; true_len -= hdr_len; hdr_len = 0; } + /* If not doing paged RX allocated skb will always have enough space */ copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; frag = true_len - copy; @@ -97,10 +73,16 @@ mt7601u_rx_skb_from_seg_paged(struct mt7601u_dev *dev, } return skb; + +bad_frame: + dev_err_ratelimited(dev->dev, "Error: incorrect frame len:%u hdr:%u\n", + true_len, hdr_len); + dev_kfree_skb(skb); + return NULL; } static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, - u32 seg_len, struct page *p, bool paged) + u32 seg_len, struct page *p) { struct sk_buff *skb; struct mt7601u_rxwi *rxwi; @@ -126,11 +108,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, trace_mt_rx(dev, rxwi, fce_info); - if (paged) - skb = mt7601u_rx_skb_from_seg_paged(dev, rxwi, data, seg_len, - truesize, p); - else - skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len); + skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p); if (!skb) return; @@ -158,23 +136,17 @@ mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e) u32 seg_len, data_len = e->urb->actual_length; u8 *data = page_address(e->p); struct page *new_p = NULL; - bool paged = true; int cnt = 0; if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state)) return; /* Copy if there is very little data in the buffer. */ - if (data_len < 512) { - paged = false; - } else { + if (data_len > 512) new_p = dev_alloc_pages(MT_RX_ORDER); - if (!new_p) - paged = false; - } while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) { - mt7601u_rx_process_seg(dev, data, seg_len, e->p, paged); + mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL); data_len -= seg_len; data += seg_len; @@ -182,9 +154,9 @@ mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e) } if (cnt > 1) - trace_mt_rx_dma_aggr(dev, cnt, paged); + trace_mt_rx_dma_aggr(dev, cnt, !!new_p); - if (paged) { + if (new_p) { /* we have one extra ref from the allocator */ __free_pages(e->p, MT_RX_ORDER); diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c index ce3837f270f0..8d8ee0344f7b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/eeprom.c +++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c @@ -277,6 +277,10 @@ mt7601u_extra_power_over_mac(struct mt7601u_dev *dev) static void mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value) { + /* Invalid? Note: vendor driver does not handle this */ + if (value == 0xff) + return; + rate->raw = s6_validate(value); rate->bw20 = s6_to_int(value); /* Note: vendor driver does cap the value to s6 right away */ diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index ca1ea2e55ff4..df3dd56199a7 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -427,6 +427,9 @@ err: void mt7601u_cleanup(struct mt7601u_dev *dev) { + if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state)) + return; + mt7601u_stop_hardware(dev); mt7601u_dma_cleanup(dev); mt7601u_mcu_cmd_deinit(dev); diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index c161bcc6a7fa..7514bce1ac91 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -450,10 +450,14 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct mt7601u_rxwi *rxwi = rxi; - u32 ctl = le32_to_cpu(rxwi->ctl); + u32 len, ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); int rssi; + len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + if (len < 10) + return 0; + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; @@ -474,7 +478,7 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); spin_unlock_bh(&dev->con_mon_lock); - return MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + return len; } static enum mt76_cipher_type diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index ced82abb414f..169384b48b27 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -119,6 +119,7 @@ mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; + MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC); MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 99e2b3997bfa..54dba4001865 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -338,8 +338,15 @@ static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state) static int mt7601u_resume(struct usb_interface *usb_intf) { struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); + int ret; + + ret = mt7601u_init_hardware(dev); + if (ret) + return ret; + + set_bit(MT7601U_STATE_INITIALIZED, &dev->state); - return mt7601u_init_hardware(dev); + return 0; } MODULE_DEVICE_TABLE(usb, mt7601u_device_table); diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 65cd461c88db..71a1b580796f 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -161,19 +161,38 @@ int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, cr_req->chan_desc.chan_width = radar_params->chandef->width; cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms); - mwifiex_dbg(priv->adapter, MSG, - "11h: issuing DFS Radar check for channel=%d\n", - radar_params->chandef->chan->hw_value); + if (radar_params->cac_time_ms) + mwifiex_dbg(priv->adapter, MSG, + "11h: issuing DFS Radar check for channel=%d\n", + radar_params->chandef->chan->hw_value); + else + mwifiex_dbg(priv->adapter, MSG, "cancelling CAC\n"); return 0; } +int mwifiex_stop_radar_detection(struct mwifiex_private *priv, + struct cfg80211_chan_def *chandef) +{ + struct mwifiex_radar_params radar_params; + + memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); + radar_params.chandef = chandef; + radar_params.cac_time_ms = 0; + + return mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, + HostCmd_ACT_GEN_SET, 0, &radar_params, true); +} + /* This function is to abort ongoing CAC upon stopping AP operations * or during unload. */ void mwifiex_abort_cac(struct mwifiex_private *priv) { if (priv->wdev.cac_started) { + if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) + mwifiex_dbg(priv->adapter, ERROR, + "failed to stop CAC in FW\n"); mwifiex_dbg(priv->adapter, MSG, "Aborting delayed work for CAC.\n"); cancel_delayed_work_sync(&priv->dfs_cac_work); @@ -245,6 +264,9 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, if (le32_to_cpu(rdr_event->passed)) { mwifiex_dbg(priv->adapter, MSG, "radar detected; indicating kernel\n"); + if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) + mwifiex_dbg(priv->adapter, ERROR, + "Failed to stop CAC in FW\n"); cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, GFP_KERNEL); mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n", @@ -252,7 +274,7 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n", rdr_event->det_type); } else { - mwifiex_dbg(priv->adapter, ERROR, + mwifiex_dbg(priv->adapter, MSG, "false radar detection event!\n"); } @@ -283,7 +305,7 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) return; } - mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef); + mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef); if (mwifiex_config_start_uap(priv, bss_cfg)) { mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 8422986cd7a9..c174e79e6df2 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -156,7 +156,7 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv, int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - int tid; + int tid, tid_down; struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; struct mwifiex_ra_list_tbl *ra_list; @@ -167,7 +167,9 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) >> BLOCKACKPARAM_TID_POS; - ra_list = mwifiex_wmm_get_ralist_node(priv, tid, add_ba_rsp-> + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, add_ba_rsp-> peer_mac_addr); if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { if (ra_list) { @@ -530,13 +532,16 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, struct mwifiex_tx_ba_stream_tbl *new_node; struct mwifiex_ra_list_tbl *ra_list; unsigned long flags; + int tid_down; if (!mwifiex_get_ba_tbl(priv, tid, ra)) { new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), GFP_ATOMIC); if (!new_node) return; - ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra); + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, ra); if (ra_list) { ra_list->ba_status = ba_status; ra_list->amsdu_in_ampdu = false; @@ -643,6 +648,30 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, } /* + * This function sends delba to specific tid + */ +void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + + if (list_empty(&priv->rx_reorder_tbl_ptr)) { + dev_dbg(priv->adapter->dev, + "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n"); + return; + } + + list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { + if (rx_reor_tbl_ptr->tid == tid) { + dev_dbg(priv->adapter->dev, + "Send delba to tid=%d, %pM\n", + tid, rx_reor_tbl_ptr->ta); + mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); + return; + } + } +} + +/* * This function handles the command response of a delete BA request. */ void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) @@ -814,3 +843,72 @@ u8 mwifiex_get_sec_chan_offset(int chan) return sec_offset; } + +/* This function will send DELBA to entries in the priv's + * Tx BA stream table + */ +static void +mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr; + + if (list_empty(&priv->tx_ba_stream_tbl_ptr)) + return; + + list_for_each_entry(tx_ba_stream_tbl_ptr, + &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) { + if (tid == tx_ba_stream_tbl_ptr->tid) { + dev_dbg(adapter->dev, + "Tx:Send delba to tid=%d, %pM\n", tid, + tx_ba_stream_tbl_ptr->ra); + mwifiex_send_delba(priv, + tx_ba_stream_tbl_ptr->tid, + tx_ba_stream_tbl_ptr->ra, 1); + return; + } + } + } +} + +/* This function updates all the tx_win_size + */ +void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter) +{ + u8 i; + u32 tx_win_size; + struct mwifiex_private *priv; + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + tx_win_size = priv->add_ba_param.tx_win_size; + + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + priv->add_ba_param.tx_win_size = + MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; + + if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) + priv->add_ba_param.tx_win_size = + MWIFIEX_STA_AMPDU_DEF_TXWINSIZE; + + if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) + priv->add_ba_param.tx_win_size = + MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE; + + if (adapter->coex_win_size) { + if (adapter->coex_tx_win_size) + priv->add_ba_param.tx_win_size = + adapter->coex_tx_win_size; + } + + if (tx_win_size != priv->add_ba_param.tx_win_size) { + if (!priv->media_connected) + continue; + for (i = 0; i < MAX_NUM_TID; i++) + mwifiex_send_delba_txbastream_tbl(priv, i); + } + } +} diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 39d7a957674c..2906cd543532 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -663,6 +663,7 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, struct mwifiex_ra_list_tbl *ra_list; u8 cleanup_rx_reorder_tbl; unsigned long flags; + int tid_down; if (type == TYPE_DELBA_RECEIVE) cleanup_rx_reorder_tbl = (initiator) ? true : false; @@ -688,7 +689,9 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, "event: TID, RA not found in table\n"); return; } - ra_list = mwifiex_wmm_get_ralist_node(priv, tid, peer_mac); + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac); if (ra_list) { ra_list->amsdu_in_ampdu = false; ra_list->ba_status = BA_SETUP_NONE; @@ -825,3 +828,83 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags) return; } + +/* This function update all the rx_win_size based on coex flag + */ +static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter, + bool coex_flag) +{ + u8 i; + u32 rx_win_size; + struct mwifiex_private *priv; + + dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag); + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + rx_win_size = priv->add_ba_param.rx_win_size; + if (coex_flag) { + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + priv->add_ba_param.rx_win_size = + MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) + priv->add_ba_param.rx_win_size = + MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) + priv->add_ba_param.rx_win_size = + MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE; + } else { + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + priv->add_ba_param.rx_win_size = + MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) + priv->add_ba_param.rx_win_size = + MWIFIEX_STA_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) + priv->add_ba_param.rx_win_size = + MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE; + } + + if (adapter->coex_win_size && adapter->coex_rx_win_size) + priv->add_ba_param.rx_win_size = + adapter->coex_rx_win_size; + + if (rx_win_size != priv->add_ba_param.rx_win_size) { + if (!priv->media_connected) + continue; + for (i = 0; i < MAX_NUM_TID; i++) + mwifiex_11n_delba(priv, i); + } + } +} + +/* This function check coex for RX BA + */ +void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter) +{ + u8 i; + struct mwifiex_private *priv; + u8 count = 0; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + if (priv->media_connected) + count++; + } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + if (priv->bss_started) + count++; + } + } + if (count >= MWIFIEX_BSS_COEX_COUNT) + break; + } + if (count >= MWIFIEX_BSS_COEX_COUNT) + mwifiex_update_ampdu_rxwinsize(adapter, true); + else + mwifiex_update_ampdu_rxwinsize(adapter, false); +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 4eecedadefbf..b15e4c7acbec 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -67,6 +67,22 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type) } } +/* This function maps IEEE HT secondary channel type to NL80211 channel type + */ +u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset) +{ + switch (second_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_NONE: + return NL80211_CHAN_HT20; + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + return NL80211_CHAN_HT40PLUS; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + return NL80211_CHAN_HT40MINUS; + default: + return NL80211_CHAN_HT20; + } +} + /* * This function checks whether WEP is set. */ @@ -1213,6 +1229,7 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, */ static int mwifiex_dump_station_info(struct mwifiex_private *priv, + struct mwifiex_sta_node *node, struct station_info *sinfo) { u32 rate; @@ -1222,6 +1239,30 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, BIT(NL80211_STA_INFO_TX_BITRATE) | BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG); + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + if (!node) + return -ENOENT; + + sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) | + BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->inactive_time = + jiffies_to_msecs(jiffies - node->stats.last_rx); + + sinfo->signal = node->stats.rssi; + sinfo->signal_avg = node->stats.rssi; + sinfo->rx_bytes = node->stats.rx_bytes; + sinfo->tx_bytes = node->stats.tx_bytes; + sinfo->rx_packets = node->stats.rx_packets; + sinfo->tx_packets = node->stats.tx_packets; + sinfo->tx_failed = node->stats.tx_failed; + + mwifiex_parse_htinfo(priv, node->stats.last_tx_htinfo, + &sinfo->txrate); + sinfo->txrate.legacy = node->stats.last_tx_rate * 5; + + return 0; + } + /* Get signal information from the firmware */ if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, HostCmd_ACT_GEN_GET, 0, NULL, true)) { @@ -1288,7 +1329,7 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) return -ENOENT; - return mwifiex_dump_station_info(priv, sinfo); + return mwifiex_dump_station_info(priv, NULL, sinfo); } /* @@ -1299,13 +1340,29 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + static struct mwifiex_sta_node *node; - if (!priv->media_connected || idx) - return -ENOENT; + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + priv->media_connected && idx == 0) { + ether_addr_copy(mac, priv->cfg_bssid); + return mwifiex_dump_station_info(priv, NULL, sinfo); + } else if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST, + HostCmd_ACT_GEN_GET, 0, NULL, true); + + if (node && (&node->list == &priv->sta_list)) { + node = NULL; + return -ENOENT; + } - memcpy(mac, priv->cfg_bssid, ETH_ALEN); + node = list_prepare_entry(node, &priv->sta_list, list); + list_for_each_entry_continue(node, &priv->sta_list, list) { + ether_addr_copy(mac, node->mac_addr); + return mwifiex_dump_station_info(priv, node, sinfo); + } + } - return mwifiex_dump_station_info(priv, sinfo); + return -ENOENT; } static int @@ -1725,6 +1782,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) return -1; } + if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { + mwifiex_dbg(priv->adapter, ERROR, + "Failed to reset BSS\n"); + return -1; + } + return 0; } @@ -1778,7 +1842,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - mwifiex_uap_set_channel(bss_cfg, params->chandef); + mwifiex_uap_set_channel(priv, bss_cfg, params->chandef); mwifiex_set_uap_rates(bss_cfg, params); if (mwifiex_set_secure_params(priv, bss_cfg, params)) { @@ -1803,6 +1867,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, mwifiex_set_wmm_params(priv, bss_cfg, params); + if (mwifiex_is_11h_active(priv)) + mwifiex_set_tpc_params(priv, bss_cfg, params); + if (mwifiex_is_11h_active(priv) && !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, priv->bss_mode)) { @@ -1813,7 +1880,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, "Failed to disable 11h extensions!!"); return -1; } - priv->state_11h.is_11h_active = true; + priv->state_11h.is_11h_active = false; } if (mwifiex_config_start_uap(priv, bss_cfg)) { @@ -2518,7 +2585,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; priv->bss_priority = 0; priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_num = 0; + priv->bss_num = adapter->curr_iface_comb.sta_intf; break; case NL80211_IFTYPE_AP: @@ -2544,7 +2611,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_priority = 0; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; priv->bss_started = 0; - priv->bss_num = 0; + priv->bss_num = adapter->curr_iface_comb.uap_intf; priv->bss_mode = type; break; @@ -2580,7 +2647,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_priority = MWIFIEX_BSS_ROLE_STA; priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_started = 0; - priv->bss_num = 0; + priv->bss_num = adapter->curr_iface_comb.p2p_intf; if (mwifiex_cfg80211_init_p2p_client(priv)) { memset(&priv->wdev, 0, sizeof(priv->wdev)); @@ -3366,6 +3433,45 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); + struct mwifiex_bssdescriptor *curr_bss; + struct ieee80211_channel *chan; + u8 second_chan_offset; + enum nl80211_channel_type chan_type; + enum ieee80211_band band; + int freq; + int ret = -ENODATA; + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP && + cfg80211_chandef_valid(&priv->bss_chandef)) { + *chandef = priv->bss_chandef; + ret = 0; + } else if (priv->media_connected) { + curr_bss = &priv->curr_bss_params.bss_descriptor; + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + freq = ieee80211_channel_to_frequency(curr_bss->channel, band); + chan = ieee80211_get_channel(wiphy, freq); + + if (curr_bss->bcn_ht_oper) { + second_chan_offset = curr_bss->bcn_ht_oper->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET; + chan_type = mwifiex_sec_chan_offset_to_chan_type + (second_chan_offset); + cfg80211_chandef_create(chandef, chan, chan_type); + } else { + cfg80211_chandef_create(chandef, chan, + NL80211_CHAN_NO_HT); + } + ret = 0; + } + + return ret; +} + static int mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, struct net_device *dev, @@ -3471,6 +3577,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .tdls_oper = mwifiex_cfg80211_tdls_oper, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, + .get_channel = mwifiex_cfg80211_get_channel, .start_radar_detection = mwifiex_cfg80211_start_radar_detection, .channel_switch = mwifiex_cfg80211_channel_switch, }; @@ -3578,7 +3685,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_HAS_CHANNEL_SWITCH; + WIPHY_FLAG_HAS_CHANNEL_SWITCH | + WIPHY_FLAG_PS_ON_BY_DEFAULT; if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index a1de83fd1dbe..207da40500f4 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -469,10 +469,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) memset(rx_info, 0, sizeof(*rx_info)); rx_info->bss_num = priv->bss_num; rx_info->bss_type = priv->bss_type; + mwifiex_dbg_dump(adapter, EVT_D, "Event Buf:", + skb->data, skb->len); } mwifiex_dbg(adapter, EVENT, "EVENT: cause: %#x\n", eventcause); - mwifiex_dbg_dump(adapter, EVT_D, "Event Buf:", skb->data, skb->len); if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) ret = mwifiex_process_uap_event(priv); @@ -574,6 +575,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, case HostCmd_CMD_UAP_BSS_START: case HostCmd_CMD_UAP_BSS_STOP: case HostCmd_CMD_UAP_STA_DEAUTH: + case HOST_CMD_APCMD_SYS_RESET: + case HOST_CMD_APCMD_STA_LIST: ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action, cmd_oid, data_buf, cmd_ptr); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 38f24e0427d2..51e344789ba2 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -29,7 +29,7 @@ #include <uapi/linux/if_arp.h> #include <net/mac80211.h> - +#define MWIFIEX_BSS_COEX_COUNT 2 #define MWIFIEX_MAX_BSS_NUM (3) #define MWIFIEX_DMA_ALIGN_SZ 64 @@ -49,7 +49,12 @@ #define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64 +#define MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE 16 + #define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32 + +#define MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE 16 + #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16 #define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64 diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index c404390cb0fa..cd09051710e6 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -128,6 +128,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_SSID 0x0000 #define TLV_TYPE_UAP_RATES 0x0001 +#define TLV_TYPE_PWR_CONSTRAINT 0x0020 #define PROPRIETARY_TLV_BASE_ID 0x0100 #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) @@ -174,6 +175,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) #define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) #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 MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -330,9 +333,11 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_RSSI_INFO 0x00a4 #define HostCmd_CMD_FUNC_INIT 0x00a9 #define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa +#define HOST_CMD_APCMD_SYS_RESET 0x00af #define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0 #define HostCmd_CMD_UAP_BSS_START 0x00b1 #define HostCmd_CMD_UAP_BSS_STOP 0x00b2 +#define HOST_CMD_APCMD_STA_LIST 0x00b3 #define HostCmd_CMD_UAP_STA_DEAUTH 0x00b5 #define HostCmd_CMD_11N_CFG 0x00cd #define HostCmd_CMD_11N_ADDBA_REQ 0x00ce @@ -419,8 +424,12 @@ enum P2P_MODES { #define HS_CFG_COND_MAC_EVENT 0x00000004 #define HS_CFG_COND_MULTICAST_DATA 0x00000008 -#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc -#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2 +#define CONNECT_ERR_AUTH_ERR_STA_FAILURE 0xFFFB +#define CONNECT_ERR_ASSOC_ERR_TIMEOUT 0xFFFC +#define CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED 0xFFFD +#define CONNECT_ERR_AUTH_MSG_UNHANDLED 0xFFFE +#define CONNECT_ERR_STA_FAILURE 0xFFFF + #define CMD_F_HOSTCMD (1 << 0) #define CMD_F_CANCELED (1 << 1) @@ -503,6 +512,7 @@ enum P2P_MODES { #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 +#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 #define EVENT_ID_MASK 0xffff #define BSS_NUM_MASK 0xf @@ -627,7 +637,12 @@ struct uap_rxpd { __le16 rx_pkt_type; __le16 seq_num; u8 priority; - u8 reserved1; + u8 rx_rate; + s8 snr; + s8 nf; + u8 ht_info; + u8 reserved[3]; + u8 flags; }; struct mwifiex_fw_chan_stats { @@ -1151,6 +1166,13 @@ enum SNMP_MIB_INDEX { DOT11H_I = 10, }; +enum mwifiex_assocmd_failurepoint { + MWIFIEX_ASSOC_CMD_SUCCESS = 0, + MWIFIEX_ASSOC_CMD_FAILURE_ASSOC, + MWIFIEX_ASSOC_CMD_FAILURE_AUTH, + MWIFIEX_ASSOC_CMD_FAILURE_JOIN +}; + #define MAX_SNMP_BUF_SIZE 128 struct host_cmd_ds_802_11_snmp_mib { @@ -1448,6 +1470,18 @@ struct host_cmd_ds_sta_deauth { __le16 reason; } __packed; +struct mwifiex_ie_types_sta_info { + struct mwifiex_ie_types_header header; + u8 mac[ETH_ALEN]; + u8 power_mfg_status; + s8 rssi; +}; + +struct host_cmd_ds_sta_list { + u16 sta_count; + u8 tlv[0]; +} __packed; + struct mwifiex_ie_types_pwr_capability { struct mwifiex_ie_types_header header; s8 min_pwr; @@ -1750,6 +1784,27 @@ struct host_cmd_tlv_ageout_timer { __le32 sta_ao_timer; } __packed; +struct host_cmd_tlv_power_constraint { + struct mwifiex_ie_types_header header; + u8 constraint; +} __packed; + +struct mwifiex_ie_types_btcoex_scan_time { + struct mwifiex_ie_types_header header; + u8 coex_scan; + u8 reserved; + u16 min_scan_time; + u16 max_scan_time; +} __packed; + +struct mwifiex_ie_types_btcoex_aggr_win_size { + struct mwifiex_ie_types_header header; + u8 coex_win_size; + u8 tx_win_size; + u8 rx_win_size; + u8 reserved; +} __packed; + struct host_cmd_ds_version_ext { u8 version_str_sel; char version_str[128]; @@ -1977,6 +2032,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_802_11_subsc_evt subsc_evt; struct host_cmd_ds_sys_config uap_sys_config; struct host_cmd_ds_sta_deauth sta_deauth; + 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_oper tdls_oper; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index f3b6ed249403..0ba894509413 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -320,63 +320,81 @@ done: /* This function parses head and tail IEs, from cfg80211_beacon_data and sets * these IE to FW. */ -static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv, - struct cfg80211_beacon_data *info) +static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) { struct mwifiex_ie *gen_ie; - struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; - struct ieee_types_header *chsw_ie = NULL; + struct ieee_types_header *hdr; + struct ieee80211_vendor_ie *vendorhdr; u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; - const u8 *vendor_ie; + int left_len, parsed_len = 0; + + if (!info->tail || !info->tail_len) + return 0; gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL); if (!gen_ie) return -ENOMEM; - gen_ie->ie_index = cpu_to_le16(gen_idx); - gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | - MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP); - if (info->tail && info->tail_len) { - rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, - info->tail, info->tail_len); - if (rsn_ie) { - memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2); - ie_len = rsn_ie->len + 2; - gen_ie->ie_length = cpu_to_le16(ie_len); + left_len = info->tail_len; + + /* Many IEs are generated in FW by parsing bss configuration. + * Let's not add them here; else we may end up duplicating these IEs + */ + while (left_len > sizeof(struct ieee_types_header)) { + hdr = (void *)(info->tail + parsed_len); + switch (hdr->element_id) { + case WLAN_EID_SSID: + case WLAN_EID_SUPP_RATES: + case WLAN_EID_COUNTRY: + case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_HT_OPERATION: + case WLAN_EID_VHT_CAPABILITY: + case WLAN_EID_VHT_OPERATION: + case WLAN_EID_VENDOR_SPECIFIC: + break; + default: + memcpy(gen_ie->ie_buffer + ie_len, hdr, + hdr->len + sizeof(struct ieee_types_header)); + ie_len += hdr->len + sizeof(struct ieee_types_header); + break; } + left_len -= hdr->len + sizeof(struct ieee_types_header); + parsed_len += hdr->len + sizeof(struct ieee_types_header); + } - vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + /* parse only WPA vendor IE from tail, WMM IE is configured by + * bss_config command + */ + vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, - info->tail, - info->tail_len); - if (vendor_ie) { - wpa_ie = (struct ieee_types_header *)vendor_ie; - memcpy(gen_ie->ie_buffer + ie_len, - wpa_ie, wpa_ie->len + 2); - ie_len += wpa_ie->len + 2; - gen_ie->ie_length = cpu_to_le16(ie_len); - } + info->tail, info->tail_len); + if (vendorhdr) { + memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, + vendorhdr->len + sizeof(struct ieee_types_header)); + ie_len += vendorhdr->len + sizeof(struct ieee_types_header); + } - chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, - info->tail, info->tail_len); - if (chsw_ie) { - memcpy(gen_ie->ie_buffer + ie_len, - chsw_ie, chsw_ie->len + 2); - ie_len += chsw_ie->len + 2; - gen_ie->ie_length = cpu_to_le16(ie_len); - } + if (!ie_len) { + kfree(gen_ie); + return 0; } - if (rsn_ie || wpa_ie || chsw_ie) { - if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, - NULL, NULL, NULL)) { - kfree(gen_ie); - return -1; - } - priv->gen_idx = gen_idx; + gen_ie->ie_index = cpu_to_le16(gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | + MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP); + gen_ie->ie_length = cpu_to_le16(ie_len); + + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL, + NULL, NULL)) { + kfree(gen_ie); + return -1; } + priv->gen_idx = gen_idx; kfree(gen_ie); return 0; } @@ -390,7 +408,7 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, { int ret; - ret = mwifiex_uap_set_head_tail_ies(priv, info); + ret = mwifiex_uap_parse_tail_ies(priv, info); return ret; return mwifiex_set_mgmt_beacon_data_ies(priv, info); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 6f11a25a6b49..4f0174c64946 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -113,6 +113,7 @@ struct mwifiex_uap_bss_param { u32 sta_ao_timer; u32 ps_sta_ao_timer; u8 qos_info; + u8 power_constraint; struct mwifiex_types_wmm_info wmm_info; }; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index cce8e39aa45e..56b024a6aaa5 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -556,6 +556,23 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, return 0; } +static const char *assoc_failure_reason_to_str(u16 cap_info) +{ + switch (cap_info) { + case CONNECT_ERR_AUTH_ERR_STA_FAILURE: + return "CONNECT_ERR_AUTH_ERR_STA_FAILURE"; + case CONNECT_ERR_AUTH_MSG_UNHANDLED: + return "CONNECT_ERR_AUTH_MSG_UNHANDLED"; + case CONNECT_ERR_ASSOC_ERR_TIMEOUT: + return "CONNECT_ERR_ASSOC_ERR_TIMEOUT"; + case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED: + return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED"; + case CONNECT_ERR_STA_FAILURE: + return "CONNECT_ERR_STA_FAILURE"; + } + + return "Unknown connect failure"; +} /* * Association firmware command response handler * @@ -656,11 +673,18 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, status_code, cap_info, le16_to_cpu(assoc_rsp->a_id)); - if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) { - if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT) + mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n", + assoc_failure_reason_to_str(cap_info)); + if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) { + if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) { ret = WLAN_STATUS_AUTH_TIMEOUT; - else + mwifiex_dbg(priv->adapter, ERROR, + "ASSOC_RESP: AUTH timeout\n"); + } else { ret = WLAN_STATUS_UNSPECIFIED_FAILURE; + mwifiex_dbg(priv->adapter, ERROR, + "ASSOC_RESP: UNSPECIFIED failure\n"); + } } else { ret = status_code; } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5a6c1c76b33b..ae98b5b83b1f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -642,6 +642,7 @@ struct mwifiex_private { u8 del_list_idx; bool hs2_enabled; struct mwifiex_uap_bss_param bss_cfg; + struct cfg80211_chan_def bss_chandef; struct station_parameters *sta_params; struct sk_buff_head tdls_txq; u8 check_tdls_tx; @@ -740,6 +741,18 @@ struct mwifiex_tdls_capab { struct ieee80211_vht_operation vhtoper; }; +struct mwifiex_station_stats { + u64 last_rx; + s8 rssi; + u64 rx_bytes; + u64 tx_bytes; + u32 rx_packets; + u32 tx_packets; + u32 tx_failed; + u8 last_tx_rate; + u8 last_tx_htinfo; +}; + /* This is AP/TDLS specific structure which stores information * about associated/peer STA */ @@ -754,6 +767,7 @@ struct mwifiex_sta_node { u16 max_amsdu; u8 tdls_status; struct mwifiex_tdls_capab tdls_cap; + struct mwifiex_station_stats stats; }; struct mwifiex_auto_tdls_peer { @@ -959,6 +973,12 @@ struct mwifiex_adapter { u32 num_in_chan_stats; int survey_idx; bool auto_tdls; + u8 coex_scan; + u8 coex_min_scan_time; + u8 coex_max_scan_time; + u8 coex_win_size; + u8 coex_tx_win_size; + u8 coex_rx_win_size; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); @@ -1135,6 +1155,9 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv, void mwifiex_set_vht_params(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_ap_settings *params); +void mwifiex_set_tpc_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_ap_settings *params); void mwifiex_set_vht_width(struct mwifiex_private *priv, @@ -1145,6 +1168,11 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_ap_settings *params); void mwifiex_set_ba_params(struct mwifiex_private *priv); + +void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *pmadapter); +void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv, + struct sk_buff *event_skb); + void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv); int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -1382,6 +1410,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type); +u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset); struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, @@ -1399,7 +1428,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, struct cfg80211_beacon_data *data); int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); u8 *mwifiex_11d_code_2_region(u8 code); -void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, +void mwifiex_uap_set_channel(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_chan_def chandef); int mwifiex_config_start_uap(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg); @@ -1473,6 +1503,8 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, void mwifiex_dfs_cac_work_queue(struct work_struct *work); void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work); void mwifiex_abort_cac(struct mwifiex_private *priv); +int mwifiex_stop_radar_detection(struct mwifiex_private *priv, + struct cfg80211_chan_def *chandef); int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, struct sk_buff *skb); @@ -1488,7 +1520,8 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter); void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter); 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); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index aa5b9a310340..b645884b3b97 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -958,6 +958,27 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv, return 0; } +static int mwifiex_ret_uap_sta_list(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_sta_list *sta_list = + &resp->params.sta_list; + struct mwifiex_ie_types_sta_info *sta_info = (void *)&sta_list->tlv; + int i; + struct mwifiex_sta_node *sta_node; + + for (i = 0; i < sta_list->sta_count; i++) { + sta_node = mwifiex_get_sta_entry(priv, sta_info->mac); + if (unlikely(!sta_node)) + continue; + + sta_node->stats.rssi = sta_info->rssi; + sta_info++; + } + + return 0; +} + /* This function handles the command response of set_cfg_data */ static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) @@ -1148,6 +1169,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_UAP_SYS_CONFIG: break; + case HOST_CMD_APCMD_STA_LIST: + ret = mwifiex_ret_uap_sta_list(priv, resp); + break; case HostCmd_CMD_UAP_BSS_START: adapter->tx_lock_flag = false; adapter->pps_uapsd_mode = false; @@ -1159,6 +1183,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_UAP_STA_DEAUTH: break; + case HOST_CMD_APCMD_SYS_RESET: + break; case HostCmd_CMD_MEF_CFG: break; case HostCmd_CMD_COALESCE_CFG: diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 95203780010a..848de2621958 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -183,6 +183,63 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, } /* +* This function handles coex events generated by firmware +*/ +void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_header *tlv; + struct mwifiex_ie_types_btcoex_aggr_win_size *winsizetlv; + struct mwifiex_ie_types_btcoex_scan_time *scantlv; + s32 len = event_skb->len - sizeof(u32); + u8 *cur_ptr = event_skb->data + sizeof(u32); + u16 tlv_type, tlv_len; + + while (len >= sizeof(struct mwifiex_ie_types_header)) { + tlv = (struct mwifiex_ie_types_header *)cur_ptr; + tlv_len = le16_to_cpu(tlv->len); + tlv_type = le16_to_cpu(tlv->type); + + if ((tlv_len + sizeof(struct mwifiex_ie_types_header)) > len) + break; + switch (tlv_type) { + case TLV_BTCOEX_WL_AGGR_WINSIZE: + winsizetlv = + (struct mwifiex_ie_types_btcoex_aggr_win_size *)tlv; + adapter->coex_win_size = winsizetlv->coex_win_size; + adapter->coex_tx_win_size = + winsizetlv->tx_win_size; + adapter->coex_rx_win_size = + winsizetlv->rx_win_size; + mwifiex_coex_ampdu_rxwinsize(adapter); + mwifiex_update_ampdu_txwinsize(adapter); + break; + + case TLV_BTCOEX_WL_SCANTIME: + scantlv = + (struct mwifiex_ie_types_btcoex_scan_time *)tlv; + adapter->coex_scan = scantlv->coex_scan; + adapter->coex_min_scan_time = scantlv->min_scan_time; + adapter->coex_max_scan_time = scantlv->max_scan_time; + break; + + default: + break; + } + + len -= tlv_len + sizeof(struct mwifiex_ie_types_header); + cur_ptr += tlv_len + + sizeof(struct mwifiex_ie_types_header); + } + + dev_dbg(adapter->dev, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n", + adapter->coex_scan, adapter->coex_min_scan_time, + adapter->coex_win_size, adapter->coex_tx_win_size, + adapter->coex_rx_win_size); +} + +/* * This function handles events generated by firmware. * * This is a generic function and handles all events. @@ -531,6 +588,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_11h_handle_radar_detected(priv, adapter->event_skb); break; + case EVENT_BT_COEX_WLAN_PARA_CHANGE: + dev_dbg(adapter->dev, "EVENT: BT coex wlan param update\n"); + mwifiex_bt_coex_wlan_param_update_event(priv, + adapter->event_skb); + break; default: mwifiex_dbg(adapter, ERROR, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 28dcc84a34d2..5ed9b794053e 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -88,13 +88,22 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_adapter *adapter = priv->adapter; u8 *head_ptr; struct txpd *local_tx_pd = NULL; + struct mwifiex_sta_node *dest_node; + struct ethhdr *hdr = (void *)skb->data; hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; - if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) + if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { + dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest); + if (dest_node) { + dest_node->stats.tx_bytes += skb->len; + dest_node->stats.tx_packets++; + } + head_ptr = mwifiex_process_uap_txpd(priv, skb); - else + } else { head_ptr = mwifiex_process_sta_txpd(priv, skb); + } if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) { skb_queue_tail(&adapter->tx_data_q, skb); @@ -310,11 +319,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, priv->stats.tx_errors++; } - if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) { + if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) atomic_dec_return(&adapter->pending_bridged_pkts); - if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) - goto done; - } + + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + goto done; if (aggr) /* For skb_aggr, do not wake up tx queue */ diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index a4ae28353b6d..b74930054b8c 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -222,6 +222,23 @@ void mwifiex_set_vht_params(struct mwifiex_private *priv, return; } +/* This function updates 11ac related parameters from IE + * and sets them into bss_config structure. + */ +void mwifiex_set_tpc_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params) +{ + const u8 *tpc_ie; + + tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail, + params->beacon.tail_len); + if (tpc_ie) + bss_cfg->power_constraint = *(tpc_ie + 2); + else + bss_cfg->power_constraint = 0; +} + /* Enable VHT only when cfg80211_ap_settings has VHT IE. * Otherwise disable VHT. */ @@ -466,6 +483,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) struct host_cmd_tlv_auth_type *auth_type; struct host_cmd_tlv_rates *tlv_rates; struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer; + struct host_cmd_tlv_power_constraint *pwr_ct; struct mwifiex_ie_types_htcap *htcap; struct mwifiex_ie_types_wmmcap *wmm_cap; struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; @@ -644,6 +662,15 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) tlv += sizeof(*ao_timer); } + if (bss_cfg->power_constraint) { + pwr_ct = (void *)tlv; + pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT); + pwr_ct->header.len = cpu_to_le16(sizeof(u8)); + pwr_ct->constraint = bss_cfg->power_constraint; + cmd_size += sizeof(*pwr_ct); + tlv += sizeof(*pwr_ct); + } + if (bss_cfg->ps_sta_ao_timer) { ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; ps_ao_timer->header.type = @@ -754,6 +781,8 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, break; case HostCmd_CMD_UAP_BSS_START: case HostCmd_CMD_UAP_BSS_STOP: + case HOST_CMD_APCMD_SYS_RESET: + case HOST_CMD_APCMD_STA_LIST: cmd->command = cpu_to_le16(cmd_no); cmd->size = cpu_to_le16(S_DS_GEN); break; @@ -775,11 +804,14 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, return 0; } -void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, +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; + priv->bss_chandef = chandef; + bss_cfg->channel = ieee80211_frequency_to_channel( chandef.chan->center_freq); @@ -800,19 +832,28 @@ void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, if (chandef.width > NL80211_CHAN_WIDTH_40) config_bands |= BAND_AAC; } + + priv->adapter->config_bands = config_bands; } int mwifiex_config_start_uap(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg) { + enum state_11d_t state_11d; + if (mwifiex_del_mgmt_ies(priv)) mwifiex_dbg(priv->adapter, ERROR, "Failed to delete mgmt IEs!\n"); if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL, true)) { - mwifiex_dbg(priv->adapter, ERROR, - "Failed to stop the BSS\n"); + mwifiex_dbg(priv->adapter, ERROR, "Failed to stop the BSS\n"); + return -1; + } + + if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { + mwifiex_dbg(priv->adapter, ERROR, "Failed to reset BSS\n"); return -1; } @@ -824,6 +865,16 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, return -1; } + /* Send cmd to FW to enable 11D function */ + state_11d = ENABLE_11D; + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + &state_11d, true)) { + mwifiex_dbg(priv->adapter, ERROR, + "11D: failed to enable 11D\n"); + return -1; + } + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, HostCmd_ACT_GEN_SET, 0, NULL, false)) { mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 06ce3fe660f1..7bc1f850e3b7 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -21,8 +21,70 @@ #include "main.h" #include "11n.h" +#define MWIFIEX_BSS_START_EVT_FIX_SIZE 12 +static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv, + struct sk_buff *event) +{ + int evt_len; + u8 *curr; + u16 tlv_len; + struct mwifiex_ie_types_data *tlv_hdr; + struct ieee_types_wmm_parameter *wmm_param_ie = NULL; + int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK; + + priv->wmm_enabled = false; + skb_pull(event, MWIFIEX_BSS_START_EVT_FIX_SIZE); + evt_len = event->len; + curr = event->data; + + mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:", + event->data, event->len); + while ((evt_len >= sizeof(tlv_hdr->header))) { + tlv_hdr = (struct mwifiex_ie_types_data *)curr; + tlv_len = le16_to_cpu(tlv_hdr->header.len); + + if (evt_len < tlv_len + sizeof(tlv_hdr->header)) + break; + + switch (le16_to_cpu(tlv_hdr->header.type)) { + case WLAN_EID_HT_CAPABILITY: + priv->ap_11n_enabled = true; + break; + + case WLAN_EID_VHT_CAPABILITY: + priv->ap_11ac_enabled = true; + break; + + case WLAN_EID_VENDOR_SPECIFIC: + /* Point the regular IEEE IE 2 bytes into the Marvell IE + * and setup the IEEE IE type and length byte fields + */ + wmm_param_ie = (void *)(curr + 2); + wmm_param_ie->vend_hdr.len = (u8)tlv_len; + wmm_param_ie->vend_hdr.element_id = + WLAN_EID_VENDOR_SPECIFIC; + mwifiex_dbg(priv->adapter, EVENT, + "info: check uap capabilities:\t" + "wmm parameter set count: %d\n", + wmm_param_ie->qos_info_bitmap & mask); + + mwifiex_wmm_setup_ac_downgrade(priv); + priv->wmm_enabled = true; + mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); + break; + + default: + break; + } + + curr += (tlv_len + sizeof(tlv_hdr->header)); + evt_len -= (tlv_len + sizeof(tlv_hdr->header)); + } + + return 0; +} /* * This function handles AP interface specific events generated by firmware. @@ -134,6 +196,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) ETH_ALEN); if (priv->hist_data) mwifiex_hist_data_reset(priv); + mwifiex_check_uap_capabilties(priv, adapter->event_skb); break; case EVENT_UAP_MIC_COUNTERMEASURES: /* For future development */ @@ -229,6 +292,11 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_dbg(adapter, EVENT, "event: Radar detected\n"); mwifiex_11h_handle_radar_detected(priv, adapter->event_skb); break; + case EVENT_BT_COEX_WLAN_PARA_CHANGE: + dev_err(adapter->dev, "EVENT: BT coex wlan param update\n"); + mwifiex_bt_coex_wlan_param_update_event(priv, + adapter->event_skb); + break; default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 61c52fdf945d..87667418af5f 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -97,6 +97,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, struct mwifiex_txinfo *tx_info; int hdr_chop; struct ethhdr *p_ethhdr; + struct mwifiex_sta_node *src_node; uap_rx_pd = (struct uap_rxpd *)(skb->data); rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); @@ -180,6 +181,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, tx_info->bss_type = priv->bss_type; tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT; + src_node = mwifiex_get_sta_entry(priv, rx_pkt_hdr->eth803_hdr.h_source); + if (src_node) { + src_node->stats.last_rx = jiffies; + src_node->stats.rx_bytes += skb->len; + src_node->stats.rx_packets++; + src_node->stats.last_tx_rate = uap_rx_pd->rx_rate; + src_node->stats.last_tx_htinfo = uap_rx_pd->ht_info; + } + if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) { /* Update bridge packet statistics as the * packet is not going to kernel/upper layer. @@ -275,6 +285,8 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type); rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); + ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source); + if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) + le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) { mwifiex_dbg(adapter, ERROR, @@ -282,6 +294,11 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset), le16_to_cpu(uap_rx_pd->rx_pkt_length)); priv->stats.rx_dropped++; + + node = mwifiex_get_sta_entry(priv, ta); + if (node) + node->stats.tx_failed++; + dev_kfree_skb_any(skb); return 0; } @@ -295,7 +312,6 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, return ret; } - memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) { spin_lock_irqsave(&priv->sta_list_spinlock, flags); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 370323a47ecb..790e61953abf 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -329,7 +329,7 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, struct rxpd *rx_pd) { u16 stype; - u8 category, action_code; + u8 category, action_code, *addr2; struct ieee80211_hdr *ieee_hdr = (void *)payload; stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE); @@ -337,21 +337,35 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, switch (stype) { case IEEE80211_STYPE_ACTION: category = *(payload + sizeof(struct ieee80211_hdr)); - action_code = *(payload + sizeof(struct ieee80211_hdr) + 1); - if (category == WLAN_CATEGORY_PUBLIC && - action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { + switch (category) { + case WLAN_CATEGORY_PUBLIC: + action_code = *(payload + sizeof(struct ieee80211_hdr) + + 1); + if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { + addr2 = ieee_hdr->addr2; + mwifiex_dbg(priv->adapter, INFO, + "TDLS discovery response %pM nf=%d, snr=%d\n", + addr2, rx_pd->nf, rx_pd->snr); + mwifiex_auto_tdls_update_peer_signal(priv, + addr2, + rx_pd->snr, + rx_pd->nf); + } + break; + case WLAN_CATEGORY_BACK: + /*we dont indicate BACK action frames to cfg80211*/ + mwifiex_dbg(priv->adapter, INFO, + "drop BACK action frames"); + return -1; + default: mwifiex_dbg(priv->adapter, INFO, - "TDLS discovery response %pM nf=%d, snr=%d\n", - ieee_hdr->addr2, rx_pd->nf, rx_pd->snr); - mwifiex_auto_tdls_update_peer_signal(priv, - ieee_hdr->addr2, - rx_pd->snr, - rx_pd->nf); + "unknown public action frame category %d\n", + category); } - break; default: mwifiex_dbg(priv->adapter, INFO, - "unknown mgmt frame subtype %#x\n", stype); + "unknown mgmt frame subtype %#x\n", stype); + return 0; } return 0; @@ -387,8 +401,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, ieee_hdr = (void *)skb->data; if (ieee80211_is_mgmt(ieee_hdr->frame_control)) { - mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr, - pkt_len, rx_pd); + if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr, + pkt_len, rx_pd)) + return -1; } /* Remove address4 */ memmove(skb->data + sizeof(struct ieee80211_hdr_3addr), @@ -416,12 +431,25 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, */ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) { + struct mwifiex_sta_node *src_node; + struct ethhdr *p_ethhdr; + if (!skb) return -1; priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + p_ethhdr = (void *)skb->data; + src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source); + if (src_node) { + src_node->stats.last_rx = jiffies; + src_node->stats.rx_bytes += skb->len; + src_node->stats.rx_packets++; + } + } + skb->dev = priv->netdev; skb->protocol = eth_type_trans(skb, priv->netdev); skb->ip_summed = CHECKSUM_NONE; diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index ebd5625d13f1..95c1d7c0a2f3 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2961,6 +2961,15 @@ enum rt2800_eeprom_word { #define BCN_TBTT_OFFSET 64 /* + * Hardware has 255 WCID table entries. First 32 entries are reserved for + * shared keys. Since parts of the pairwise key table might be shared with + * the beacon frame buffers 6 & 7 we could only use the first 222 entries. + */ +#define WCID_START 33 +#define WCID_END 222 +#define STA_IDS_SIZE (WCID_END - WCID_START + 2) + +/* * RT2800 driver data structure */ struct rt2800_drv_data { @@ -2971,6 +2980,7 @@ struct rt2800_drv_data { u8 txmixer_gain_24g; u8 txmixer_gain_5g; unsigned int tbtt_tick; + DECLARE_BITMAP(sta_ids, STA_IDS_SIZE); }; #endif /* RT2800_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 0bc5ac56f283..9524564f873b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1381,38 +1381,6 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_config_shared_key); -static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev) -{ - struct mac_wcid_entry wcid_entry; - int idx; - u32 offset; - - /* - * Search for the first free WCID entry and return the corresponding - * index. - * - * Make sure the WCID starts _after_ the last possible shared key - * entry (>32). - * - * Since parts of the pairwise key table might be shared with - * the beacon frame buffers 6 & 7 we should only write into the - * first 222 entries. - */ - for (idx = 33; idx <= 222; idx++) { - offset = MAC_WCID_ENTRY(idx); - rt2800_register_multiread(rt2x00dev, offset, &wcid_entry, - sizeof(wcid_entry)); - if (is_broadcast_ether_addr(wcid_entry.mac)) - return idx; - } - - /* - * Use -1 to indicate that we don't have any more space in the WCID - * table. - */ - return -1; -} - int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key) @@ -1425,7 +1393,7 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * Allow key configuration only for STAs that are * known by the hw. */ - if (crypto->wcid < 0) + if (crypto->wcid > WCID_END) return -ENOSPC; key->hw_key_idx = crypto->wcid; @@ -1455,11 +1423,13 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, { int wcid; struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; /* - * Find next free WCID. + * Search for the first free WCID entry and return the corresponding + * index. */ - wcid = rt2800_find_wcid(rt2x00dev); + wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START; /* * Store selected wcid even if it is invalid so that we can @@ -1471,9 +1441,11 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, * No space left in the device, however, we can still communicate * with the STA -> No error. */ - if (wcid < 0) + if (wcid > WCID_END) return 0; + __set_bit(wcid - WCID_START, drv_data->sta_ids); + /* * Clean up WCID attributes and write STA address to the device. */ @@ -1487,11 +1459,16 @@ EXPORT_SYMBOL_GPL(rt2800_sta_add); int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid) { + struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + + if (wcid > WCID_END) + return 0; /* * Remove WCID entry, no need to clean the attributes as they will * get renewed when the WCID is reused. */ rt2800_config_wcid(rt2x00dev, NULL, wcid); + __clear_bit(wcid - WCID_START, drv_data->sta_ids); return 0; } @@ -7968,11 +7945,11 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* * Don't allow aggregation for stations the hardware isn't aware * of because tx status reports for frames to an unknown station - * always contain wcid=255 and thus we can't distinguish between - * multiple stations which leads to unwanted situations when the - * hw reorders frames due to aggregation. + * always contain wcid=WCID_END+1 and thus we can't distinguish + * between multiple stations which leads to unwanted situations + * when the hw reorders frames due to aggregation. */ - if (sta_priv->wcid < 0) + if (sta_priv->wcid > WCID_END) return 1; switch (action) { diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 1b8a459a412b..3c26ee65a415 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -535,16 +535,8 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); - /* - * If there's no space left in the device table store - * -1 as wcid but tell mac80211 everything went ok. - */ - if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta)) - sta_priv->wcid = -1; - - return 0; + return rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta); } EXPORT_SYMBOL_GPL(rt2x00mac_sta_add); @@ -554,12 +546,6 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); - /* - * If we never sent the STA to the device no need to clean it up. - */ - if (sta_priv->wcid < 0) - return 0; - return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid); } EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index d930c1f78721..ce4da9d79fbd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -1123,23 +1123,22 @@ static void rtl88e_dm_init_txpower_tracking(struct ieee80211_hw *hw) void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; if (!rtlpriv->dm.txpower_tracking) return; - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17)|BIT(16), 0x03); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 88E Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking !!\n"); dm_txpower_track_cb_therm(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index f5ee67cda73a..0aca6f47487c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -1169,23 +1169,22 @@ static void rtl92c_dm_check_txpower_tracking_thermal_meter( struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; if (!rtlpriv->dm.txpower_tracking) return; - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK, 0x60); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 92S Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking direct call!!\n"); rtl92c_dm_txpower_tracking_directcall(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 29983bc96a89..14b819ea8b71 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -233,13 +233,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) pfwheader = (struct rtl92c_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)); + rtlhal->fw_version = pfwheader->version; + rtlhal->fw_subversion = pfwheader->subversion; pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); fwsize = fwsize - sizeof(struct rtl92c_firmware_header); } diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 189859617db8..767358a553fb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -840,6 +840,26 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) rtl92c_set_data_filter(hw, value16); } +static void _rtl92cu_init_beacon_parameters(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010); + + /* TODO: Remove these magic number */ + rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404); + rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME); + rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); + /* Change beacon AIFS to the largest number + * beacause test chip does not contension before sending beacon. + */ + if (IS_NORMAL_CHIP(rtlhal->version)) + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); + else + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); +} + static int _rtl92cu_init_mac(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -887,7 +907,7 @@ static int _rtl92cu_init_mac(struct ieee80211_hw *hw) _rtl92cu_init_usb_aggregation(hw); rtlpriv->cfg->ops->set_bw_mode(hw, NL80211_CHAN_HT20); rtl92c_set_min_space(hw, IS_92C_SERIAL(rtlhal->version)); - rtl92c_init_beacon_parameters(hw, rtlhal->version); + _rtl92cu_init_beacon_parameters(hw); rtl92c_init_ampdu_aggregation(hw); rtl92c_init_beacon_max_error(hw); return err; @@ -987,7 +1007,6 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); int err = 0; - static bool iqk_initialized; unsigned long flags; /* As this function can take a very long time (up to 350 ms) @@ -1038,11 +1057,11 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); if (ppsc->rfpwr_state == ERFON) { rtl92c_phy_set_rfpath_switch(hw, 1); - if (iqk_initialized) { + if (rtlphy->iqk_initialized) { rtl92c_phy_iq_calibrate(hw, true); } else { rtl92c_phy_iq_calibrate(hw, false); - iqk_initialized = true; + rtlphy->iqk_initialized = true; } rtl92c_dm_check_txpower_tracking(hw); rtl92c_phy_lc_calibrate(hw); @@ -1391,6 +1410,9 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw) _CardDisableHWSM(hw); else _CardDisableWithoutHWSM(hw); + + /* after power off we should do iqk again */ + rtlpriv->phy.iqk_initialized = false; } void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) @@ -1451,25 +1473,6 @@ int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) return 0; } -static void _InitBeaconParameters(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - - rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010); - - /* TODO: Remove these magic number */ - rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404); - rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME); - rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); - /* Change beacon AIFS to the largest number - * beacause test chip does not contension before sending beacon. */ - if (IS_NORMAL_CHIP(rtlhal->version)) - rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); - else - rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); -} - static void _beacon_function_enable(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1490,7 +1493,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw) atim_window = 2; /*FIX MERGE */ rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); - _InitBeaconParameters(hw); + _rtl92cu_init_beacon_parameters(hw); rtl_write_byte(rtlpriv, REG_SLOT, 0x09); /* * Force beacon frame transmission even after receiving beacon frame diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index f3db6bc8596a..490a7cf7c702 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -641,21 +641,6 @@ void rtl92c_init_retry_function(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); } -void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, - enum version_8192c version) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - - rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);/* ms */ - rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*ms*/ - rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); - if (IS_NORMAL_CHIP(rtlhal->version)) - rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); - else - rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); -} - void rtl92c_disable_fast_edca(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h index 58548e8f2c41..e34f0f14ccd7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -70,9 +70,6 @@ void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw); void rtl92c_init_rdg_setting(struct ieee80211_hw *hw); void rtl92c_init_retry_function(struct ieee80211_hw *hw); -void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, - enum version_8192c version); - void rtl92c_disable_fast_edca(struct ieee80211_hw *hw); void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 12f6d474b492..c972fa50926d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -108,13 +108,8 @@ void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw) { bool rtstatus; - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool is92c = IS_92C_SERIAL(rtlhal->version); rtstatus = _rtl92cu_phy_config_mac_with_headerfile(hw); - if (is92c && IS_HARDWARE_TYPE_8192CE(rtlhal)) - rtl_write_byte(rtlpriv, 0x14, 0x71); return rtstatus; } @@ -122,7 +117,6 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw) { bool rtstatus = true; struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u16 regval; u32 regval32; u8 b_reg_hwparafile = 1; @@ -134,17 +128,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); - if (IS_HARDWARE_TYPE_8192CE(rtlhal)) { - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA | - FEN_DIO_PCIE | FEN_BB_GLB_RSTn | FEN_BBRSTB); - } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) { - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | - FEN_BB_GLB_RSTn | FEN_BBRSTB); - } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | + FEN_BB_GLB_RSTn | FEN_BBRSTB); regval32 = rtl_read_dword(rtlpriv, 0x87c); rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31))); - if (IS_HARDWARE_TYPE_8192CU(rtlhal)) - rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); + rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); if (b_reg_hwparafile == 1) rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); @@ -162,7 +150,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n"); arraylength = rtlphy->hwparam_tables[MAC_REG].length ; ptrarray = rtlphy->hwparam_tables[MAC_REG].pdata; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CEMAC_2T_ARRAY\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CUMAC_2T_ARRAY\n"); for (i = 0; i < arraylength; i = i + 2) rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); return true; @@ -259,18 +247,18 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, radiob_arraylen = rtlphy->hwparam_tables[RADIOB_2T].length; radiob_array_table = rtlphy->hwparam_tables[RADIOB_2T].pdata; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio_A:RTL8192CERADIOA_2TARRAY\n"); + "Radio_A:RTL8192CURADIOA_2TARRAY\n"); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio_B:RTL8192CE_RADIOB_2TARRAY\n"); + "Radio_B:RTL8192CU_RADIOB_2TARRAY\n"); } else { radioa_arraylen = rtlphy->hwparam_tables[RADIOA_1T].length; radioa_array_table = rtlphy->hwparam_tables[RADIOA_1T].pdata; radiob_arraylen = rtlphy->hwparam_tables[RADIOB_1T].length; radiob_array_table = rtlphy->hwparam_tables[RADIOB_1T].pdata; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio_A:RTL8192CE_RADIOA_1TARRAY\n"); + "Radio_A:RTL8192CU_RADIOA_1TARRAY\n"); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "Radio_B:RTL8192CE_RADIOB_1TARRAY\n"); + "Radio_B:RTL8192CU_RADIOB_1TARRAY\n"); } RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath); switch (rfpath) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index b878d56d2f4d..5624ade92cc0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -66,7 +66,6 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u32 tx_agc[2] = { 0, 0 }, tmpval = 0; @@ -74,14 +73,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, u8 idx1, idx2; u8 *ptr; - if (rtlhal->interface == INTF_PCI) { - if (rtlefuse->eeprom_regulatory != 0) - turbo_scanoff = true; - } else { - if ((rtlefuse->eeprom_regulatory != 0) || - (rtlefuse->external_pa)) - turbo_scanoff = true; - } + if ((rtlefuse->eeprom_regulatory != 0) || (rtlefuse->external_pa)) + turbo_scanoff = true; if (mac->act_scanning) { tx_agc[RF90_PATH_A] = 0x3f3f3f3f; tx_agc[RF90_PATH_B] = 0x3f3f3f3f; @@ -90,11 +83,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, (ppowerlevel[idx1] << 8) | (ppowerlevel[idx1] << 16) | (ppowerlevel[idx1] << 24); - if (rtlhal->interface == INTF_USB) { - if (tx_agc[idx1] > 0x20 && - rtlefuse->external_pa) - tx_agc[idx1] = 0x20; - } + if (tx_agc[idx1] > 0x20 && rtlefuse->external_pa) + tx_agc[idx1] = 0x20; } } else { if (rtlpriv->dm.dynamic_txhighpower_lvl == @@ -452,9 +442,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) udelay(1); switch (rfpath) { case RF90_PATH_A: - rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); - break; case RF90_PATH_B: rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw, (enum radio_path) rfpath); @@ -483,7 +470,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) } } RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n"); - return rtstatus; phy_rf_cfg_fail: return rtstatus; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index cbead007171f..95880fe4106e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -321,7 +321,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, stats->rate = (u8) GET_RX_DESC_RX_MCS(pdesc); stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); - stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) + stats->isfirst_ampdu = (bool)((GET_RX_DESC_PAGGR(pdesc) == 1) && (GET_RX_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index a1be5a68edfb..587b8c505a76 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -1240,23 +1240,22 @@ static void rtl92d_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; if (!rtlpriv->dm.txpower_tracking) return; - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16), 0x03); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 92S Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking direct call!!\n"); rtl92d_dm_txpower_tracking_callback_thermalmeter(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index 575980b88658..9bae5a92e30f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -200,7 +200,6 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter( { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); - static u8 tm_trigger; u8 tx_power_checkcnt = 5; /* 2T2R TP issue */ @@ -215,13 +214,13 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter( return; } - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK, 0x60); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; } else { _rtl92s_dm_txpowertracking_callback_thermalmeter(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c index e77c3a46c94a..3a81cdba8ca3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -909,23 +909,22 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter( void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; if (!rtlpriv->dm.txpower_tracking) return; - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16), 0x03); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 8723be Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking !!\n"); rtl8723be_dm_txpower_tracking_callback_thermalmeter(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c index 342678d2ed42..b57cfd965196 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c @@ -1068,20 +1068,18 @@ static void rtl8812ae_dm_check_txpower_tracking_thermalmeter( struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17) | BIT(16), 0x03); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 8812 Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking direct call!!\n"); rtl8812ae_dm_txpower_tracking_callback_thermalmeter(hw); - tm_trigger = 0; } static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw) @@ -2519,21 +2517,19 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter( void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - static u8 tm_trigger; - - if (!tm_trigger) { + if (!rtlpriv->dm.tm_trigger) { rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16), 0x03); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Trigger 8821ae Thermal Meter!!\n"); - tm_trigger = 1; + rtlpriv->dm.tm_trigger = 1; return; } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Schedule TxPowerTracking !!\n"); rtl8821ae_dm_txpower_tracking_callback_thermalmeter(hw); - tm_trigger = 0; + rtlpriv->dm.tm_trigger = 0; } } diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 51572912c53d..2b770b5e2620 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1665,6 +1665,7 @@ struct rtl_dm { u8 last_dtp_lvl; u8 thermalvalue_avg[AVG_THERMAL_NUM]; u8 thermalvalue_avg_index; + u8 tm_trigger; bool done_txpower; u8 dynamic_txhighpower_lvl; /*Tx high power level */ u8 dm_flag; /*Indicate each dynamic mechanism's status. */ diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index 5695628757ee..d6fbdda2cba3 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -53,10 +53,7 @@ int wl1251_acx_station_id(struct wl1251 *wl) mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); - if (ret < 0) - goto out; -out: kfree(mac); return ret; } diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 5ba6918ca20b..9657f11d48a7 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up) } #endif +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); +#else +static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) +{ + return -ENOTSUPP; +} +static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev) +{ + return -ENOTSUPP; +} +#endif #endif /* LINUX_BCMA_DRIVER_PCI_H_ */ |