diff options
author | David S. Miller <davem@davemloft.net> | 2018-07-23 21:30:03 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-07-23 21:30:03 -0700 |
commit | a527d3f728bfdb6c30c8ecc0b58e695d05d42fc8 (patch) | |
tree | 037021e7b978abe5d744435bc553d66b86079cbb | |
parent | 176bd861ff5affe4a54bcd00266279542142170c (diff) | |
parent | 4a07ed51cae18765c76d9aede5b9830d42db1546 (diff) | |
download | linux-a527d3f728bfdb6c30c8ecc0b58e695d05d42fc8.tar.bz2 |
Merge tag 'wireless-drivers-next-for-davem-2018-07-23' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for 4.19
The first set of patches for 4.19. Only smaller features and bug
fixes, not really anything major. Also included are changes to
include/linux/bitfield.h, we agreed with Johannes that it makes sense
to apply them via wireless-drivers-next.
Major changes:
ath10k
* support channel 173
* fix spectral scan for QCA9984 and QCA9888 chipsets
ath6kl
* add support for Dell Wireless 1537
ti wlcore
* add support for runtime PM
* enable runtime PM autosuspend support
qtnfmac
* support changing MAC address
* enable source MAC address randomization support
libertas
* fix suspend and resume for SDIO cards
mt76
* add software DFS radar pattern detector for mt76x2 based devices
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
79 files changed, 1787 insertions, 704 deletions
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 84f071ac0d84..54ff5930126c 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -1,15 +1,15 @@ config ATH10K - tristate "Atheros 802.11ac wireless cards support" - depends on MAC80211 && HAS_DMA + tristate "Atheros 802.11ac wireless cards support" + depends on MAC80211 && HAS_DMA select ATH_COMMON select CRC32 select WANT_DEV_COREDUMP select ATH10K_CE - ---help--- - This module adds support for wireless adapters based on - Atheros IEEE 802.11ac family of chipsets. + ---help--- + This module adds support for wireless adapters based on + Atheros IEEE 802.11ac family of chipsets. - If you choose to build a module, it'll be called ath10k. + If you choose to build a module, it'll be called ath10k. config ATH10K_CE bool @@ -41,12 +41,12 @@ config ATH10K_USB work in progress and will not fully work. config ATH10K_SNOC - tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" - depends on ATH10K && ARCH_QCOM - ---help--- - This module adds support for integrated WCN3990 chip connected - to system NOC(SNOC). Currently work in progress and will not - fully work. + tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" + depends on ATH10K && ARCH_QCOM + ---help--- + This module adds support for integrated WCN3990 chip connected + to system NOC(SNOC). Currently work in progress and will not + fully work. config ATH10K_DEBUG bool "Atheros ath10k debugging" diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 3b96a43fbda4..18c709c484e7 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1512,7 +1512,7 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); if (ret) { dma_free_coherent(ar->dev, - (nentries * sizeof(struct ce_desc) + + (nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN), src_ring->base_addr_owner_space_unaligned, base_addr); diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index dbeffaef6024..b8fb5382dede 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -383,4 +383,46 @@ static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) return CE_INTERRUPT_SUMMARY; } +/* Host software's Copy Engine configuration. */ +#define CE_ATTR_FLAGS 0 + +/* + * Configuration information for a Copy Engine pipe. + * Passed from Host to Target during startup (one per CE). + * + * NOTE: Structure is shared between Host software and Target firmware! + */ +struct ce_pipe_config { + __le32 pipenum; + __le32 pipedir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; + __le32 reserved; +}; + +/* + * Directions for interconnect pipe configuration. + * These definitions may be used during configuration and are shared + * between Host and Target. + * + * Pipe Directions are relative to the Host, so PIPEDIR_IN means + * "coming IN over air through Target to Host" as with a WiFi Rx operation. + * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" + * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" + * Target since things that are "PIPEDIR_OUT" are coming IN to the Target + * over the interconnect. + */ +#define PIPEDIR_NONE 0 +#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ +#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ +#define PIPEDIR_INOUT 3 /* bidirectional */ + +/* Establish a mapping between a service/direction and a pipe. */ +struct service_to_pipe { + __le32 service_id; + __le32 pipedir; + __le32 pipenum; +}; + #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ad4f6e3c0737..85c58ebbfb26 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -41,10 +41,8 @@ static bool uart_print; static bool skip_otp; static bool rawmode; -/* Enable ATH10K_FW_CRASH_DUMP_REGISTERS and ATH10K_FW_CRASH_DUMP_CE_DATA - * by default. - */ -unsigned long ath10k_coredump_mask = 0x3; +unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); /* FIXME: most of these should be readonly */ module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); @@ -82,6 +80,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -113,6 +112,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -145,6 +145,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -176,6 +177,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -207,6 +209,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -238,6 +241,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -272,6 +276,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -309,6 +314,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, @@ -347,6 +353,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + .spectral_bin_offset = 8, /* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz * or 2x2 160Mhz, long-guard-interval. @@ -388,6 +395,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + .spectral_bin_offset = 8, /* Can do only 1x1 VHT160 or 80+80. 780Mbps is 2x2 80Mhz or * 1x1 160Mhz, long-guard-interval. @@ -423,6 +431,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -456,6 +465,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, @@ -494,6 +504,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .spectral_bin_offset = 0, .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 951dbdd1c9eb..427ee5752bb0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -48,7 +48,8 @@ #define WMI_READY_TIMEOUT (5 * HZ) #define ATH10K_FLUSH_TIMEOUT_HZ (5 * HZ) #define ATH10K_CONNECTION_LOSS_HZ (3 * HZ) -#define ATH10K_NUM_CHANS 40 +#define ATH10K_NUM_CHANS 41 +#define ATH10K_MAX_5G_CHAN 173 /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 0d98c93a3aba..4926722e0c0d 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1727,7 +1727,9 @@ int ath10k_debug_start(struct ath10k *ar) ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); } - if (ar->debug.nf_cal_period) { + if (ar->debug.nf_cal_period && + !test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, ar->debug.nf_cal_period); @@ -1744,7 +1746,9 @@ void ath10k_debug_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); - ath10k_debug_cal_data_fetch(ar); + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) + ath10k_debug_cal_data_fetch(ar); /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid @@ -2367,15 +2371,18 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar, &fops_fw_dbglog); - debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, - &fops_cal_data); + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { + debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, + &fops_cal_data); + + debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, + &fops_nf_cal_period); + } debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar, &fops_ani_enable); - debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, - &fops_nf_cal_period); - if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy, ar, &fops_simulate_radar); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 5d8b97a0ccaa..89157c5b5e5f 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1202,7 +1202,7 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* pass through */ + /* fall through */ case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_32; @@ -1404,7 +1404,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* pass through */ + /* fall through */ case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_64; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 23467e9fefeb..a274bd809a08 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -586,6 +586,9 @@ struct ath10k_hw_params { /* target supporting retention restore on ddr */ bool rri_on_ddr; + + /* Number of bytes to be the offset for each FFT sample */ + int spectral_bin_offset; }; struct htt_rx_desc; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 836e0a47b94a..541bc1c4b2f7 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7737,7 +7737,7 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, return; sinfo->rx_duration = arsta->rx_duration; - sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); if (!arsta->txrate.legacy && !arsta->txrate.nss) return; @@ -7750,7 +7750,7 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.bw = arsta->txrate.bw; } sinfo->txrate.flags = arsta->txrate.flags; - sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } static const struct ieee80211_ops ath10k_ops = { @@ -7870,6 +7870,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = { CHAN5G(161, 5805, 0), CHAN5G(165, 5825, 0), CHAN5G(169, 5845, 0), + CHAN5G(173, 5865, 0), + /* If you add more, you may need to change ATH10K_MAX_5G_CHAN */ + /* And you will definitely need to change ATH10K_NUM_CHANS in core.h */ }; struct ath10k *ath10k_mac_create(size_t priv_size) diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index e52fd83156b6..0ed436657108 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -86,48 +86,6 @@ struct pcie_state { /* PCIE_CONFIG_FLAG definitions */ #define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001 -/* Host software's Copy Engine configuration. */ -#define CE_ATTR_FLAGS 0 - -/* - * Configuration information for a Copy Engine pipe. - * Passed from Host to Target during startup (one per CE). - * - * NOTE: Structure is shared between Host software and Target firmware! - */ -struct ce_pipe_config { - __le32 pipenum; - __le32 pipedir; - __le32 nentries; - __le32 nbytes_max; - __le32 flags; - __le32 reserved; -}; - -/* - * Directions for interconnect pipe configuration. - * These definitions may be used during configuration and are shared - * between Host and Target. - * - * Pipe Directions are relative to the Host, so PIPEDIR_IN means - * "coming IN over air through Target to Host" as with a WiFi Rx operation. - * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" - * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" - * Target since things that are "PIPEDIR_OUT" are coming IN to the Target - * over the interconnect. - */ -#define PIPEDIR_NONE 0 -#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ -#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ -#define PIPEDIR_INOUT 3 /* bidirectional */ - -/* Establish a mapping between a service/direction and a pipe. */ -struct service_to_pipe { - __le32 service_id; - __le32 pipedir; - __le32 pipenum; -}; - /* Per-pipe state. */ struct ath10k_pci_pipe { /* Handle of underlying Copy Engine */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index a3a7042fe13a..fa1843a7e0fd 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -14,19 +14,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/module.h> +#include <linux/clk.h> #include <linux/kernel.h> -#include "debug.h" -#include "hif.h" -#include "htc.h" -#include "ce.h" -#include "snoc.h" +#include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include <linux/clk.h> -#define WCN3990_CE_ATTR_FLAGS 0 + +#include "ce.h" +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "snoc.h" + #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -449,7 +450,7 @@ static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) static void ath10k_snoc_rx_replenish_retry(struct timer_list *t) { - struct ath10k_pci *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); + struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); struct ath10k *ar = ar_snoc->ar; ath10k_snoc_rx_post(ar); @@ -820,7 +821,7 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; -int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) +static int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); int i; @@ -868,7 +869,7 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) return done; } -void ath10k_snoc_init_napi(struct ath10k *ar) +static void ath10k_snoc_init_napi(struct ath10k *ar) { netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, ATH10K_NAPI_BUDGET); @@ -1303,13 +1304,13 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; - ath10k_snoc_resource_init(ar); + ret = ath10k_snoc_resource_init(ar); if (ret) { ath10k_warn(ar, "failed to initialize resource: %d\n", ret); goto err_core_destroy; } - ath10k_snoc_setup_resource(ar); + ret = ath10k_snoc_setup_resource(ar); if (ret) { ath10k_warn(ar, "failed to setup resource: %d\n", ret); goto err_core_destroy; @@ -1388,25 +1389,7 @@ static struct platform_driver ath10k_snoc_driver = { .of_match_table = ath10k_snoc_dt_match, }, }; - -static int __init ath10k_snoc_init(void) -{ - int ret; - - ret = platform_driver_register(&ath10k_snoc_driver); - if (ret) - pr_err("failed to register ath10k snoc driver: %d\n", - ret); - - return ret; -} -module_init(ath10k_snoc_init); - -static void __exit ath10k_snoc_exit(void) -{ - platform_driver_unregister(&ath10k_snoc_driver); -} -module_exit(ath10k_snoc_exit); +module_platform_driver(ath10k_snoc_driver); MODULE_AUTHOR("Qualcomm"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 05dc98f46ccd..f9e530189d48 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -19,7 +19,6 @@ #include "hw.h" #include "ce.h" -#include "pci.h" struct ath10k_snoc_drv_priv { enum ath10k_hw_rev hw_rev; diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index af6995de7e00..653b6d013207 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -145,7 +145,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar, fft_sample->noise = __cpu_to_be16(phyerr->nf_chains[chain_idx]); bins = (u8 *)fftr; - bins += sizeof(*fftr); + bins += sizeof(*fftr) + ar->hw_params.spectral_bin_offset; fft_sample->tsf = __cpu_to_be64(tsf); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f97ab795cf2e..877249ac6fd4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2366,7 +2366,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) */ if (channel >= 1 && channel <= 14) { status->band = NL80211_BAND_2GHZ; - } else if (channel >= 36 && channel <= 169) { + } else if (channel >= 36 && channel <= ATH10K_MAX_5G_CHAN) { status->band = NL80211_BAND_5GHZ; } else { /* Shouldn't happen unless list of advertised channels to @@ -4602,10 +4602,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ev = (struct wmi_pdev_tpc_config_event *)skb->data; - tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); - if (!tpc_stats) - return; - num_tx_chain = __le32_to_cpu(ev->num_tx_chain); if (num_tx_chain > WMI_TPC_TX_N_CHAIN) { @@ -4614,6 +4610,10 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) return; } + tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); + if (!tpc_stats) + return; + ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table, num_tx_chain); @@ -5018,13 +5018,11 @@ static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, void *vaddr; pool_size = num_units * round_up(unit_len, 4); - vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); + vaddr = dma_zalloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); if (!vaddr) return -ENOMEM; - memset(vaddr, 0, pool_size); - ar->wmi.mem_chunks[idx].vaddr = vaddr; ar->wmi.mem_chunks[idx].paddr = paddr; ar->wmi.mem_chunks[idx].len = pool_size; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index f23c851765df..05140d8baa36 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -670,6 +670,7 @@ ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) break; case NL80211_IFTYPE_ADHOC: AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); + /* fall through */ default: /* On non-STA modes timer1 is used as next DMA * beacon alert (DBA) timer and timer2 as next diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0687697d5e2d..e121187f371f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1811,20 +1811,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, if (vif->target_stats.rx_byte) { sinfo->rx_bytes = vif->target_stats.rx_byte; - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_packets = vif->target_stats.rx_pkt; - sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); } if (vif->target_stats.tx_byte) { sinfo->tx_bytes = vif->target_stats.tx_byte; - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); sinfo->tx_packets = vif->target_stats.tx_pkt; - sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); } sinfo->signal = vif->target_stats.cs_rssi; - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); rate = vif->target_stats.tx_ucast_rate; @@ -1857,12 +1857,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); if (test_bit(CONNECTED, &vif->flags) && test_bit(DTIM_PERIOD_AVAIL, &vif->flags) && vif->nw_type == INFRA_NETWORK) { - sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period; sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int; @@ -3899,16 +3899,19 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) switch (ar->hw.cap) { case WMI_11AN_CAP: ht = true; + /* fall through */ case WMI_11A_CAP: band_5gig = true; break; case WMI_11GN_CAP: ht = true; + /* fall through */ case WMI_11G_CAP: band_2gig = true; break; case WMI_11AGN_CAP: ht = true; + /* fall through */ case WMI_11AG_CAP: band_2gig = true; band_5gig = true; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 2195b1b7a8a6..bb50680580f3 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1415,6 +1415,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = { {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x18))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x19))}, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 7922550c2159..ef2dd68d3f77 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -583,12 +583,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) case 0x5: REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); + /* fall through */ case 0x3: if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); break; } + /* else: fall through */ case 0x1: case 0x2: case 0x7: diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 61a9b85045d2..713291881208 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -119,6 +119,7 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) aModeRefSel = 2; if (aModeRefSel) break; + /* else: fall through */ case 1: default: aModeRefSel = 0; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f685843a2ff3..0a6eb8a8c1ed 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -538,7 +538,7 @@ static int read_file_interrupt(struct seq_file *file, void *data) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { PR_IS("RXLP", rxlp); PR_IS("RXHP", rxhp); - PR_IS("WATHDOG", bb_watchdog); + PR_IS("WATCHDOG", bb_watchdog); } else { PR_IS("RX", rxok); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b6663c80e7dd..5eb1c0aea41d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1928,6 +1928,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: flush = true; + /* fall through */ case IEEE80211_AMPDU_TX_STOP_CONT: ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 78946f28d0c7..013d056a7a4c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -302,14 +302,14 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, sinfo->generation = wil->sinfo_gen; - sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | - BIT(NL80211_STA_INFO_TX_BYTES) | - BIT(NL80211_STA_INFO_RX_PACKETS) | - BIT(NL80211_STA_INFO_TX_PACKETS) | - BIT(NL80211_STA_INFO_RX_BITRATE) | - BIT(NL80211_STA_INFO_TX_BITRATE) | - BIT(NL80211_STA_INFO_RX_DROP_MISC) | - BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->filled = BIT_ULL(NL80211_STA_INFO_RX_BYTES) | + BIT_ULL(NL80211_STA_INFO_TX_BYTES) | + BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_RX_BITRATE) | + BIT_ULL(NL80211_STA_INFO_TX_BITRATE) | + BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->txrate.flags = RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); @@ -322,7 +322,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_vif_fwconnected, vif->status)) { - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) sinfo->signal = reply.evt.rssi; diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index b01dc34d55af..3ed3d9f6aae9 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -1516,10 +1516,9 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, priv->present_callback = card_present; priv->card = card; priv->firmware = NULL; - priv->firmware_id[0] = '\0'; priv->firmware_type = fw_type; if (firmware) /* module parameter */ - strcpy(priv->firmware_id, firmware); + strlcpy(priv->firmware_id, firmware, sizeof(priv->firmware_id)); priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; priv->station_state = STATION_STATE_DOWN; priv->do_rx_crc = 0; @@ -2646,14 +2645,9 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; } - if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { - rc = -ENOMEM; - break; - } - - if (copy_from_user(new_firmware, com.data, com.len)) { - kfree(new_firmware); - rc = -EFAULT; + new_firmware = memdup_user(com.data, com.len); + if (IS_ERR(new_firmware)) { + rc = PTR_ERR(new_firmware); break; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b6122aad639e..24c4e18e7d80 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2434,7 +2434,7 @@ 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); + si->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS); sfu = &si->sta_flags; sfu->mask = BIT(NL80211_STA_FLAG_WME) | BIT(NL80211_STA_FLAG_AUTHENTICATED) | @@ -2470,7 +2470,7 @@ static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si) brcmf_err("Failed to get bss info (%d)\n", err); goto out_kfree; } - si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + si->filled |= BIT_ULL(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); @@ -2501,7 +2501,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, brcmf_err("BRCMF_C_GET_RATE error (%d)\n", err); return err; } - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); sinfo->txrate.legacy = rate * 5; memset(&scbval, 0, sizeof(scbval)); @@ -2512,7 +2512,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, return err; } rssi = le32_to_cpu(scbval.val); - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi; err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_GET_PKTCNTS, &pktcnt, @@ -2521,10 +2521,10 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, brcmf_err("BRCMF_C_GET_GET_PKTCNTS error (%d)\n", err); return err; } - sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) | - BIT(NL80211_STA_INFO_RX_DROP_MISC) | - BIT(NL80211_STA_INFO_TX_PACKETS) | - BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) | + BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->rx_packets = le32_to_cpu(pktcnt.rx_good_pkt); sinfo->rx_dropped_misc = le32_to_cpu(pktcnt.rx_bad_pkt); sinfo->tx_packets = le32_to_cpu(pktcnt.tx_good_pkt); @@ -2571,7 +2571,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, } } brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver)); - sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->filled = BIT_ULL(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); @@ -2581,33 +2581,33 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, 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->filled |= BIT_ULL(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->filled |= BIT_ULL(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->filled |= BIT_ULL(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->filled |= BIT_ULL(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->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate) / 100; } if (sinfo->rx_packets) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate) / 100; } if (le16_to_cpu(sta_info_le.ver) >= 4) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->filled |= BIT_ULL(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->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes); } total_rssi = 0; @@ -2623,10 +2623,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, } } if (count_rssi) { - sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); sinfo->chains = count_rssi; - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); total_rssi /= count_rssi; sinfo->signal = total_rssi; } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED, @@ -2639,7 +2639,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, goto done; } else { rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi; brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 72954fd6df3b..b1f702faff4f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -21,6 +21,7 @@ #include <net/cfg80211.h> #include <net/rtnetlink.h> #include <net/addrconf.h> +#include <net/ieee80211_radiotap.h> #include <net/ipv6.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> @@ -404,6 +405,30 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) netif_rx_ni(skb); } +void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb) +{ + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) { + /* Do nothing */ + } else { + struct ieee80211_radiotap_header *radiotap; + + /* TODO: use RX status to fill some radiotap data */ + radiotap = skb_push(skb, sizeof(*radiotap)); + memset(radiotap, 0, sizeof(*radiotap)); + radiotap->it_len = cpu_to_le16(sizeof(*radiotap)); + + /* TODO: 4 bytes with receive status? */ + skb->len -= 4; + } + + skb->dev = ifp->ndev; + skb_reset_mac_header(skb); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + brcmf_netif_rx(ifp, skb); +} + static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, struct brcmf_if **ifp) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 401f50458686..dcf6e27cc16f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -121,6 +121,7 @@ struct brcmf_pub { struct brcmf_if *iflist[BRCMF_MAX_IFS]; s32 if2bss[BRCMF_MAX_IFS]; + struct brcmf_if *mon_if; struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; @@ -216,6 +217,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); +void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb); void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); int __init brcmf_core_init(void); void __exit brcmf_core_exit(void); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 800a423c7bc2..4db4d444407a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -48,6 +48,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { { BRCMF_FEAT_MBSS, "mbss" }, { BRCMF_FEAT_MCHAN, "mchan" }, { BRCMF_FEAT_P2P, "p2p" }, + { BRCMF_FEAT_MONITOR, "monitor" }, + { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, }; #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index d1193825e559..0b4974df353a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -33,6 +33,8 @@ * MFP: 802.11w Management Frame Protection. * GSCAN: enhanced scan offload feature. * FWSUP: Firmware supplicant. + * MONITOR: firmware can pass monitor packets to host. + * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -48,7 +50,9 @@ BRCMF_FEAT_DEF(WOWL_ARP_ND) \ BRCMF_FEAT_DEF(MFP) \ BRCMF_FEAT_DEF(GSCAN) \ - BRCMF_FEAT_DEF(FWSUP) + BRCMF_FEAT_DEF(FWSUP) \ + BRCMF_FEAT_DEF(MONITOR) \ + BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 4b290705e3e6..d5bb81e88762 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -32,11 +32,30 @@ #define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ #define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002 -#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 */ +#define BRCMF_STA_BRCM 0x00000001 /* Running a Broadcom driver */ +#define BRCMF_STA_WME 0x00000002 /* WMM association */ +#define BRCMF_STA_NONERP 0x00000004 /* No ERP */ +#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */ +#define BRCMF_STA_ASSOC 0x00000010 /* Associated */ +#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */ +#define BRCMF_STA_WDS 0x00000040 /* Wireless Distribution System */ +#define BRCMF_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ +#define BRCMF_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ +#define BRCMF_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ +#define BRCMF_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ +#define BRCMF_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ +#define BRCMF_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ +#define BRCMF_STA_N_CAP 0x00002000 /* STA 802.11n capable */ +#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ +#define BRCMF_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ +#define BRCMF_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ +#define BRCMF_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ +#define BRCMF_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ +#define BRCMF_STA_RIFS_CAP 0x00080000 /* rifs enabled */ +#define BRCMF_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ +#define BRCMF_STA_WPS 0x00200000 /* WPS state */ +#define BRCMF_STA_DWDS_CAP 0x01000000 /* DWDS CAP */ +#define BRCMF_STA_DWDS 0x02000000 /* DWDS active */ /* size of brcmf_scan_params not including variable length array */ #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 @@ -155,6 +174,8 @@ #define BRCMF_MFP_CAPABLE 1 #define BRCMF_MFP_REQUIRED 2 +#define BRCMF_VHT_CAP_MCS_MAP_NSS_MAX 8 + /* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each * ioctl. It is relatively small because firmware has small maximum size input * playload restriction for ioctls. @@ -531,6 +552,8 @@ struct brcmf_sta_info_le { /* w/hi bit set if basic */ __le32 in; /* seconds elapsed since associated */ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */ + + /* Fields valid for ver >= 3 */ __le32 tx_pkts; /* # of packets transmitted */ __le32 tx_failures; /* # of packets failed */ __le32 rx_ucast_pkts; /* # of unicast packets received */ @@ -539,6 +562,8 @@ struct brcmf_sta_info_le { __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 */ + + /* Fields valid for ver >= 4 */ __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 */ @@ -575,6 +600,14 @@ struct brcmf_sta_info_le { */ __le32 rx_pkts_retried; /* # rx with retry bit set */ __le32 tx_rate_fallback; /* lowest fallback TX rate */ + + /* Fields valid for ver >= 5 */ + struct { + __le32 count; /* # rates in this set */ + u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ + u8 mcs[BRCMF_MCSSET_LEN]; /* supported mcs index bit map */ + __le16 vht_mcs[BRCMF_VHT_CAP_MCS_MAP_NSS_MAX]; /* supported mcs index bit map per nss */ + } rateset_adv; }; struct brcmf_chanspec_list { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index c40ba8855cd5..4e8397a0cbc8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -69,6 +69,8 @@ #define BRCMF_MSGBUF_MAX_EVENTBUF_POST 8 #define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3 0x01 +#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11 0x02 +#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK 0x07 #define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT 5 #define BRCMF_MSGBUF_TX_FLUSH_CNT1 32 @@ -1128,6 +1130,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) struct sk_buff *skb; u16 data_offset; u16 buflen; + u16 flags; u32 idx; struct brcmf_if *ifp; @@ -1137,6 +1140,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) data_offset = le16_to_cpu(rx_complete->data_offset); buflen = le16_to_cpu(rx_complete->data_len); idx = le32_to_cpu(rx_complete->msg.request_id); + flags = le16_to_cpu(rx_complete->flags); skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, msgbuf->rx_pktids, idx); @@ -1150,6 +1154,20 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) skb_trim(skb, buflen); + if ((flags & BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK) == + BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11) { + ifp = msgbuf->drvr->mon_if; + + if (!ifp) { + brcmf_err("Received unexpected monitor pkt\n"); + brcmu_pkt_buf_free_skb(skb); + return; + } + + brcmf_netif_mon_rx(ifp, skb); + return; + } + ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx); if (!ifp || !ifp->ndev) { brcmf_err("Received pkt for invalid ifidx %d\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index 3a13d176b221..35e3b101e5cf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -159,7 +159,7 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr) { u16 data; - if ((addr == RADIO_IDCODE)) + if (addr == RADIO_IDCODE) return 0xffff; switch (pi->pubpi.phy_type) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 1a187557982e..bedec1606caa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -16904,7 +16904,7 @@ static void wlc_phy_workarounds_nphy_rev3(struct brcms_phy *pi) } } -void wlc_phy_workarounds_nphy_rev1(struct brcms_phy *pi) +static void wlc_phy_workarounds_nphy_rev1(struct brcms_phy *pi) { static const u8 rfseq_rx2tx_events[] = { NPHY_RFSEQ_CMD_NOP, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c index b9672da24a9d..b24bc57ca91b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c @@ -213,7 +213,7 @@ static const s16 log_table[] = { 30498, 31267, 32024, - 32768 + 32767 }; #define LOG_TABLE_SIZE 32 /* log_table size */ diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index b8fd3cc90634..1ad83ef5f202 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -692,7 +692,7 @@ static void printk_buf(int level, const u8 * data, u32 len) static void schedule_reset(struct ipw2100_priv *priv) { - unsigned long now = get_seconds(); + time64_t now = ktime_get_boottime_seconds(); /* If we haven't received a reset request within the backoff period, * then we can reset the backoff interval so this reset occurs @@ -701,10 +701,10 @@ static void schedule_reset(struct ipw2100_priv *priv) (now - priv->last_reset > priv->reset_backoff)) priv->reset_backoff = 0; - priv->last_reset = get_seconds(); + priv->last_reset = now; if (!(priv->status & STATUS_RESET_PENDING)) { - IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", + IPW_DEBUG_INFO("%s: Scheduling firmware restart (%llds).\n", priv->net_dev->name, priv->reset_backoff); netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); @@ -2079,7 +2079,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) memcpy(priv->bssid, bssid, ETH_ALEN); priv->status |= STATUS_ASSOCIATING; - priv->connect_start = get_seconds(); + priv->connect_start = ktime_get_boottime_seconds(); schedule_delayed_work(&priv->wx_event_work, HZ / 10); } @@ -4070,8 +4070,8 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, #define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x) if (priv->status & STATUS_ASSOCIATED) - len += sprintf(buf + len, "connected: %lu\n", - get_seconds() - priv->connect_start); + len += sprintf(buf + len, "connected: %llu\n", + ktime_get_boottime_seconds() - priv->connect_start); else len += sprintf(buf + len, "not connected\n"); @@ -4108,7 +4108,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, DUMP_VAR(txq_stat.lo, "d"); DUMP_VAR(ieee->scans, "d"); - DUMP_VAR(reset_backoff, "d"); + DUMP_VAR(reset_backoff, "lld"); return len; } @@ -6437,7 +6437,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) pci_disable_device(pci_dev); pci_set_power_state(pci_dev, PCI_D3hot); - priv->suspend_at = get_seconds(); + priv->suspend_at = ktime_get_boottime_seconds(); mutex_unlock(&priv->action_mutex); @@ -6482,7 +6482,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) * the queue of needed */ netif_device_attach(dev); - priv->suspend_time = get_seconds() - priv->suspend_at; + priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at; /* Bring the device back up */ if (!(priv->status & STATUS_RF_KILL_SW)) diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h index ce3e35f6b60f..8c11c7fa2eef 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h @@ -491,7 +491,7 @@ struct ipw2100_priv { /* Statistics */ int resets; - int reset_backoff; + time64_t reset_backoff; /* Context */ u8 essid[IW_ESSID_MAX_SIZE]; @@ -500,8 +500,8 @@ struct ipw2100_priv { u8 channel; int last_mode; - unsigned long connect_start; - unsigned long last_reset; + time64_t connect_start; + time64_t last_reset; u32 channel_mask; u32 fatal_error; @@ -581,9 +581,9 @@ struct ipw2100_priv { int user_requested_scan; - /* Track time in suspend */ - unsigned long suspend_at; - unsigned long suspend_time; + /* Track time in suspend, using CLOCK_BOOTTIME */ + time64_t suspend_at; + time64_t suspend_time; u32 interrupts; int tx_interrupts; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 8a858f7e36f4..9644e7b93645 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -7112,7 +7112,7 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) { u32 ret = 0; - if ((priv == NULL)) + if (!priv) return 0; if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION)) @@ -11888,7 +11888,7 @@ static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); - priv->suspend_at = get_seconds(); + priv->suspend_at = ktime_get_boottime_seconds(); return 0; } @@ -11925,7 +11925,7 @@ static int ipw_pci_resume(struct pci_dev *pdev) * the queue of needed */ netif_device_attach(dev); - priv->suspend_time = get_seconds() - priv->suspend_at; + priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at; /* Bring the device back up */ schedule_work(&priv->up); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index aa301d1eee3c..f98ab1f71edd 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -1343,9 +1343,9 @@ struct ipw_priv { s8 tx_power; - /* Track time in suspend */ - unsigned long suspend_at; - unsigned long suspend_time; + /* Track time in suspend using CLOCK_BOOTIME */ + time64_t suspend_at; + time64_t suspend_time; #ifdef CONFIG_PM u32 pm_state[16]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a6e072234398..26021bc55e98 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4216,7 +4216,7 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, if (mvmsta->avg_energy) { sinfo->signal_avg = mvmsta->avg_energy; - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); } if (!fw_has_capa(&mvm->fw->ucode_capa, @@ -4240,11 +4240,11 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, sinfo->rx_beacon = mvmvif->beacon_stats.num_beacons + mvmvif->beacon_stats.accu_num_beacons; - sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX); if (mvmvif->beacon_stats.avg_signal) { /* firmware only reports a value after RXing a few beacons */ sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal; - sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG); } unlock: mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index f99031cfdf86..57edfada0665 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1559,10 +1559,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, int ret; size_t i; - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | - BIT(NL80211_STA_INFO_TX_PACKETS) | - BIT(NL80211_STA_INFO_RX_BYTES) | - BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES) | + BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_RX_BYTES) | + BIT_ULL(NL80211_STA_INFO_RX_PACKETS); sinfo->tx_bytes = priv->dev->stats.tx_bytes; sinfo->tx_packets = priv->dev->stats.tx_packets; sinfo->rx_bytes = priv->dev->stats.rx_bytes; @@ -1572,14 +1572,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, ret = lbs_get_rssi(priv, &signal, &noise); if (ret == 0) { sinfo->signal = signal; - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } /* Convert priv->cur_rate from hw_value to NL80211 value */ for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { if (priv->cur_rate == lbs_rates[i].hw_value) { sinfo->txrate.legacy = lbs_rates[i].bitrate; - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); break; } } diff --git a/drivers/net/wireless/marvell/libertas/dev.h b/drivers/net/wireless/marvell/libertas/dev.h index dd1ee1f0af48..469134930026 100644 --- a/drivers/net/wireless/marvell/libertas/dev.h +++ b/drivers/net/wireless/marvell/libertas/dev.h @@ -104,6 +104,7 @@ struct lbs_private { u8 fw_ready; u8 surpriseremoved; u8 setup_fw_on_resume; + u8 power_up_on_resume; int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); int (*power_save) (struct lbs_private *priv); diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 2300e796c6ab..43743c26c071 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1290,15 +1290,23 @@ static void if_sdio_remove(struct sdio_func *func) static int if_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - int ret; struct if_sdio_card *card = sdio_get_drvdata(func); + struct lbs_private *priv = card->priv; + int ret; mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); + priv->power_up_on_resume = false; /* If we're powered off anyway, just let the mmc layer remove the * card. */ - if (!lbs_iface_active(card->priv)) - return -ENOSYS; + if (!lbs_iface_active(priv)) { + if (priv->fw_ready) { + priv->power_up_on_resume = true; + if_sdio_power_off(card); + } + + return 0; + } dev_info(dev, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags); @@ -1306,9 +1314,14 @@ static int if_sdio_suspend(struct device *dev) /* If we aren't being asked to wake on anything, we should bail out * and let the SD stack power down the card. */ - if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { + if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { dev_info(dev, "Suspend without wake params -- powering down card\n"); - return -ENOSYS; + if (priv->fw_ready) { + priv->power_up_on_resume = true; + if_sdio_power_off(card); + } + + return 0; } if (!(flags & MMC_PM_KEEP_POWER)) { @@ -1321,7 +1334,7 @@ static int if_sdio_suspend(struct device *dev) if (ret) return ret; - ret = lbs_suspend(card->priv); + ret = lbs_suspend(priv); if (ret) return ret; @@ -1336,6 +1349,11 @@ static int if_sdio_resume(struct device *dev) dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func)); + if (card->priv->power_up_on_resume) { + if_sdio_power_on(card); + wait_event(card->pwron_waitq, card->priv->fw_ready); + } + ret = lbs_resume(card->priv); return ret; diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index ffea610f67e2..c67a8e7be310 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -614,6 +614,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, struct if_usb_card *cardp, struct lbs_private *priv) { + unsigned long flags; u8 i; if (recvlength > LBS_CMD_BUFFER_SIZE) { @@ -623,9 +624,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - BUG_ON(!in_interrupt()); - - spin_lock(&priv->driver_lock); + spin_lock_irqsave(&priv->driver_lock, flags); i = (priv->resp_idx == 0) ? 1 : 0; BUG_ON(priv->resp_len[i]); @@ -635,7 +634,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, kfree_skb(skb); lbs_notify_command_response(priv, i); - spin_unlock(&priv->driver_lock); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_usbd(&cardp->udev->dev, "Wake up main thread to handle cmd response\n"); diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index 5153922e7ce1..e92fc5001171 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -603,6 +603,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, struct if_usb_card *cardp, struct lbtf_private *priv) { + unsigned long flags; + if (recvlength > LBS_CMD_BUFFER_SIZE) { lbtf_deb_usbd(&cardp->udev->dev, "The receive buffer is too large\n"); @@ -610,14 +612,12 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - BUG_ON(!in_interrupt()); - - spin_lock(&priv->driver_lock); + spin_lock_irqsave(&priv->driver_lock, flags); memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, recvlength - MESSAGE_HEADER_LEN); kfree_skb(skb); lbtf_cmd_response_rx(priv); - spin_unlock(&priv->driver_lock); + spin_unlock_irqrestore(&priv->driver_lock, flags); } /** diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 4b5ae9098504..c02e02c17c9c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1353,17 +1353,17 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, { u32 rate; - sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) | - BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) | - BIT(NL80211_STA_INFO_TX_BITRATE) | - BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->filled = BIT_ULL(NL80211_STA_INFO_RX_BYTES) | BIT_ULL(NL80211_STA_INFO_TX_BYTES) | + BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_BITRATE) | + BIT_ULL(NL80211_STA_INFO_SIGNAL) | BIT_ULL(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->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->inactive_time = jiffies_to_msecs(jiffies - node->stats.last_rx); @@ -1413,7 +1413,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, sinfo->txrate.legacy = rate * 5; if (priv->bss_mode == NL80211_IFTYPE_STATION) { - sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & WLAN_CAPABILITY_SHORT_PREAMBLE) diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index 1e6a62c69ac5..5ce85d5727e4 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -289,32 +289,6 @@ int mwifiex_uap_recv_packet(struct mwifiex_private *priv, src_node->stats.rx_packets++; } - skb->dev = priv->netdev; - skb->protocol = eth_type_trans(skb, priv->netdev); - skb->ip_summed = CHECKSUM_NONE; - - /* This is required only in case of 11n and USB/PCIE as we alloc - * a buffer of 4K only if its 11N (to be able to receive 4K - * AMSDU packets). In case of SD we allocate buffers based - * on the size of packet and hence this is not needed. - * - * Modifying the truesize here as our allocation for each - * skb is 4K but we only receive 2K packets and this cause - * the kernel to start dropping packets in case where - * application has allocated buffer based on 2K size i.e. - * if there a 64K packet received (in IP fragments and - * application allocates 64K to receive this packet but - * this packet would almost double up because we allocate - * each 1.5K fragment in 4K and pass it up. As soon as the - * 64K limit hits kernel will start to drop rest of the - * fragments. Currently we fail the Filesndl-ht.scr script - * for UDP, hence this fix - */ - if ((adapter->iface_type == MWIFIEX_USB || - adapter->iface_type == MWIFIEX_PCIE) && - (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) - skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); - if (is_multicast_ether_addr(p_ethhdr->h_dest) || mwifiex_get_sta_entry(priv, p_ethhdr->h_dest)) { if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) @@ -350,6 +324,32 @@ int mwifiex_uap_recv_packet(struct mwifiex_private *priv, return 0; } + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + skb->ip_summed = CHECKSUM_NONE; + + /* This is required only in case of 11n and USB/PCIE as we alloc + * a buffer of 4K only if its 11N (to be able to receive 4K + * AMSDU packets). In case of SD we allocate buffers based + * on the size of packet and hence this is not needed. + * + * Modifying the truesize here as our allocation for each + * skb is 4K but we only receive 2K packets and this cause + * the kernel to start dropping packets in case where + * application has allocated buffer based on 2K size i.e. + * if there a 64K packet received (in IP fragments and + * application allocates 64K to receive this packet but + * this packet would almost double up because we allocate + * each 1.5K fragment in 4K and pass it up. As soon as the + * 64K limit hits kernel will start to drop rest of the + * fragments. Currently we fail the Filesndl-ht.scr script + * for UDP, hence this fix + */ + if ((adapter->iface_type == MWIFIEX_USB || + adapter->iface_type == MWIFIEX_PCIE) && + skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE) + skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); + /* Forward multicast/broadcast packet to upper layer*/ if (in_interrupt()) netif_rx(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d2166fbf50ff..96e9798bb8a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -390,6 +390,18 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev); int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_dev *dev); +/* increment with wrap-around */ +static inline int mt76_incr(int val, int size) +{ + return (val + 1) & (size - 1); +} + +/* decrement with wrap-around */ +static inline int mt76_decr(int val, int size) +{ + return (val - 1) & (size - 1); +} + static inline struct ieee80211_txq * mtxq_to_txq(struct mt76_txq *mtxq) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index dc12bbdbb2ee..71fcfa44fb2e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -27,6 +27,7 @@ #include <linux/mutex.h> #include <linux/bitops.h> #include <linux/kfifo.h> +#include <linux/average.h> #define MT7662_FIRMWARE "mt7662.bin" #define MT7662_ROM_PATCH "mt7662_rom_patch.bin" @@ -47,6 +48,8 @@ #include "mt76x2_mac.h" #include "mt76x2_dfs.h" +DECLARE_EWMA(signal, 10, 8) + struct mt76x2_mcu { struct mutex mutex; @@ -69,9 +72,8 @@ struct mt76x2_calibration { u8 agc_gain_init[MT_MAX_CHAINS]; u8 agc_gain_cur[MT_MAX_CHAINS]; - int avg_rssi[MT_MAX_CHAINS]; - int avg_rssi_all; - + u16 false_cca; + s8 avg_rssi_all; s8 agc_gain_adjust; s8 low_gain; @@ -120,10 +122,13 @@ struct mt76x2_dev { u8 beacon_mask; u8 beacon_data_mask; - u32 rxfilter; + u8 tbtt_count; + u16 beacon_int; u16 chainmask; + u32 rxfilter; + struct mt76x2_calibration cal; s8 target_power; @@ -149,6 +154,9 @@ struct mt76x2_sta { struct mt76x2_vif *vif; struct mt76x2_tx_status status; int n_frames; + + struct ewma_signal rssi; + int inactive_count; }; static inline bool is_mt7612(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 955ea3e692dd..74725902e6dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -91,12 +91,20 @@ mt76x2_dfs_stat_read(struct seq_file *file, void *data) struct mt76x2_dev *dev = file->private; struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + seq_printf(file, "allocated sequences:\t%d\n", + dfs_pd->seq_stats.seq_pool_len); + seq_printf(file, "used sequences:\t\t%d\n", + dfs_pd->seq_stats.seq_len); + seq_puts(file, "\n"); + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { seq_printf(file, "engine: %d\n", i); seq_printf(file, " hw pattern detected:\t%d\n", dfs_pd->stats[i].hw_pattern); seq_printf(file, " hw pulse discarded:\t%d\n", dfs_pd->stats[i].hw_pulse_discarded); + seq_printf(file, " sw pattern detected:\t%d\n", + dfs_pd->stats[i].sw_pattern); } return 0; @@ -115,6 +123,18 @@ static const struct file_operations fops_dfs_stat = { .release = single_release, }; +static int read_agc(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = dev_get_drvdata(file->private); + + seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); + seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); + seq_printf(file, "false_cca: %d\n", dev->cal.false_cca); + seq_printf(file, "agc_gain_adjust: %d\n", dev->cal.agc_gain_adjust); + + return 0; +} + void mt76x2_init_debugfs(struct mt76x2_dev *dev) { struct dentry *dir; @@ -130,4 +150,6 @@ void mt76x2_init_debugfs(struct mt76x2_dev *dev) debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat); debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, read_txpower); + + debugfs_create_devm_seqfile(dev->mt76.dev, "agc", dir, read_agc); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c index f936dc9a5476..374cc655c11d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c @@ -159,6 +159,81 @@ static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, mt76_wr(dev, MT_BBP(DFS, 36), data); } +static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev, + struct mt76x2_dfs_sequence *seq) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + list_add(&seq->head, &dfs_pd->seq_pool); + + dfs_pd->seq_stats.seq_pool_len++; + dfs_pd->seq_stats.seq_len--; +} + +static +struct mt76x2_dfs_sequence *mt76x2_dfs_seq_pool_get(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq; + + if (list_empty(&dfs_pd->seq_pool)) { + seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); + } else { + seq = list_first_entry(&dfs_pd->seq_pool, + struct mt76x2_dfs_sequence, + head); + list_del(&seq->head); + dfs_pd->seq_stats.seq_pool_len--; + } + if (seq) + dfs_pd->seq_stats.seq_len++; + + return seq; +} + +static int mt76x2_dfs_get_multiple(int val, int frac, int margin) +{ + int remainder, factor; + + if (!frac) + return 0; + + if (abs(val - frac) <= margin) + return 1; + + factor = val / frac; + remainder = val % frac; + + if (remainder > margin) { + if ((frac - remainder) <= margin) + factor++; + else + factor = 0; + } + return factor; +} + +static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq, *tmp_seq; + int i; + + /* reset hw detector */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + + /* reset sw detector */ + for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { + dfs_pd->event_rb[i].h_rb = 0; + dfs_pd->event_rb[i].t_rb = 0; + } + + list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { + list_del_init(&seq->head); + mt76x2_dfs_seq_pool_put(dev, seq); + } +} + static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) { bool ret = false; @@ -295,6 +370,256 @@ static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, return ret; } +static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + u32 data; + + /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2) + * 2nd: DFS_R37[21:0]: pulse time + * 3rd: DFS_R37[11:0]: pulse width + * 3rd: DFS_R37[25:16]: phase + * 4th: DFS_R37[12:0]: current pwr + * 4th: DFS_R37[21:16]: pwr stable counter + * + * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected + */ + data = mt76_rr(dev, MT_BBP(DFS, 37)); + if (!MT_DFS_CHECK_EVENT(data)) + return false; + + event->engine = MT_DFS_EVENT_ENGINE(data); + data = mt76_rr(dev, MT_BBP(DFS, 37)); + event->ts = MT_DFS_EVENT_TIMESTAMP(data); + data = mt76_rr(dev, MT_BBP(DFS, 37)); + event->width = MT_DFS_EVENT_WIDTH(data); + + return true; +} + +static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + if (event->engine == 2) { + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; + u16 last_event_idx; + u32 delta_ts; + + last_event_idx = mt76_decr(event_buff->t_rb, + MT_DFS_EVENT_BUFLEN); + delta_ts = event->ts - event_buff->data[last_event_idx].ts; + if (delta_ts < MT_DFS_EVENT_TIME_MARGIN && + event_buff->data[last_event_idx].width >= 200) + return false; + } + return true; +} + +static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff; + + /* add radar event to ring buffer */ + event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] + : &dfs_pd->event_rb[0]; + event_buff->data[event_buff->t_rb] = *event; + event_buff->data[event_buff->t_rb].fetch_ts = jiffies; + + event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); + if (event_buff->t_rb == event_buff->h_rb) + event_buff->h_rb = mt76_incr(event_buff->h_rb, + MT_DFS_EVENT_BUFLEN); +} + +static int mt76x2_dfs_create_sequence(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event, + u16 cur_len) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sw_detector_params *sw_params; + u32 width_delta, with_sum, factor, cur_pri; + struct mt76x2_dfs_sequence seq, *seq_p; + struct mt76x2_dfs_event_rb *event_rb; + struct mt76x2_dfs_event *cur_event; + int i, j, end, pri; + + event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] + : &dfs_pd->event_rb[0]; + + i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN); + end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN); + + while (i != end) { + cur_event = &event_rb->data[i]; + with_sum = event->width + cur_event->width; + + sw_params = &dfs_pd->sw_dpd_params; + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + case NL80211_DFS_JP: + if (with_sum < 600) + width_delta = 8; + else + width_delta = with_sum >> 3; + break; + case NL80211_DFS_ETSI: + if (event->engine == 2) + width_delta = with_sum >> 6; + else if (with_sum < 620) + width_delta = 24; + else + width_delta = 8; + break; + case NL80211_DFS_UNSET: + default: + return -EINVAL; + } + + pri = event->ts - cur_event->ts; + if (abs(event->width - cur_event->width) > width_delta || + pri < sw_params->min_pri) + goto next; + + if (pri > sw_params->max_pri) + break; + + seq.pri = event->ts - cur_event->ts; + seq.first_ts = cur_event->ts; + seq.last_ts = event->ts; + seq.engine = event->engine; + seq.count = 2; + + j = mt76_decr(i, MT_DFS_EVENT_BUFLEN); + while (j != end) { + cur_event = &event_rb->data[j]; + cur_pri = event->ts - cur_event->ts; + factor = mt76x2_dfs_get_multiple(cur_pri, seq.pri, + sw_params->pri_margin); + if (factor > 0) { + seq.first_ts = cur_event->ts; + seq.count++; + } + + j = mt76_decr(j, MT_DFS_EVENT_BUFLEN); + } + if (seq.count <= cur_len) + goto next; + + seq_p = mt76x2_dfs_seq_pool_get(dev); + if (!seq_p) + return -ENOMEM; + + *seq_p = seq; + INIT_LIST_HEAD(&seq_p->head); + list_add(&seq_p->head, &dfs_pd->sequences); +next: + i = mt76_decr(i, MT_DFS_EVENT_BUFLEN); + } + return 0; +} + +static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev, + struct mt76x2_dfs_event *event) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sw_detector_params *sw_params; + struct mt76x2_dfs_sequence *seq, *tmp_seq; + u16 max_seq_len = 0; + u32 factor, pri; + + sw_params = &dfs_pd->sw_dpd_params; + list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { + if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) { + list_del_init(&seq->head); + mt76x2_dfs_seq_pool_put(dev, seq); + continue; + } + + if (event->engine != seq->engine) + continue; + + pri = event->ts - seq->last_ts; + factor = mt76x2_dfs_get_multiple(pri, seq->pri, + sw_params->pri_margin); + if (factor > 0) { + seq->last_ts = event->ts; + seq->count++; + max_seq_len = max_t(u16, max_seq_len, seq->count); + } + } + return max_seq_len; +} + +static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_sequence *seq; + + if (list_empty(&dfs_pd->sequences)) + return false; + + list_for_each_entry(seq, &dfs_pd->sequences, head) { + if (seq->count > MT_DFS_SEQUENCE_TH) { + dfs_pd->stats[seq->engine].sw_pattern++; + return true; + } + } + return false; +} + +static void mt76x2_dfs_add_events(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event event; + int i, seq_len; + + /* disable debug mode */ + mt76x2_dfs_set_capture_mode_ctrl(dev, false); + for (i = 0; i < MT_DFS_EVENT_LOOP; i++) { + if (!mt76x2_dfs_fetch_event(dev, &event)) + break; + + if (dfs_pd->last_event_ts > event.ts) + mt76x2_dfs_detector_reset(dev); + dfs_pd->last_event_ts = event.ts; + + if (!mt76x2_dfs_check_event(dev, &event)) + continue; + + seq_len = mt76x2_dfs_add_event_to_sequence(dev, &event); + mt76x2_dfs_create_sequence(dev, &event, seq_len); + + mt76x2_dfs_queue_event(dev, &event); + } + mt76x2_dfs_set_capture_mode_ctrl(dev, true); +} + +static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x2_dfs_event_rb *event_buff; + struct mt76x2_dfs_event *event; + int i; + + for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { + event_buff = &dfs_pd->event_rb[i]; + + while (event_buff->h_rb != event_buff->t_rb) { + event = &event_buff->data[event_buff->h_rb]; + + /* sorted list */ + if (time_is_after_jiffies(event->fetch_ts + + MT_DFS_EVENT_WINDOW)) + break; + event_buff->h_rb = mt76_incr(event_buff->h_rb, + MT_DFS_EVENT_BUFLEN); + } + } +} + static void mt76x2_dfs_tasklet(unsigned long arg) { struct mt76x2_dev *dev = (struct mt76x2_dev *)arg; @@ -305,6 +630,24 @@ static void mt76x2_dfs_tasklet(unsigned long arg) if (test_bit(MT76_SCANNING, &dev->mt76.state)) goto out; + if (time_is_before_jiffies(dfs_pd->last_sw_check + + MT_DFS_SW_TIMEOUT)) { + bool radar_detected; + + dfs_pd->last_sw_check = jiffies; + + mt76x2_dfs_add_events(dev); + radar_detected = mt76x2_dfs_check_detection(dev); + if (radar_detected) { + /* sw detector rx radar pattern */ + ieee80211_radar_detected(dev->mt76.hw); + mt76x2_dfs_detector_reset(dev); + + return; + } + mt76x2_dfs_check_event_window(dev); + } + engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); if (!(engine_mask & 0xf)) goto out; @@ -326,9 +669,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg) /* hw detector rx radar pattern */ dfs_pd->stats[i].hw_pattern++; ieee80211_radar_detected(dev->mt76.hw); - - /* reset hw detector */ - mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + mt76x2_dfs_detector_reset(dev); return; } @@ -340,6 +681,32 @@ out: mt76x2_irq_enable(dev, MT_INT_GPTIMER); } +static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; + break; + case NL80211_DFS_ETSI: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2; + break; + case NL80211_DFS_JP: + dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI; + dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI; + dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; + break; + case NL80211_DFS_UNSET: + default: + break; + } +} + static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) { u32 data; @@ -462,6 +829,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && dev->dfs_pd.region != NL80211_DFS_UNSET) { + mt76x2_dfs_init_sw_detector(dev); mt76x2_dfs_set_bbp_params(dev); /* enable debug mode */ mt76x2_dfs_set_capture_mode_ctrl(dev, true); @@ -486,7 +854,10 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) { struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + INIT_LIST_HEAD(&dfs_pd->sequences); + INIT_LIST_HEAD(&dfs_pd->seq_pool); dfs_pd->region = NL80211_DFS_UNSET; + dfs_pd->last_sw_check = jiffies; tasklet_init(&dfs_pd->dfs_tasklet, mt76x2_dfs_tasklet, (unsigned long)dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h index 8dbc783cc6bc..693f421bf096 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h @@ -33,6 +33,22 @@ #define MT_DFS_PKT_END_MASK 0 #define MT_DFS_CH_EN 0xf +/* sw detector params */ +#define MT_DFS_EVENT_LOOP 64 +#define MT_DFS_SW_TIMEOUT (HZ / 20) +#define MT_DFS_EVENT_WINDOW (HZ / 5) +#define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) +#define MT_DFS_EVENT_TIME_MARGIN 2000 +#define MT_DFS_PRI_MARGIN 4 +#define MT_DFS_SEQUENCE_TH 6 + +#define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) +#define MT_DFS_FCC_MIN_PRI (3000 - 2) +#define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) +#define MT_DFS_JP_MIN_PRI (28500 - 2) +#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) +#define MT_DFS_ETSI_MIN_PRI (4500 - 20) + struct mt76x2_radar_specs { u8 mode; u16 avg_len; @@ -50,6 +66,32 @@ struct mt76x2_radar_specs { u16 pwr_jmp; }; +#define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) +#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) +#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) +#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) +struct mt76x2_dfs_event { + unsigned long fetch_ts; + u32 ts; + u16 width; + u8 engine; +}; + +#define MT_DFS_EVENT_BUFLEN 256 +struct mt76x2_dfs_event_rb { + struct mt76x2_dfs_event data[MT_DFS_EVENT_BUFLEN]; + int h_rb, t_rb; +}; + +struct mt76x2_dfs_sequence { + struct list_head head; + u32 first_ts; + u32 last_ts; + u32 pri; + u16 count; + u8 engine; +}; + struct mt76x2_dfs_hw_pulse { u8 engine; u32 period; @@ -58,9 +100,21 @@ struct mt76x2_dfs_hw_pulse { u32 burst; }; +struct mt76x2_dfs_sw_detector_params { + u32 min_pri; + u32 max_pri; + u32 pri_margin; +}; + struct mt76x2_dfs_engine_stats { u32 hw_pattern; u32 hw_pulse_discarded; + u32 sw_pattern; +}; + +struct mt76x2_dfs_seq_stats { + u32 seq_pool_len; + u32 seq_len; }; struct mt76x2_dfs_pattern_detector { @@ -69,6 +123,16 @@ struct mt76x2_dfs_pattern_detector { u8 chirp_pulse_cnt; u32 chirp_pulse_ts; + struct mt76x2_dfs_sw_detector_params sw_dpd_params; + struct mt76x2_dfs_event_rb event_rb[2]; + + struct list_head sequences; + struct list_head seq_pool; + struct mt76x2_dfs_seq_stats seq_stats; + + unsigned long last_sw_check; + u32 last_event_ts; + struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; struct tasklet_struct dfs_tasklet; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index b49aea4da2d6..fc9af79b3e69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -269,21 +269,31 @@ static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len) skb_pull(skb, len); } -static struct mt76_wcid * -mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, u8 idx, bool unicast) +static struct mt76x2_sta * +mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) { - struct mt76x2_sta *sta; struct mt76_wcid *wcid; if (idx >= ARRAY_SIZE(dev->wcid)) return NULL; wcid = rcu_dereference(dev->wcid[idx]); - if (unicast || !wcid) - return wcid; + if (!wcid) + return NULL; + + return container_of(wcid, struct mt76x2_sta, wcid); +} + +static struct mt76_wcid * +mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x2_sta *sta, bool unicast) +{ + if (!sta) + return NULL; - sta = container_of(wcid, struct mt76x2_sta, wcid); - return &sta->vif->group_wcid; + if (unicast) + return &sta->wcid; + else + return &sta->vif->group_wcid; } int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, @@ -291,6 +301,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct mt76x2_rxwi *rxwi = rxi; + struct mt76x2_sta *sta; u32 rxinfo = le32_to_cpu(rxwi->rxinfo); u32 ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); @@ -315,7 +326,8 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, } wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); - status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast); + sta = mt76x2_rx_get_sta(dev, wcid); + status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast); len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); @@ -361,6 +373,11 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); + if (sta) { + ewma_signal_add(&sta->rssi, status->signal); + sta->inactive_count = 0; + } + return mt76x2_mac_process_rate(status, rate); } @@ -439,15 +456,13 @@ mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev, if (last_rate < IEEE80211_TX_MAX_RATES - 1) rate[last_rate + 1].idx = -1; - cur_idx = rate[last_rate].idx + st->retry; + cur_idx = rate[last_rate].idx + last_rate; for (i = 0; i <= last_rate; i++) { rate[i].flags = rate[last_rate].flags; rate[i].idx = max_t(int, 0, cur_idx - i); rate[i].count = 1; } - - if (last_rate > 0) - rate[last_rate - 1].count = st->retry + 1 - last_rate; + rate[last_rate].count = st->retry + 1 - last_rate; info->status.ampdu_len = n_frames; info->status.ampdu_ack_len = st->success ? n_frames : 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index ce90ff999b49..3c0ebe6d231c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -238,10 +238,13 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_BSSID) mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); - if (changed & BSS_CHANGED_BEACON_INT) + if (changed & BSS_CHANGED_BEACON_INT) { mt76_rmw_field(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_INTVAL, info->beacon_int << 4); + dev->beacon_int = info->beacon_int; + dev->tbtt_count = 0; + } if (changed & BSS_CHANGED_BEACON_ENABLED) { tasklet_disable(&dev->pre_tbtt_tasklet); @@ -291,6 +294,8 @@ mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); + ewma_signal_init(&msta->rssi); + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); out: diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index c1c38ca3330a..20ffa6a40d39 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -485,12 +485,14 @@ static void mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) { u32 false_cca; - u8 limit = dev->cal.low_gain > 1 ? 4 : 16; + u8 limit = dev->cal.low_gain > 0 ? 16 : 4; false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); + dev->cal.false_cca = false_cca; if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) dev->cal.agc_gain_adjust += 2; - else if (false_cca < 10 && dev->cal.agc_gain_adjust > 0) + else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) || + (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) dev->cal.agc_gain_adjust -= 2; else return; @@ -498,60 +500,115 @@ mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) mt76x2_phy_set_gain_val(dev); } +static int +mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) +{ + struct mt76x2_sta *sta; + struct mt76_wcid *wcid; + int i, j, min_rssi = 0; + s8 cur_rssi; + + local_bh_disable(); + rcu_read_lock(); + + for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { + unsigned long mask = dev->wcid_mask[i]; + + if (!mask) + continue; + + for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { + if (!(mask & 1)) + continue; + + wcid = rcu_dereference(dev->wcid[j]); + if (!wcid) + continue; + + sta = container_of(wcid, struct mt76x2_sta, wcid); + spin_lock(&dev->mt76.rx_lock); + if (sta->inactive_count++ < 5) + cur_rssi = ewma_signal_read(&sta->rssi); + else + cur_rssi = 0; + spin_unlock(&dev->mt76.rx_lock); + + if (cur_rssi < min_rssi) + min_rssi = cur_rssi; + } + } + + rcu_read_unlock(); + local_bh_enable(); + + if (!min_rssi) + return -75; + + return min_rssi; +} + static void mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) { - u32 val = mt76_rr(dev, MT_BBP(AGC, 20)); - int rssi0 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI0, val); - int rssi1 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI1, val); u8 *gain = dev->cal.agc_gain_init; - u8 gain_delta; + u8 low_gain_delta, gain_delta; + bool gain_change; int low_gain; + u32 val; - dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + - (rssi0 << 8) / 16; - dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + - (rssi1 << 8) / 16; - dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] + - dev->cal.avg_rssi[1]) / 512; + dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); - if (dev->cal.low_gain == low_gain) { + gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2); + dev->cal.low_gain = low_gain; + + if (!gain_change) { mt76x2_phy_adjust_vga_gain(dev); return; } - dev->cal.low_gain = low_gain; - - if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) + if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) { mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); - else + val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf; + if (low_gain == 2) + val |= 0x3; + else + val |= 0x5; + mt76_wr(dev, MT_BBP(AGC, 26), val); + } else { mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); + } - if (low_gain) { - mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); + if (mt76x2_has_ext_lna(dev)) + low_gain_delta = 10; + else + low_gain_delta = 14; + + if (low_gain == 2) { + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); - if (mt76x2_has_ext_lna(dev)) - gain_delta = 10; - else - gain_delta = 14; + gain_delta = low_gain_delta; + dev->cal.agc_gain_adjust = 0; } else { - mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014); else mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116); mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C); gain_delta = 0; + dev->cal.agc_gain_adjust = low_gain_delta; } dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; - dev->cal.agc_gain_adjust = 0; mt76x2_phy_set_gain_val(dev); + + /* clear false CCA counters */ + mt76_rr(dev, MT_RX_STAT_1); } int mt76x2_phy_set_channel(struct mt76x2_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index e46eafc4c436..560376dd1133 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -218,6 +218,37 @@ mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) data->tail[mvif->idx] = skb; } +static void +mt76x2_resync_beacon_timer(struct mt76x2_dev *dev) +{ + u32 timer_val = dev->beacon_int << 4; + + dev->tbtt_count++; + + /* + * Beacon timer drifts by 1us every tick, the timer is configured + * in 1/16 TU (64us) units. + */ + if (dev->tbtt_count < 62) + return; + + if (dev->tbtt_count >= 64) { + dev->tbtt_count = 0; + return; + } + + /* + * The updated beacon interval takes effect after two TBTT, because + * at this point the original interval has already been loaded into + * the next TBTT_TIMER value + */ + if (dev->tbtt_count == 62) + timer_val -= 1; + + mt76_rmw_field(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_INTVAL, timer_val); +} + void mt76x2_pre_tbtt_tasklet(unsigned long arg) { struct mt76x2_dev *dev = (struct mt76x2_dev *) arg; @@ -226,6 +257,8 @@ void mt76x2_pre_tbtt_tasklet(unsigned long arg) struct sk_buff *skb; int i, nframes; + mt76x2_resync_beacon_timer(dev); + data.dev = dev; __skb_queue_head_init(&data.q); diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index ae0ca8006849..656ddc659218 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -1013,6 +1013,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) if (hw_info->hw_capab & QLINK_HW_CAPAB_STA_INACT_TIMEOUT) wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; + if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR) + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + if (hw_info->hw_capab & QLINK_HW_CAPAB_REG_UPDATE) { wiphy->regulatory_flags |= REGULATORY_STRICT_REG | REGULATORY_CUSTOM_REG; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c5d94a95e21a..42a598f92539 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -640,83 +640,83 @@ qtnf_cmd_sta_info_parse(struct station_info *sinfo, return; if (qtnf_sta_stat_avail(inactive_time, QLINK_STA_INFO_INACTIVE_TIME)) { - sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME); sinfo->inactive_time = le32_to_cpu(stats->inactive_time); } if (qtnf_sta_stat_avail(connected_time, QLINK_STA_INFO_CONNECTED_TIME)) { - sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME); sinfo->connected_time = le32_to_cpu(stats->connected_time); } if (qtnf_sta_stat_avail(signal, QLINK_STA_INFO_SIGNAL)) { - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); sinfo->signal = stats->signal - QLINK_RSSI_OFFSET; } if (qtnf_sta_stat_avail(signal_avg, QLINK_STA_INFO_SIGNAL_AVG)) { - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); sinfo->signal_avg = stats->signal_avg - QLINK_RSSI_OFFSET; } if (qtnf_sta_stat_avail(rxrate, QLINK_STA_INFO_RX_BITRATE)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); qtnf_sta_info_parse_rate(&sinfo->rxrate, &stats->rxrate); } if (qtnf_sta_stat_avail(txrate, QLINK_STA_INFO_TX_BITRATE)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); qtnf_sta_info_parse_rate(&sinfo->txrate, &stats->txrate); } if (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS); qtnf_sta_info_parse_flags(&sinfo->sta_flags, &stats->sta_flags); } if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); } if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES); sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); } if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES64)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); } if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES64)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); } if (qtnf_sta_stat_avail(rx_packets, QLINK_STA_INFO_RX_PACKETS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); sinfo->rx_packets = le32_to_cpu(stats->rx_packets); } if (qtnf_sta_stat_avail(tx_packets, QLINK_STA_INFO_TX_PACKETS)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); sinfo->tx_packets = le32_to_cpu(stats->tx_packets); } if (qtnf_sta_stat_avail(rx_beacon, QLINK_STA_INFO_BEACON_RX)) { - sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX); sinfo->rx_beacon = le64_to_cpu(stats->rx_beacon); } if (qtnf_sta_stat_avail(rx_dropped_misc, QLINK_STA_INFO_RX_DROP_MISC)) { - sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); sinfo->rx_dropped_misc = le32_to_cpu(stats->rx_dropped_misc); } if (qtnf_sta_stat_avail(tx_failed, QLINK_STA_INFO_TX_FAILED)) { - sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->tx_failed = le32_to_cpu(stats->tx_failed); } @@ -2234,6 +2234,22 @@ static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb, qchan->chan.flags = cpu_to_le32(flags); } +static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, + const u8 *mac_addr, + const u8 *mac_addr_mask) +{ + struct qlink_random_mac_addr *randmac; + struct qlink_tlv_hdr *hdr = + skb_put(cmd_skb, sizeof(*hdr) + sizeof(*randmac)); + + hdr->type = cpu_to_le16(QTN_TLV_ID_RANDOM_MAC_ADDR); + hdr->len = cpu_to_le16(sizeof(*randmac)); + randmac = (struct qlink_random_mac_addr *)hdr->val; + + memcpy(randmac->mac_addr, mac_addr, ETH_ALEN); + memcpy(randmac->mac_addr_mask, mac_addr_mask, ETH_ALEN); +} + int qtnf_cmd_send_scan(struct qtnf_wmac *mac) { struct sk_buff *cmd_skb; @@ -2291,6 +2307,15 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) } } + if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + pr_debug("MAC%u: scan with random addr=%pM, mask=%pM\n", + mac->macid, + scan_req->mac_addr, scan_req->mac_addr_mask); + + qtnf_cmd_randmac_tlv_add(cmd_skb, scan_req->mac_addr, + scan_req->mac_addr_mask); + } + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); if (unlikely(ret)) diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index a6a450984f9a..c318340e1bd5 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -179,6 +179,30 @@ static void qtnf_netdev_tx_timeout(struct net_device *ndev) } } +static int qtnf_netdev_set_mac_address(struct net_device *ndev, void *addr) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct sockaddr *sa = addr; + int ret; + unsigned char old_addr[ETH_ALEN]; + + memcpy(old_addr, sa->sa_data, sizeof(old_addr)); + + ret = eth_mac_addr(ndev, sa); + if (ret) + return ret; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_change_intf_type(vif, vif->wdev.iftype, + sa->sa_data); + + if (ret) + memcpy(ndev->dev_addr, old_addr, ETH_ALEN); + + return ret; +} + /* Network device ops handlers */ const struct net_device_ops qtnf_netdev_ops = { .ndo_open = qtnf_netdev_open, @@ -186,6 +210,7 @@ const struct net_device_ops qtnf_netdev_ops = { .ndo_start_xmit = qtnf_netdev_hard_start_xmit, .ndo_tx_timeout = qtnf_netdev_tx_timeout, .ndo_get_stats64 = qtnf_netdev_get_stats64, + .ndo_set_mac_address = qtnf_netdev_set_mac_address, }; static int qtnf_mac_init_single_band(struct wiphy *wiphy, diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index f85deda703fb..4a32967d0479 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -69,11 +69,14 @@ struct qlink_msg_header { * associated STAs due to inactivity. Inactivity timeout period is taken * from QLINK_CMD_START_AP parameters. * @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality + * @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address + * Randomization in probe requests. */ enum qlink_hw_capab { QLINK_HW_CAPAB_REG_UPDATE = BIT(0), QLINK_HW_CAPAB_STA_INACT_TIMEOUT = BIT(1), QLINK_HW_CAPAB_DFS_OFFLOAD = BIT(2), + QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR = BIT(3), }; enum qlink_iface_type { @@ -1089,6 +1092,7 @@ enum qlink_tlv_id { QTN_TLV_ID_HW_ID = 0x0405, QTN_TLV_ID_CALIBRATION_VER = 0x0406, QTN_TLV_ID_UBOOT_VER = 0x0407, + QTN_TLV_ID_RANDOM_MAC_ADDR = 0x0408, }; struct qlink_tlv_hdr { @@ -1360,4 +1364,20 @@ struct qlink_sta_stats { u8 rsvd[1]; }; +/** + * struct qlink_random_mac_addr - data for QTN_TLV_ID_RANDOM_MAC_ADDR TLV + * + * Specifies MAC address mask/value for generation random MAC address + * during scan. + * + * @mac_addr: MAC address used with randomisation + * @mac_addr_mask: MAC address mask used with randomisation, bits that + * are 0 in the mask should be randomised, bits that are 1 should + * be taken from the @mac_addr + */ +struct qlink_random_mac_addr { + u8 mac_addr[ETH_ALEN]; + u8 mac_addr_mask[ETH_ALEN]; +} __packed; + #endif /* _QTN_QLINK_H_ */ diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9935bd09db1f..51e4e92d95a0 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2480,7 +2480,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); if (ret == 0) { sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } len = sizeof(rssi); @@ -2488,7 +2488,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, &rssi, &len); if (ret == 0) { sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } } @@ -2928,6 +2928,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, while (buflen >= sizeof(*auth_req)) { auth_req = (void *)buf; + if (buflen < le32_to_cpu(auth_req->length)) + return; type = "unknown"; flags = le32_to_cpu(auth_req->flags); pairwise_error = false; diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 86ccf84ea0c6..597e934c4630 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -20,6 +20,8 @@ * */ +#include <linux/pm_runtime.h> + #include "../wlcore/debugfs.h" #include "../wlcore/wlcore.h" #include "../wlcore/debug.h" @@ -276,15 +278,18 @@ static ssize_t radar_detection_write(struct file *file, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl18xx_cmd_radar_detection_debug(wl, channel); if (ret < 0) count = ret; - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -315,15 +320,18 @@ static ssize_t dynamic_fw_traces_write(struct file *file, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl18xx_acx_dynamic_fw_traces(wl); if (ret < 0) count = ret; - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -374,9 +382,11 @@ static ssize_t radar_debug_mode_write(struct file *file, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif_ap(wl, wlvif) { wlcore_cmd_generic_cfg(wl, wlvif, @@ -384,7 +394,8 @@ static ssize_t radar_debug_mode_write(struct file *file, wl->radar_debug_mode, 0); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index 3ca9167d6146..7c83915a7c5e 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -31,7 +31,6 @@ #include "wlcore.h" #include "debug.h" #include "wl12xx_80211.h" -#include "ps.h" #include "hw_ops.h" int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 761cf8573a80..903968735a74 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/etherdevice.h> #include <linux/ieee80211.h> @@ -191,6 +192,12 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); + goto free_vector; + } + do { if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", @@ -222,6 +229,9 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, } while (!event); out: + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); +free_vector: kfree(events_vector); return ret; } diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index a2cb408be8aa..aeb74e74698e 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -26,6 +26,7 @@ #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include "wlcore.h" #include "debug.h" @@ -65,9 +66,11 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl) if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if (!wl->plt && time_after(jiffies, wl->stats.fw_stats_update + @@ -76,7 +79,8 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl) wl->stats.fw_stats_update = jiffies; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -118,14 +122,18 @@ static void chip_op_handler(struct wl1271 *wl, unsigned long value, return; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); + return; + } chip_op = arg; chip_op(wl); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); } @@ -292,9 +300,11 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* In case we're already in PSM, trigger it again to set new timeout * immediately without waiting for re-association @@ -305,7 +315,8 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -359,9 +370,11 @@ static ssize_t forced_ps_write(struct file *file, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* In case we're already in PSM, trigger it again to switch mode * immediately without waiting for re-association @@ -374,7 +387,8 @@ static ssize_t forced_ps_write(struct file *file, wl1271_ps_set_mode(wl, wlvif, ps_mode); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -838,15 +852,18 @@ static ssize_t rx_streaming_interval_write(struct file *file, wl->conf.rx_streaming.interval = value; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif_sta(wl, wlvif) { wl1271_recalc_rx_streaming(wl, wlvif); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -893,15 +910,18 @@ static ssize_t rx_streaming_always_write(struct file *file, wl->conf.rx_streaming.always = value; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif_sta(wl, wlvif) { wl1271_recalc_rx_streaming(wl, wlvif); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -940,15 +960,18 @@ static ssize_t beacon_filtering_write(struct file *file, mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif(wl, wlvif) { ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -1019,16 +1042,19 @@ static ssize_t sleep_auth_write(struct file *file, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl1271_acx_sleep_auth(wl, value); if (ret < 0) goto out_sleep; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return count; @@ -1083,7 +1109,7 @@ static ssize_t dev_mem_read(struct file *file, * Don't fail if elp_wakeup returns an error, so the device's memory * could be read even if the FW crashed */ - wl1271_ps_elp_wakeup(wl); + pm_runtime_get_sync(wl->dev); /* store current partition and switch partition */ memcpy(&old_part, &wl->curr_part, sizeof(old_part)); @@ -1102,7 +1128,8 @@ read_err: goto part_err; part_err: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); skip_read: mutex_unlock(&wl->mutex); @@ -1164,7 +1191,7 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, * Don't fail if elp_wakeup returns an error, so the device's memory * could be read even if the FW crashed */ - wl1271_ps_elp_wakeup(wl); + pm_runtime_get_sync(wl->dev); /* store current partition and switch partition */ memcpy(&old_part, &wl->curr_part, sizeof(old_part)); @@ -1183,7 +1210,8 @@ write_err: goto part_err; part_err: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); skip_write: mutex_unlock(&wl->mutex); @@ -1247,8 +1275,9 @@ static ssize_t fw_logger_write(struct file *file, } mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); + ret = pm_runtime_get_sync(wl->dev); if (ret < 0) { + pm_runtime_put_noidle(wl->dev); count = ret; goto out; } @@ -1257,7 +1286,8 @@ static ssize_t fw_logger_write(struct file *file, ret = wl12xx_cmd_config_fwlog(wl); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 3a51ab116e79..37f785f601c1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -26,6 +26,7 @@ #include <linux/vmalloc.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/pm_runtime.h> #include "wlcore.h" #include "debug.h" @@ -43,6 +44,7 @@ #define WL1271_BOOT_RETRIES 3 #define WL1271_SUSPEND_SLEEP 100 +#define WL1271_WAKEUP_TIMEOUT 500 static char *fwlog_param; static int fwlog_mem_blocks = -1; @@ -153,9 +155,11 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work) if (!wl->conf.rx_streaming.interval) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl1271_set_rx_streaming(wl, wlvif, true); if (ret < 0) @@ -166,7 +170,8 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work) jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -183,16 +188,19 @@ static void wl1271_rx_streaming_disable_work(struct work_struct *work) if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl1271_set_rx_streaming(wl, wlvif, false); if (ret) goto out_sleep; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -229,9 +237,11 @@ static void wlcore_rc_update_work(struct work_struct *work) if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if (ieee80211_vif_is_mesh(vif)) { ret = wl1271_acx_set_ht_capabilities(wl, &wlvif->rc_ht_cap, @@ -243,7 +253,8 @@ static void wlcore_rc_update_work(struct work_struct *work) } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -539,15 +550,16 @@ static int wlcore_irq_locked(struct wl1271 *wl) if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } while (!done && loopcount--) { /* * In order to avoid a race with the hardirq, clear the flag - * before acknowledging the chip. Since the mutex is held, - * wl1271_ps_elp_wakeup cannot be called concurrently. + * before acknowledging the chip. */ clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_atomic(); @@ -641,7 +653,8 @@ static int wlcore_irq_locked(struct wl1271 *wl) wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: return ret; @@ -796,8 +809,6 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl) wl->state = WLCORE_STATE_RESTARTING; set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); - wl1271_ps_elp_wakeup(wl); - wlcore_disable_interrupts_nosync(wl); ieee80211_queue_work(wl->hw, &wl->recovery_work); } } @@ -819,6 +830,7 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) static void wl12xx_read_fwlog_panic(struct wl1271 *wl) { u32 end_of_log = 0; + int error; if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) return; @@ -830,8 +842,11 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) * Do not send a stop fwlog command if the fw is hanged or if * dbgpins are used (due to some fw bug). */ - if (wl1271_ps_elp_wakeup(wl)) + error = pm_runtime_get_sync(wl->dev); + if (error < 0) { + pm_runtime_put_noidle(wl->dev); return; + } if (!wl->watchdog_recovery && wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS) wl12xx_cmd_stop_fwlog(wl); @@ -919,12 +934,20 @@ static void wl1271_recovery_work(struct work_struct *work) container_of(work, struct wl1271, recovery_work); struct wl12xx_vif *wlvif; struct ieee80211_vif *vif; + int error; mutex_lock(&wl->mutex); if (wl->state == WLCORE_STATE_OFF || wl->plt) goto out_unlock; + error = pm_runtime_get_sync(wl->dev); + if (error < 0) { + wl1271_warning("Enable for recovery failed"); + pm_runtime_put_noidle(wl->dev); + } + wlcore_disable_interrupts_nosync(wl); + if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { if (wl->conf.fwlog.output == WL12XX_FWLOG_OUTPUT_HOST) wl12xx_read_fwlog_panic(wl); @@ -958,6 +981,8 @@ static void wl1271_recovery_work(struct work_struct *work) } wlcore_op_stop_locked(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); ieee80211_restart_hw(wl->hw); @@ -978,24 +1003,6 @@ static int wlcore_fw_wakeup(struct wl1271 *wl) return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); } -static int wlcore_fw_sleep(struct wl1271 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); - if (ret < 0) { - wl12xx_queue_recovery_work(wl); - goto out; - } - set_bit(WL1271_FLAG_IN_ELP, &wl->flags); -out: - mutex_unlock(&wl->mutex); - mdelay(WL1271_SUSPEND_SLEEP); - - return 0; -} - static int wl1271_setup(struct wl1271 *wl) { wl->raw_fw_status = kzalloc(wl->fw_status_len, GFP_KERNEL); @@ -1184,7 +1191,6 @@ int wl1271_plt_stop(struct wl1271 *wl) wl1271_flush_deferred_work(wl); cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->recovery_work); - cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); mutex_lock(&wl->mutex); @@ -1719,6 +1725,7 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif; + unsigned long flags; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); @@ -1734,8 +1741,9 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); + ret = pm_runtime_get_sync(wl->dev); if (ret < 0) { + pm_runtime_put_noidle(wl->dev); mutex_unlock(&wl->mutex); return ret; } @@ -1765,6 +1773,7 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw, goto out_sleep; out_sleep: + pm_runtime_put_noidle(wl->dev); mutex_unlock(&wl->mutex); if (ret < 0) { @@ -1775,21 +1784,7 @@ out_sleep: /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); - /* - * disable and re-enable interrupts in order to flush - * the threaded_irq - */ - wlcore_disable_interrupts(wl); - - /* - * set suspended flag to avoid triggering a new threaded_irq - * work. no need for spinlock as interrupts are disabled. - */ - set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); - - wlcore_enable_interrupts(wl); flush_work(&wl->tx_work); - flush_delayed_work(&wl->elp_work); /* * Cancel the watchdog even if above tx_flush failed. We will detect @@ -1798,15 +1793,14 @@ out_sleep: cancel_delayed_work(&wl->tx_watchdog_work); /* - * Use an immediate call for allowing the firmware to go into power - * save during suspend. - * Using a workque for this last write was only hapenning on resume - * leaving the firmware with power save disabled during suspend, - * while consuming full power during wowlan suspend. + * set suspended flag to avoid triggering a new threaded_irq + * work. */ - wlcore_fw_sleep(wl); + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); - return 0; + return pm_runtime_force_suspend(wl->dev); } static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw) @@ -1821,6 +1815,12 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw) wl->wow_enabled); WARN_ON(!wl->wow_enabled); + ret = pm_runtime_force_resume(wl->dev); + if (ret < 0) { + wl1271_error("ELP wakeup failure!"); + goto out_sleep; + } + /* * re-enable irq_work enqueuing, and call irq_work directly if * there is a pending work. @@ -1857,9 +1857,11 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw) goto out_sleep; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif(wl, wlvif) { if (wlcore_is_p2p_mgmt(wlvif)) @@ -1878,7 +1880,8 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw) goto out_sleep; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: wl->wow_enabled = false; @@ -1945,7 +1948,6 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->tx_work); - cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); /* let's notify MAC80211 about the remaining pending TX frames */ @@ -2060,13 +2062,16 @@ static void wlcore_channel_switch_work(struct work_struct *work) vif = wl12xx_wlvif_to_vif(wlvif); ieee80211_chswitch_done(vif, false); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_cmd_stop_channel_switch(wl, wlvif); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -2128,14 +2133,17 @@ static void wlcore_pending_auth_complete_work(struct work_struct *work) if (!time_after(time_spare, wlvif->pending_auth_reply_time)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* cancel the ROC if active */ wlcore_update_inconn_sta(wl, wlvif, NULL, false); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -2537,9 +2545,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl12xx_get_vif_count(hw, vif, &vif_count); mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; /* * in some very corner case HW recovery scenarios its possible to @@ -2568,14 +2573,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto out; - if (wl12xx_need_fw_change(wl, vif_count, true)) { - wl12xx_force_active_psm(wl); - set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); - mutex_unlock(&wl->mutex); - wl1271_recovery_work(&wl->recovery_work); - return 0; - } - /* * TODO: after the nvs issue will be solved, move this block * to start(), and make sure here the driver is ON. @@ -2592,6 +2589,24 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + /* + * Call runtime PM only after possible wl12xx_init_fw() above + * is done. Otherwise we do not have interrupts enabled. + */ + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); + goto out_unlock; + } + + if (wl12xx_need_fw_change(wl, vif_count, true)) { + wl12xx_force_active_psm(wl); + set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); + mutex_unlock(&wl->mutex); + wl1271_recovery_work(&wl->recovery_work); + return 0; + } + if (!wlcore_is_p2p_mgmt(wlvif)) { ret = wl12xx_cmd_role_enable(wl, vif->addr, role_type, &wlvif->role_id); @@ -2622,7 +2637,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, else wl->sta_count++; out: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out_unlock: mutex_unlock(&wl->mutex); @@ -2677,9 +2693,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { /* disable active roles */ - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto deinit; + } if (wlvif->bss_type == BSS_TYPE_STA_BSS || wlvif->bss_type == BSS_TYPE_IBSS) { @@ -2697,7 +2715,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, goto deinit; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); } deinit: wl12xx_tx_reset_wlvif(wl, wlvif); @@ -3121,9 +3140,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* configure each interface */ wl12xx_for_each_wlvif(wl, wlvif) { @@ -3133,7 +3154,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3202,9 +3224,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif(wl, wlvif) { if (wlcore_is_p2p_mgmt(wlvif)) @@ -3247,7 +3271,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, */ out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3454,13 +3479,16 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, goto out_wake_queues; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out_wake_queues; + } ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out_wake_queues: if (might_change_spare) @@ -3600,9 +3628,11 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw, goto out_unlock; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out_unlock; + } wlvif->default_key = key_idx; @@ -3616,7 +3646,8 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw, } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out_unlock: mutex_unlock(&wl->mutex); @@ -3634,7 +3665,7 @@ void wlcore_regdomain_config(struct wl1271 *wl) if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); + ret = pm_runtime_get_sync(wl->dev); if (ret < 0) goto out; @@ -3644,7 +3675,8 @@ void wlcore_regdomain_config(struct wl1271 *wl) goto out; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -3678,9 +3710,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* fail if there is any role in ROC */ if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { @@ -3691,7 +3725,8 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, ret = wlcore_scan(hw->priv, vif, ssid, len, req); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3718,9 +3753,11 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if (wl->scan.state != WL1271_SCAN_STATE_DONE) { ret = wl->ops->scan_stop(wl, wlvif); @@ -3741,7 +3778,8 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, ieee80211_scan_completed(wl->hw, &info); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3766,9 +3804,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl->ops->sched_scan_start(wl, wlvif, req, ies); if (ret < 0) @@ -3777,7 +3817,8 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, wl->sched_vif = wlvif; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return ret; @@ -3797,13 +3838,16 @@ static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl->ops->sched_scan_stop(wl, wlvif); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3822,15 +3866,18 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl1271_acx_frag_threshold(wl, value); if (ret < 0) wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -3851,16 +3898,19 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif(wl, wlvif) { ret = wl1271_acx_rts_threshold(wl, wlvif, value); if (ret < 0) wl1271_warning("set rts threshold failed: %d", ret); } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -4607,9 +4657,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if ((changed & BSS_CHANGED_TXPOWER) && bss_conf->txpower != wlvif->power_level) { @@ -4626,7 +4678,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, else wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -4665,9 +4718,11 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl12xx_for_each_wlvif(wl, wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); @@ -4690,7 +4745,8 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, } } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -4719,9 +4775,11 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wlvif->band = ctx->def.chan->band; wlvif->channel = channel; @@ -4737,7 +4795,8 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, wlvif->radar_enabled = true; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -4768,9 +4827,11 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if (wlvif->radar_enabled) { wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); @@ -4778,7 +4839,8 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, wlvif->radar_enabled = false; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -4835,9 +4897,11 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } for (i = 0; i < n_vifs; i++) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif); @@ -4847,7 +4911,8 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw, goto out_sleep; } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -4878,9 +4943,11 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* * the txop is confed in units of 32us by the mac80211, @@ -4899,7 +4966,8 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, 0, 0); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -4923,16 +4991,19 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime); if (ret < 0) goto out_sleep; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -5238,13 +5309,16 @@ static int wl12xx_op_sta_state(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); if (new_state < old_state) @@ -5293,9 +5367,11 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, ba_bitmap = &wl->links[hlid].ba_bitmap; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", tid, action); @@ -5368,7 +5444,8 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, ret = -EINVAL; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -5402,16 +5479,19 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, if (wlvif->bss_type == BSS_TYPE_STA_BSS && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl1271_set_band_rate(wl, wlvif); wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl, wlvif); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); } out: mutex_unlock(&wl->mutex); @@ -5441,9 +5521,11 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } /* TODO: change mac80211 to pass vif as param */ @@ -5465,7 +5547,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -5532,9 +5615,11 @@ static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl->ops->channel_switch(wl, wlvif, &ch_switch); if (ret) @@ -5543,7 +5628,8 @@ static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw, set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } @@ -5584,9 +5670,11 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl12xx_start_dev(wl, wlvif, chan->band, channel); if (ret < 0) @@ -5596,7 +5684,8 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, ieee80211_queue_delayed_work(hw, &wl->roc_complete_work, msecs_to_jiffies(duration)); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); return ret; @@ -5638,13 +5727,16 @@ static int wlcore_roc_completed(struct wl1271 *wl) goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = __wlcore_roc_completed(wl); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -5719,19 +5811,22 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out_sleep; + } ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm); if (ret < 0) goto out_sleep; - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi_dbm; out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -6300,7 +6395,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, skb_queue_head_init(&wl->deferred_rx_queue); skb_queue_head_init(&wl->deferred_tx_queue); - INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); INIT_WORK(&wl->netstack_work, wl1271_netstack_work); INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work); @@ -6575,6 +6669,99 @@ out: complete_all(&wl->nvs_loading_complete); } +static int __maybe_unused wlcore_runtime_suspend(struct device *dev) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + struct wl12xx_vif *wlvif; + int error; + + /* We do not enter elp sleep in PLT mode */ + if (wl->plt) + return 0; + + /* Nothing to do if no ELP mode requested */ + if (wl->sleep_auth != WL1271_PSM_ELP) + return 0; + + wl12xx_for_each_wlvif(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) + return -EBUSY; + } + + wl1271_debug(DEBUG_PSM, "chip to elp"); + error = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); + if (error < 0) { + wl12xx_queue_recovery_work(wl); + + return error; + } + + set_bit(WL1271_FLAG_IN_ELP, &wl->flags); + + return 0; +} + +static int __maybe_unused wlcore_runtime_resume(struct device *dev) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + DECLARE_COMPLETION_ONSTACK(compl); + unsigned long flags; + int ret; + unsigned long start_time = jiffies; + bool pending = false; + + /* Nothing to do if no ELP mode requested */ + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) + return 0; + + wl1271_debug(DEBUG_PSM, "waking up chip from elp"); + + spin_lock_irqsave(&wl->wl_lock, flags); + if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) + pending = true; + else + wl->elp_compl = &compl; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); + if (ret < 0) { + wl12xx_queue_recovery_work(wl); + goto err; + } + + if (!pending) { + ret = wait_for_completion_timeout(&compl, + msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); + if (ret == 0) { + wl1271_error("ELP wakeup timeout!"); + wl12xx_queue_recovery_work(wl); + + /* Return no error for runtime PM for recovery */ + return 0; + } + } + + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); + + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start_time)); + + return 0; + +err: + spin_lock_irqsave(&wl->wl_lock, flags); + wl->elp_compl = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + return ret; +} + +static const struct dev_pm_ops wlcore_pm_ops = { + SET_RUNTIME_PM_OPS(wlcore_runtime_suspend, + wlcore_runtime_resume, + NULL) +}; + int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) { struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); @@ -6602,6 +6789,11 @@ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) wlcore_nvs_cb(NULL, wl); } + wl->dev->driver->pm = &wlcore_pm_ops; + pm_runtime_set_autosuspend_delay(wl->dev, 50); + pm_runtime_use_autosuspend(wl->dev); + pm_runtime_enable(wl->dev); + return ret; } EXPORT_SYMBOL_GPL(wlcore_probe); @@ -6610,6 +6802,13 @@ int wlcore_remove(struct platform_device *pdev) { struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); struct wl1271 *wl = platform_get_drvdata(pdev); + int error; + + error = pm_runtime_get_sync(wl->dev); + if (error < 0) + dev_warn(wl->dev, "PM runtime failed: %i\n", error); + + wl->dev->driver->pm = NULL; if (pdev_data->family && pdev_data->family->nvs_name) wait_for_completion(&wl->nvs_loading_complete); @@ -6621,6 +6820,11 @@ int wlcore_remove(struct platform_device *pdev) disable_irq_wake(wl->irq); } wl1271_unregister_hw(wl); + + pm_runtime_put_sync(wl->dev); + pm_runtime_dont_use_autosuspend(wl->dev); + pm_runtime_disable(wl->dev); + free_irq(wl->irq, wl); wlcore_free_hw(wl); diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index b36133b739cb..9de843d1984b 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -26,152 +26,6 @@ #include "tx.h" #include "debug.h" -#define WL1271_WAKEUP_TIMEOUT 500 - -#define ELP_ENTRY_DELAY 30 -#define ELP_ENTRY_DELAY_FORCE_PS 5 - -void wl1271_elp_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - struct wl12xx_vif *wlvif; - int ret; - - dwork = to_delayed_work(work); - wl = container_of(dwork, struct wl1271, elp_work); - - wl1271_debug(DEBUG_PSM, "elp work"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state != WLCORE_STATE_ON)) - goto out; - - /* our work might have been already cancelled */ - if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) - goto out; - - if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) - goto out; - - wl12xx_for_each_wlvif(wl, wlvif) { - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && - test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) - goto out; - } - - wl1271_debug(DEBUG_PSM, "chip to elp"); - ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); - if (ret < 0) { - wl12xx_queue_recovery_work(wl); - goto out; - } - - set_bit(WL1271_FLAG_IN_ELP, &wl->flags); - -out: - mutex_unlock(&wl->mutex); -} - -/* Routines to toggle sleep mode while in ELP */ -void wl1271_ps_elp_sleep(struct wl1271 *wl) -{ - struct wl12xx_vif *wlvif; - u32 timeout; - - /* We do not enter elp sleep in PLT mode */ - if (wl->plt) - return; - - if (wl->sleep_auth != WL1271_PSM_ELP) - return; - - /* we shouldn't get consecutive sleep requests */ - if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) - return; - - wl12xx_for_each_wlvif(wl, wlvif) { - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && - test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) - return; - } - - timeout = wl->conf.conn.forced_ps ? - ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY; - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(timeout)); -} -EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep); - -int wl1271_ps_elp_wakeup(struct wl1271 *wl) -{ - DECLARE_COMPLETION_ONSTACK(compl); - unsigned long flags; - int ret; - unsigned long start_time = jiffies; - bool pending = false; - - /* - * we might try to wake up even if we didn't go to sleep - * before (e.g. on boot) - */ - if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) - return 0; - - /* don't cancel_sync as it might contend for a mutex and deadlock */ - cancel_delayed_work(&wl->elp_work); - - if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) - return 0; - - wl1271_debug(DEBUG_PSM, "waking up chip from elp"); - - /* - * The spinlock is required here to synchronize both the work and - * the completion variable in one entity. - */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) - pending = true; - else - wl->elp_compl = &compl; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); - if (ret < 0) { - wl12xx_queue_recovery_work(wl); - goto err; - } - - if (!pending) { - ret = wait_for_completion_timeout( - &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); - if (ret == 0) { - wl1271_error("ELP wakeup timeout!"); - wl12xx_queue_recovery_work(wl); - ret = -ETIMEDOUT; - goto err; - } - } - - clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); - - wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start_time)); - goto out; - -err: - spin_lock_irqsave(&wl->wl_lock, flags); - wl->elp_compl = NULL; - spin_unlock_irqrestore(&wl->wl_lock, flags); - return ret; - -out: - return 0; -} -EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup); - int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode) { diff --git a/drivers/net/wireless/ti/wlcore/ps.h b/drivers/net/wireless/ti/wlcore/ps.h index de4f9da8ed26..411727587f95 100644 --- a/drivers/net/wireless/ti/wlcore/ps.h +++ b/drivers/net/wireless/ti/wlcore/ps.h @@ -29,9 +29,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode); -void wl1271_ps_elp_sleep(struct wl1271 *wl); -int wl1271_ps_elp_wakeup(struct wl1271 *wl); -void wl1271_elp_work(struct work_struct *work); void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid, bool clean_queues); void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index 5612f5916b4e..764e723e4ef9 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -22,13 +22,13 @@ */ #include <linux/ieee80211.h> +#include <linux/pm_runtime.h> #include "wlcore.h" #include "debug.h" #include "cmd.h" #include "scan.h" #include "acx.h" -#include "ps.h" #include "tx.h" void wl1271_scan_complete_work(struct work_struct *work) @@ -67,17 +67,17 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.req = NULL; wl->scan_wlvif = NULL; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } - wl1271_ps_elp_sleep(wl); - if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); @@ -85,6 +85,9 @@ void wl1271_scan_complete_work(struct work_struct *work) wlcore_cmd_regdomain_config_locked(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); + ieee80211_scan_completed(wl->hw, &info); out: diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index d31eb775e023..7425ba9471d0 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -19,9 +19,11 @@ * */ +#include <linux/pm_runtime.h> + +#include "acx.h" #include "wlcore.h" #include "debug.h" -#include "ps.h" #include "sysfs.h" static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, @@ -68,12 +70,15 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } wl1271_acx_sg_enable(wl, wl->sg_enabled); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index 009ec07c4cec..dcb2c8b0feb6 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -22,13 +22,13 @@ */ #include "testmode.h" +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <net/genetlink.h> #include "wlcore.h" #include "debug.h" #include "acx.h" -#include "ps.h" #include "io.h" #define WL1271_TM_MAX_DATA_LENGTH 1024 @@ -97,9 +97,11 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wl1271_cmd_test(wl, buf, buf_len, answer); if (ret < 0) { @@ -141,7 +143,8 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) } out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -169,9 +172,11 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -205,7 +210,8 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) out_free: kfree(cmd); out_sleep: - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 00e9b4624dcf..b6e19c2d66b0 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/etherdevice.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include "wlcore.h" @@ -868,9 +869,11 @@ void wl1271_tx_work(struct work_struct *work) int ret; mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wlcore_tx_work_locked(wl); if (ret < 0) { @@ -878,7 +881,8 @@ void wl1271_tx_work(struct work_struct *work) goto out; } - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index 5c0bcb1fe1a1..dbe78d8491ef 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -8,12 +8,13 @@ * version 2 as published by the Free Software Foundation. */ +#include <linux/pm_runtime.h> + #include <net/mac80211.h> #include <net/netlink.h> #include "wlcore.h" #include "debug.h" -#include "ps.h" #include "hw_ops.h" #include "vendor_cmd.h" @@ -55,14 +56,17 @@ wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wlcore_smart_config_start(wl, nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID])); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -87,13 +91,16 @@ wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wlcore_smart_config_stop(wl); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); @@ -131,16 +138,19 @@ wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy, goto out; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) + ret = pm_runtime_get_sync(wl->dev); + if (ret < 0) { + pm_runtime_put_noidle(wl->dev); goto out; + } ret = wlcore_smart_config_set_group_key(wl, nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]), nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]), nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY])); - wl1271_ps_elp_sleep(wl); + pm_runtime_mark_last_busy(wl->dev); + pm_runtime_put_autosuspend(wl->dev); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 95fbedc8ea34..d4b1f66ef457 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -348,7 +348,6 @@ struct wl1271 { enum nl80211_band band; struct completion *elp_compl; - struct delayed_work elp_work; /* in dBm */ int power_level; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index e840985385fc..32ec121ccac2 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -233,7 +233,6 @@ enum wl12xx_flags { WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, WL1271_FLAG_IN_ELP, - WL1271_FLAG_ELP_REQUESTED, WL1271_FLAG_IRQ_RUNNING, WL1271_FLAG_FW_TX_BUSY, WL1271_FLAG_DUMMY_PACKET_PENDING, diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_chip.c b/drivers/net/wireless/zydas/zd1211rw/zd_chip.c index 07b94eda9604..dd6a86b899eb 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_chip.c @@ -1341,7 +1341,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) case ZD_LED_SCANNING: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~other_led; - if (get_seconds() % 3 == 0) { + if ((u32)ktime_get_seconds() % 3 == 0) { ioreqs[1].value &= ~chip->link_led; } else { ioreqs[1].value |= chip->link_led; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index c30bf118c67d..c2cda3acd4af 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -371,25 +371,27 @@ static inline void handle_regs_int_override(struct urb *urb) { struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; + unsigned long flags; - spin_lock(&intr->lock); + spin_lock_irqsave(&intr->lock, flags); if (atomic_read(&intr->read_regs_enabled)) { atomic_set(&intr->read_regs_enabled, 0); intr->read_regs_int_overridden = 1; complete(&intr->read_regs.completion); } - spin_unlock(&intr->lock); + spin_unlock_irqrestore(&intr->lock, flags); } static inline void handle_regs_int(struct urb *urb) { struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; + unsigned long flags; int len; u16 int_num; ZD_ASSERT(in_interrupt()); - spin_lock(&intr->lock); + spin_lock_irqsave(&intr->lock, flags); int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); if (int_num == CR_INTERRUPT) { @@ -425,7 +427,7 @@ static inline void handle_regs_int(struct urb *urb) } out: - spin_unlock(&intr->lock); + spin_unlock_irqrestore(&intr->lock, flags); /* CR_INTERRUPT might override read_reg too. */ if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) @@ -665,6 +667,7 @@ static void rx_urb_complete(struct urb *urb) struct zd_usb_rx *rx; const u8 *buffer; unsigned int length; + unsigned long flags; switch (urb->status) { case 0: @@ -693,14 +696,14 @@ static void rx_urb_complete(struct urb *urb) /* If there is an old first fragment, we don't care. */ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n"); ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment)); - spin_lock(&rx->lock); + spin_lock_irqsave(&rx->lock, flags); memcpy(rx->fragment, buffer, length); rx->fragment_length = length; - spin_unlock(&rx->lock); + spin_unlock_irqrestore(&rx->lock, flags); goto resubmit; } - spin_lock(&rx->lock); + spin_lock_irqsave(&rx->lock, flags); if (rx->fragment_length > 0) { /* We are on a second fragment, we believe */ ZD_ASSERT(length + rx->fragment_length <= @@ -710,9 +713,9 @@ static void rx_urb_complete(struct urb *urb) handle_rx_packet(usb, rx->fragment, rx->fragment_length + length); rx->fragment_length = 0; - spin_unlock(&rx->lock); + spin_unlock_irqrestore(&rx->lock, flags); } else { - spin_unlock(&rx->lock); + spin_unlock_irqrestore(&rx->lock, flags); handle_rx_packet(usb, buffer, length); } diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index cf2588d81148..65a6981eef7b 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -104,7 +104,7 @@ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ }) -extern void __compiletime_warning("value doesn't fit into mask") +extern void __compiletime_error("value doesn't fit into mask") __field_overflow(void); extern void __compiletime_error("bad bitfield mask") __bad_mask(void); @@ -121,8 +121,8 @@ static __always_inline u64 field_mask(u64 field) #define ____MAKE_OP(type,base,to,from) \ static __always_inline __##type type##_encode_bits(base v, base field) \ { \ - if (__builtin_constant_p(v) && (v & ~field_multiplier(field))) \ - __field_overflow(); \ + if (__builtin_constant_p(v) && (v & ~field_mask(field))) \ + __field_overflow(); \ return to((v & field_mask(field)) * field_multiplier(field)); \ } \ static __always_inline __##type type##_replace_bits(__##type old, \ @@ -143,6 +143,7 @@ static __always_inline base type##_get_bits(__##type v, base field) \ ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ ____MAKE_OP(u##size,u##size,,) +____MAKE_OP(u8,u8,,) __MAKE_OP(16) __MAKE_OP(32) __MAKE_OP(64) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8838d1158d19..d3d82eccdfa5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1802,6 +1802,13 @@ config TEST_BITMAP If unsure, say N. +config TEST_BITFIELD + tristate "Test bitfield functions at runtime" + help + Enable this option to test the bitfield functions at boot. + + If unsure, say N. + config TEST_UUID tristate "Test functions located in the uuid module at runtime" diff --git a/lib/Makefile b/lib/Makefile index 90dc5520b784..60d0d5f90946 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o obj-$(CONFIG_TEST_PRINTF) += test_printf.o obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o +obj-$(CONFIG_TEST_BITFIELD) += test_bitfield.o obj-$(CONFIG_TEST_UUID) += test_uuid.o obj-$(CONFIG_TEST_PARMAN) += test_parman.o obj-$(CONFIG_TEST_KMOD) += test_kmod.o diff --git a/lib/test_bitfield.c b/lib/test_bitfield.c new file mode 100644 index 000000000000..5b8f4108662d --- /dev/null +++ b/lib/test_bitfield.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test cases for bitfield helpers. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/bitfield.h> + +#define CHECK_ENC_GET_U(tp, v, field, res) do { \ + { \ + u##tp _res; \ + \ + _res = u##tp##_encode_bits(v, field); \ + if (_res != res) { \ + pr_warn("u" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != " #res "\n",\ + (u64)_res); \ + return -EINVAL; \ + } \ + if (u##tp##_get_bits(_res, field) != v) \ + return -EINVAL; \ + } \ + } while (0) + +#define CHECK_ENC_GET_LE(tp, v, field, res) do { \ + { \ + __le##tp _res; \ + \ + _res = le##tp##_encode_bits(v, field); \ + if (_res != cpu_to_le##tp(res)) { \ + pr_warn("le" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\ + (u64)le##tp##_to_cpu(_res), \ + (u64)(res)); \ + return -EINVAL; \ + } \ + if (le##tp##_get_bits(_res, field) != v) \ + return -EINVAL; \ + } \ + } while (0) + +#define CHECK_ENC_GET_BE(tp, v, field, res) do { \ + { \ + __be##tp _res; \ + \ + _res = be##tp##_encode_bits(v, field); \ + if (_res != cpu_to_be##tp(res)) { \ + pr_warn("be" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\ + (u64)be##tp##_to_cpu(_res), \ + (u64)(res)); \ + return -EINVAL; \ + } \ + if (be##tp##_get_bits(_res, field) != v) \ + return -EINVAL; \ + } \ + } while (0) + +#define CHECK_ENC_GET(tp, v, field, res) do { \ + CHECK_ENC_GET_U(tp, v, field, res); \ + CHECK_ENC_GET_LE(tp, v, field, res); \ + CHECK_ENC_GET_BE(tp, v, field, res); \ + } while (0) + +static int test_constants(void) +{ + /* + * NOTE + * This whole function compiles (or at least should, if everything + * is going according to plan) to nothing after optimisation. + */ + + CHECK_ENC_GET(16, 1, 0x000f, 0x0001); + CHECK_ENC_GET(16, 3, 0x00f0, 0x0030); + CHECK_ENC_GET(16, 5, 0x0f00, 0x0500); + CHECK_ENC_GET(16, 7, 0xf000, 0x7000); + CHECK_ENC_GET(16, 14, 0x000f, 0x000e); + CHECK_ENC_GET(16, 15, 0x00f0, 0x00f0); + + CHECK_ENC_GET_U(8, 1, 0x0f, 0x01); + CHECK_ENC_GET_U(8, 3, 0xf0, 0x30); + CHECK_ENC_GET_U(8, 14, 0x0f, 0x0e); + CHECK_ENC_GET_U(8, 15, 0xf0, 0xf0); + + CHECK_ENC_GET(32, 1, 0x00000f00, 0x00000100); + CHECK_ENC_GET(32, 3, 0x0000f000, 0x00003000); + CHECK_ENC_GET(32, 5, 0x000f0000, 0x00050000); + CHECK_ENC_GET(32, 7, 0x00f00000, 0x00700000); + CHECK_ENC_GET(32, 14, 0x0f000000, 0x0e000000); + CHECK_ENC_GET(32, 15, 0xf0000000, 0xf0000000); + + CHECK_ENC_GET(64, 1, 0x00000f0000000000ull, 0x0000010000000000ull); + CHECK_ENC_GET(64, 3, 0x0000f00000000000ull, 0x0000300000000000ull); + CHECK_ENC_GET(64, 5, 0x000f000000000000ull, 0x0005000000000000ull); + CHECK_ENC_GET(64, 7, 0x00f0000000000000ull, 0x0070000000000000ull); + CHECK_ENC_GET(64, 14, 0x0f00000000000000ull, 0x0e00000000000000ull); + CHECK_ENC_GET(64, 15, 0xf000000000000000ull, 0xf000000000000000ull); + + return 0; +} + +#define CHECK(tp, mask) do { \ + u64 v; \ + \ + for (v = 0; v < 1 << hweight32(mask); v++) \ + if (tp##_encode_bits(v, mask) != v << __ffs64(mask)) \ + return -EINVAL; \ + } while (0) + +static int test_variables(void) +{ + CHECK(u8, 0x0f); + CHECK(u8, 0xf0); + CHECK(u8, 0x38); + + CHECK(u16, 0x0038); + CHECK(u16, 0x0380); + CHECK(u16, 0x3800); + CHECK(u16, 0x8000); + + CHECK(u32, 0x80000000); + CHECK(u32, 0x7f000000); + CHECK(u32, 0x07e00000); + CHECK(u32, 0x00018000); + + CHECK(u64, 0x8000000000000000ull); + CHECK(u64, 0x7f00000000000000ull); + CHECK(u64, 0x0001800000000000ull); + CHECK(u64, 0x0000000080000000ull); + CHECK(u64, 0x000000007f000000ull); + CHECK(u64, 0x0000000018000000ull); + CHECK(u64, 0x0000001f8000000ull); + + return 0; +} + +static int __init test_bitfields(void) +{ + int ret = test_constants(); + + if (ret) { + pr_warn("constant tests failed!\n"); + return ret; + } + + ret = test_variables(); + if (ret) { + pr_warn("variable tests failed!\n"); + return ret; + } + +#ifdef TEST_BITFIELD_COMPILE + /* these should fail compilation */ + CHECK_ENC_GET(16, 16, 0x0f00, 0x1000); + u32_encode_bits(7, 0x06000000); + + /* this should at least give a warning */ + u16_encode_bits(0, 0x60000); +#endif + + pr_info("tests passed\n"); + + return 0; +} +module_init(test_bitfields) + +MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); +MODULE_LICENSE("GPL"); |