forked from Minki/linux
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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJbVgnkAAoJEG4XJFUm622b/DAH/0wmjFQrt1qe/goZ4igZOC5z TTqPUmv7HO4PbHV6mU5yOFGsRCaGDo1cTyEeoiaYNGH6bQLzzJZeQORkuPQB2q5S BCwlaET7F2iSmk8hx7eboONyVDm5v2+g6NMHBoikVFz1wZ13kCVa4sHkokUJKYB9 XNw3B2OiarPv9i37DlY3woMlY+6VMQh8J6GiB9cJSa4Xs+7l1aQCdQRP03SabI71 gLBEsW+bEVZrUdJGB5cZ8c6LmukmRQMDKMTQYUna5ZXeW1IX3ejYcQGHzzCZoKJS LPUmisz4014r5aBzXIu3ctVn4LnVhMS5ms0EH1A6IX3vx8G9QynqH5lm9VQ1OXI= =kWW/ -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
a527d3f728
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "hw.h"
|
||||
#include "ce.h"
|
||||
#include "pci.h"
|
||||
|
||||
struct ath10k_snoc_drv_priv {
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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))},
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -213,7 +213,7 @@ static const s16 log_table[] = {
|
||||
30498,
|
||||
31267,
|
||||
32024,
|
||||
32768
|
||||
32767
|
||||
};
|
||||
|
||||
#define LOG_TABLE_SIZE 32 /* log_table size */
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
sta = container_of(wcid, struct mt76x2_sta, wcid);
|
||||
return &sta->vif->group_wcid;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -348,7 +348,6 @@ struct wl1271 {
|
||||
enum nl80211_band band;
|
||||
|
||||
struct completion *elp_compl;
|
||||
struct delayed_work elp_work;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
168
lib/test_bitfield.c
Normal file
168
lib/test_bitfield.c
Normal file
@ -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");
|
Loading…
Reference in New Issue
Block a user