Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.16. Major changes: ath10k * enable multiqueue support for all hw using mac80211 wake_tx_queue op * new Kconfig option ATH10K_SPECTRAL to save RAM * show tx stats on QCA9880 * new qcom,ath10k-calibration-variant DT entry * WMI layer support for wcn3990 ath9k * new Kconfig option ATH9K_COMMON_SPECTRAL to save RAM wcn36xx * hardware scan offload support wil6210 * run-time PM support when interface is down
This commit is contained in:
commit
1dde35d0b8
|
@ -41,6 +41,9 @@ Optional properties:
|
|||
- qcom,msi_addr: MSI interrupt address.
|
||||
- qcom,msi_base: Base value to add before writing MSI data into
|
||||
MSI address register.
|
||||
- qcom,ath10k-calibration-variant: string to search for in the board-2.bin
|
||||
variant list with the same bus and device
|
||||
specific ids
|
||||
- qcom,ath10k-calibration-data : calibration data + board specific data
|
||||
as an array, the length can vary between
|
||||
hw versions.
|
||||
|
|
|
@ -47,12 +47,19 @@ config ATH10K_DEBUG
|
|||
config ATH10K_DEBUGFS
|
||||
bool "Atheros ath10k debugfs support"
|
||||
depends on ATH10K && DEBUG_FS
|
||||
select RELAY
|
||||
---help---
|
||||
Enabled debugfs support
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config ATH10K_SPECTRAL
|
||||
bool "Atheros ath10k spectral scan support"
|
||||
depends on ATH10K_DEBUGFS
|
||||
select RELAY
|
||||
default n
|
||||
---help---
|
||||
Say Y to enable access to the FFT/spectral data via debugfs.
|
||||
|
||||
config ATH10K_TRACING
|
||||
bool "Atheros ath10k tracing support"
|
||||
depends on ATH10K
|
||||
|
|
|
@ -15,7 +15,7 @@ ath10k_core-y += mac.o \
|
|||
p2p.o \
|
||||
swap.o
|
||||
|
||||
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
|
||||
ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o
|
||||
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
|
||||
ath10k_core-$(CONFIG_THERMAL) += thermal.o
|
||||
|
|
|
@ -75,6 +75,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA9887_HW_1_0_VERSION,
|
||||
|
@ -99,6 +102,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
|
@ -122,6 +128,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_2_1_VERSION,
|
||||
|
@ -145,6 +154,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_3_0_VERSION,
|
||||
|
@ -168,6 +180,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA6174_HW_3_2_VERSION,
|
||||
|
@ -194,6 +209,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA99X0_HW_2_0_DEV_VERSION,
|
||||
|
@ -223,6 +241,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 11,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA9984_HW_1_0_DEV_VERSION,
|
||||
|
@ -257,6 +278,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 1560,
|
||||
.vht160_mcs_tx_highest = 1560,
|
||||
.n_cipher_suites = 11,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA9888_HW_2_0_DEV_VERSION,
|
||||
|
@ -290,6 +314,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 780,
|
||||
.vht160_mcs_tx_highest = 780,
|
||||
.n_cipher_suites = 11,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA9377_HW_1_0_DEV_VERSION,
|
||||
|
@ -313,6 +340,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA9377_HW_1_1_DEV_VERSION,
|
||||
|
@ -338,6 +368,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 8,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = QCA4019_HW_1_0_DEV_VERSION,
|
||||
|
@ -368,6 +401,27 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
|||
.vht160_mcs_rx_highest = 0,
|
||||
.vht160_mcs_tx_highest = 0,
|
||||
.n_cipher_suites = 11,
|
||||
.num_peers = TARGET_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = 0x10,
|
||||
.num_wds_entries = 0x20,
|
||||
},
|
||||
{
|
||||
.id = WCN3990_HW_1_0_DEV_VERSION,
|
||||
.dev_id = 0,
|
||||
.name = "wcn3990 hw1.0",
|
||||
.continuous_frag_desc = true,
|
||||
.tx_chain_mask = 0x7,
|
||||
.rx_chain_mask = 0x7,
|
||||
.max_spatial_stream = 4,
|
||||
.fw = {
|
||||
.dir = WCN3990_HW_1_0_FW_DIR,
|
||||
},
|
||||
.sw_decrypt_mcast_mgmt = true,
|
||||
.hw_ops = &wcn3990_ops,
|
||||
.decap_align_bytes = 1,
|
||||
.num_peers = TARGET_HL_10_TLV_NUM_PEERS,
|
||||
.ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT,
|
||||
.num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -390,6 +444,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
|
|||
[ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war",
|
||||
[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",
|
||||
[ATH10K_FW_FEATURE_NO_PS] = "no-ps",
|
||||
[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
|
||||
};
|
||||
|
||||
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
|
||||
|
@ -860,6 +915,28 @@ static int ath10k_core_check_smbios(struct ath10k *ar)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_check_dt(struct ath10k *ar)
|
||||
{
|
||||
struct device_node *node;
|
||||
const char *variant = NULL;
|
||||
|
||||
node = ar->dev->of_node;
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
of_property_read_string(node, "qcom,ath10k-calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
return -ENODATA;
|
||||
|
||||
if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT,
|
||||
"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
|
||||
variant);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
{
|
||||
u32 result, address = ar->hw_params.patch_load_addr;
|
||||
|
@ -1231,19 +1308,19 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
|
|||
/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
|
||||
char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
|
||||
|
||||
if (ar->id.bmi_ids_valid) {
|
||||
scnprintf(name, name_len,
|
||||
"bus=%s,bmi-chip-id=%d,bmi-board-id=%d",
|
||||
ath10k_bus_str(ar->hif.bus),
|
||||
ar->id.bmi_chip_id,
|
||||
ar->id.bmi_board_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ar->id.bdf_ext[0] != '\0')
|
||||
scnprintf(variant, sizeof(variant), ",variant=%s",
|
||||
ar->id.bdf_ext);
|
||||
|
||||
if (ar->id.bmi_ids_valid) {
|
||||
scnprintf(name, name_len,
|
||||
"bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s",
|
||||
ath10k_bus_str(ar->hif.bus),
|
||||
ar->id.bmi_chip_id,
|
||||
ar->id.bmi_board_id, variant);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scnprintf(name, name_len,
|
||||
"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",
|
||||
ath10k_bus_str(ar->hif.bus),
|
||||
|
@ -2343,7 +2420,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
|||
|
||||
ret = ath10k_core_check_smbios(ar);
|
||||
if (ret)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not set.\n");
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");
|
||||
|
||||
ret = ath10k_core_check_dt(ar);
|
||||
if (ret)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");
|
||||
|
||||
ret = ath10k_core_fetch_board_file(ar);
|
||||
if (ret) {
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
|
||||
/* NAPI poll budget */
|
||||
#define ATH10K_NAPI_BUDGET 64
|
||||
#define ATH10K_NAPI_QUOTA_LIMIT 60
|
||||
|
||||
/* SMBIOS type containing Board Data File Name Extension */
|
||||
#define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8
|
||||
|
@ -364,11 +363,11 @@ struct ath10k_sta {
|
|||
struct rate_info txrate;
|
||||
|
||||
struct work_struct update_wk;
|
||||
u64 rx_duration;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
/* protected by conf_mutex */
|
||||
bool aggr_mode;
|
||||
u64 rx_duration;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -463,7 +462,7 @@ struct ath10k_fw_crash_data {
|
|||
bool crashed_since_read;
|
||||
|
||||
guid_t guid;
|
||||
struct timespec timestamp;
|
||||
struct timespec64 timestamp;
|
||||
__le32 registers[REG_DUMP_COUNT_QCA988X];
|
||||
struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX];
|
||||
};
|
||||
|
@ -488,7 +487,6 @@ struct ath10k_debug {
|
|||
/* protected by conf_mutex */
|
||||
u64 fw_dbglog_mask;
|
||||
u32 fw_dbglog_level;
|
||||
u32 pktlog_filter;
|
||||
u32 reg_addr;
|
||||
u32 nf_cal_period;
|
||||
void *cal_data;
|
||||
|
@ -615,6 +613,9 @@ enum ath10k_fw_features {
|
|||
/* Firmware does not support power save in station mode. */
|
||||
ATH10K_FW_FEATURE_NO_PS = 17,
|
||||
|
||||
/* Firmware allows management tx by reference instead of by value. */
|
||||
ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
|
@ -963,6 +964,7 @@ struct ath10k {
|
|||
} spectral;
|
||||
#endif
|
||||
|
||||
u32 pktlog_filter;
|
||||
struct {
|
||||
/* protected by conf_mutex */
|
||||
struct ath10k_fw_components utf_mode_fw;
|
||||
|
|
|
@ -720,7 +720,7 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
|
|||
|
||||
crash_data->crashed_since_read = true;
|
||||
guid_gen(&crash_data->guid);
|
||||
getnstimeofday(&crash_data->timestamp);
|
||||
ktime_get_real_ts64(&crash_data->timestamp);
|
||||
|
||||
return crash_data;
|
||||
}
|
||||
|
@ -1950,14 +1950,14 @@ int ath10k_debug_start(struct ath10k *ar)
|
|||
ret);
|
||||
}
|
||||
|
||||
if (ar->debug.pktlog_filter) {
|
||||
if (ar->pktlog_filter) {
|
||||
ret = ath10k_wmi_pdev_pktlog_enable(ar,
|
||||
ar->debug.pktlog_filter);
|
||||
ar->pktlog_filter);
|
||||
if (ret)
|
||||
/* not serious */
|
||||
ath10k_warn(ar,
|
||||
"failed to enable pktlog filter %x: %d\n",
|
||||
ar->debug.pktlog_filter, ret);
|
||||
ar->pktlog_filter, ret);
|
||||
} else {
|
||||
ret = ath10k_wmi_pdev_pktlog_disable(ar);
|
||||
if (ret)
|
||||
|
@ -2097,12 +2097,12 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
|
|||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ar->debug.pktlog_filter = filter;
|
||||
ar->pktlog_filter = filter;
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (filter == ar->debug.pktlog_filter) {
|
||||
if (filter == ar->pktlog_filter) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
@ -2111,7 +2111,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
|
|||
ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
|
||||
ar->debug.pktlog_filter, ret);
|
||||
ar->pktlog_filter, ret);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
@ -2122,7 +2122,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
|
|||
}
|
||||
}
|
||||
|
||||
ar->debug.pktlog_filter = filter;
|
||||
ar->pktlog_filter = filter;
|
||||
ret = count;
|
||||
|
||||
out:
|
||||
|
@ -2139,7 +2139,7 @@ static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
|
|||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
|
||||
ar->debug.pktlog_filter);
|
||||
ar->pktlog_filter);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
||||
|
|
|
@ -51,7 +51,8 @@ enum ath10k_pktlog_filter {
|
|||
ATH10K_PKTLOG_RCFIND = 0x000000004,
|
||||
ATH10K_PKTLOG_RCUPDATE = 0x000000008,
|
||||
ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
|
||||
ATH10K_PKTLOG_ANY = 0x00000001f,
|
||||
ATH10K_PKTLOG_PEER_STATS = 0x000000040,
|
||||
ATH10K_PKTLOG_ANY = 0x00000005f,
|
||||
};
|
||||
|
||||
enum ath10k_dbg_aggr_mode {
|
||||
|
@ -60,6 +61,21 @@ enum ath10k_dbg_aggr_mode {
|
|||
ATH10K_DBG_AGGR_MODE_MAX,
|
||||
};
|
||||
|
||||
/* Types of packet log events */
|
||||
enum ath_pktlog_type {
|
||||
ATH_PKTLOG_TYPE_TX_CTRL = 1,
|
||||
ATH_PKTLOG_TYPE_TX_STAT,
|
||||
};
|
||||
|
||||
struct ath10k_pktlog_hdr {
|
||||
__le16 flags;
|
||||
__le16 missed_cnt;
|
||||
__le16 log_type; /* Type of log information foll this header */
|
||||
__le16 size; /* Size of variable length log information in bytes */
|
||||
__le32 timestamp;
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
/* FIXME: How to calculate the buffer size sanely? */
|
||||
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
|
||||
|
||||
|
@ -190,9 +206,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
struct ieee80211_sta *sta, struct dentry *dir);
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats);
|
||||
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo);
|
||||
#else
|
||||
static inline
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
|
|
|
@ -65,33 +65,6 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
|||
ath10k_sta_update_stats_rx_duration(ar, stats);
|
||||
}
|
||||
|
||||
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
return;
|
||||
|
||||
sinfo->rx_duration = arsta->rx_duration;
|
||||
sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
|
||||
|
||||
if (!arsta->txrate.legacy && !arsta->txrate.nss)
|
||||
return;
|
||||
|
||||
if (arsta->txrate.legacy) {
|
||||
sinfo->txrate.legacy = arsta->txrate.legacy;
|
||||
} else {
|
||||
sinfo->txrate.mcs = arsta->txrate.mcs;
|
||||
sinfo->txrate.nss = arsta->txrate.nss;
|
||||
sinfo->txrate.bw = arsta->txrate.bw;
|
||||
}
|
||||
sinfo->txrate.flags = arsta->txrate.flags;
|
||||
sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
|
|
@ -1497,6 +1497,23 @@ struct htt_peer_tx_stats {
|
|||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
#define ATH10K_10_2_TX_STATS_OFFSET 136
|
||||
#define PEER_STATS_FOR_NO_OF_PPDUS 4
|
||||
|
||||
struct ath10k_10_2_peer_tx_stats {
|
||||
u8 ratecode[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
u8 success_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
__le16 success_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
u8 retry_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
__le16 retry_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
u8 failed_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
__le16 failed_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
u8 flags[PEER_STATS_FOR_NO_OF_PPDUS];
|
||||
__le32 tx_duration;
|
||||
u8 tx_ppdu_cnt;
|
||||
u8 peer_id;
|
||||
} __packed;
|
||||
|
||||
union htt_rx_pn_t {
|
||||
/* WEP: 24-bit PN */
|
||||
u32 pn24;
|
||||
|
@ -1695,7 +1712,7 @@ struct ath10k_htt {
|
|||
/* This is used to group tx/rx completions separately and process them
|
||||
* in batches to reduce cache stalls
|
||||
*/
|
||||
struct sk_buff_head rx_compl_q;
|
||||
struct sk_buff_head rx_msdus_q;
|
||||
struct sk_buff_head rx_in_ord_compl_q;
|
||||
struct sk_buff_head tx_fetch_ind_q;
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
|
|||
{
|
||||
del_timer_sync(&htt->rx_ring.refill_retry_timer);
|
||||
|
||||
skb_queue_purge(&htt->rx_compl_q);
|
||||
skb_queue_purge(&htt->rx_msdus_q);
|
||||
skb_queue_purge(&htt->rx_in_ord_compl_q);
|
||||
skb_queue_purge(&htt->tx_fetch_ind_q);
|
||||
|
||||
|
@ -515,7 +515,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
|
|||
htt->rx_ring.sw_rd_idx.msdu_payld = 0;
|
||||
hash_init(htt->rx_ring.skb_table);
|
||||
|
||||
skb_queue_head_init(&htt->rx_compl_q);
|
||||
skb_queue_head_init(&htt->rx_msdus_q);
|
||||
skb_queue_head_init(&htt->rx_in_ord_compl_q);
|
||||
skb_queue_head_init(&htt->tx_fetch_ind_q);
|
||||
atomic_set(&htt->num_mpdus_ready, 0);
|
||||
|
@ -974,16 +974,25 @@ static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
|
|||
return out;
|
||||
}
|
||||
|
||||
static void ath10k_process_rx(struct ath10k *ar,
|
||||
static void ath10k_htt_rx_h_queue_msdu(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
*status = *rx_status;
|
||||
|
||||
__skb_queue_tail(&ar->htt.rx_msdus_q, skb);
|
||||
}
|
||||
|
||||
static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
char tid[32];
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
*status = *rx_status;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_DATA,
|
||||
"rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
|
@ -1517,7 +1526,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|||
}
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
|
||||
static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
|
@ -1540,7 +1549,7 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
|
|||
status->flag |= RX_FLAG_ALLOW_SAME_PN;
|
||||
}
|
||||
|
||||
ath10k_process_rx(ar, status, msdu);
|
||||
ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1652,7 +1661,7 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
struct ath10k *ar = htt->ar;
|
||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct sk_buff_head amsdu;
|
||||
int ret, num_msdus;
|
||||
int ret;
|
||||
|
||||
__skb_queue_head_init(&amsdu);
|
||||
|
||||
|
@ -1674,7 +1683,6 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
num_msdus = skb_queue_len(&amsdu);
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
|
||||
/* only for ret = 1 indicates chained msdus */
|
||||
|
@ -1683,9 +1691,9 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
|
||||
|
||||
return num_msdus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
|
||||
|
@ -1893,7 +1901,7 @@ static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
|
|||
RX_FLAG_MMIC_STRIPPED;
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
||||
static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
||||
struct sk_buff_head *list)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
|
@ -1901,7 +1909,6 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
|||
struct htt_rx_offload_msdu *rx;
|
||||
struct sk_buff *msdu;
|
||||
size_t offset;
|
||||
int num_msdu = 0;
|
||||
|
||||
while ((msdu = __skb_dequeue(list))) {
|
||||
/* Offloaded frames don't have Rx descriptor. Instead they have
|
||||
|
@ -1940,10 +1947,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
|||
|
||||
ath10k_htt_rx_h_rx_offload_prot(status, msdu);
|
||||
ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
|
||||
ath10k_process_rx(ar, status, msdu);
|
||||
num_msdu++;
|
||||
ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
|
||||
}
|
||||
return num_msdu;
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
@ -1959,7 +1964,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
u8 tid;
|
||||
bool offload;
|
||||
bool frag;
|
||||
int ret, num_msdus = 0;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
|
@ -2001,7 +2006,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
* separately.
|
||||
*/
|
||||
if (offload)
|
||||
num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
|
||||
ath10k_htt_rx_h_rx_offload(ar, &list);
|
||||
|
||||
while (!skb_queue_empty(&list)) {
|
||||
__skb_queue_head_init(&amsdu);
|
||||
|
@ -2014,11 +2019,10 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
* better to report something than nothing though. This
|
||||
* should still give an idea about rx rate to the user.
|
||||
*/
|
||||
num_msdus += skb_queue_len(&amsdu);
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, status);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
|
||||
break;
|
||||
case -EAGAIN:
|
||||
/* fall through */
|
||||
|
@ -2030,7 +2034,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
return -EIO;
|
||||
}
|
||||
}
|
||||
return num_msdus;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
|
||||
|
@ -2449,6 +2453,62 @@ out:
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data)
|
||||
{
|
||||
struct ath10k_pktlog_hdr *hdr = (struct ath10k_pktlog_hdr *)data;
|
||||
struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats;
|
||||
struct ath10k_10_2_peer_tx_stats *tx_stats;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_peer *peer;
|
||||
u16 log_type = __le16_to_cpu(hdr->log_type);
|
||||
u32 peer_id = 0, i;
|
||||
|
||||
if (log_type != ATH_PKTLOG_TYPE_TX_STAT)
|
||||
return;
|
||||
|
||||
tx_stats = (struct ath10k_10_2_peer_tx_stats *)((hdr->payload) +
|
||||
ATH10K_10_2_TX_STATS_OFFSET);
|
||||
|
||||
if (!tx_stats->tx_ppdu_cnt)
|
||||
return;
|
||||
|
||||
peer_id = tx_stats->peer_id;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
|
||||
peer_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sta = peer->sta;
|
||||
for (i = 0; i < tx_stats->tx_ppdu_cnt; i++) {
|
||||
p_tx_stats->succ_bytes =
|
||||
__le16_to_cpu(tx_stats->success_bytes[i]);
|
||||
p_tx_stats->retry_bytes =
|
||||
__le16_to_cpu(tx_stats->retry_bytes[i]);
|
||||
p_tx_stats->failed_bytes =
|
||||
__le16_to_cpu(tx_stats->failed_bytes[i]);
|
||||
p_tx_stats->ratecode = tx_stats->ratecode[i];
|
||||
p_tx_stats->flags = tx_stats->flags[i];
|
||||
p_tx_stats->succ_pkts = tx_stats->success_pkts[i];
|
||||
p_tx_stats->retry_pkts = tx_stats->retry_pkts[i];
|
||||
p_tx_stats->failed_pkts = tx_stats->failed_pkts[i];
|
||||
|
||||
ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats);
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
|
@ -2566,6 +2626,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|||
skb->len -
|
||||
offsetof(struct htt_resp,
|
||||
pktlog_msg.payload));
|
||||
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
ath10k_fetch_10_2_tx_stats(ar,
|
||||
resp->pktlog_msg.payload);
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_RX_FLUSH: {
|
||||
|
@ -2631,6 +2695,24 @@ void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
|
|||
}
|
||||
EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
|
||||
|
||||
static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
while (quota < budget) {
|
||||
if (skb_queue_empty(&ar->htt.rx_msdus_q))
|
||||
break;
|
||||
|
||||
skb = __skb_dequeue(&ar->htt.rx_msdus_q);
|
||||
if (!skb)
|
||||
break;
|
||||
ath10k_process_rx(ar, skb);
|
||||
quota++;
|
||||
}
|
||||
|
||||
return quota;
|
||||
}
|
||||
|
||||
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
|
@ -2638,63 +2720,44 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
|
|||
struct sk_buff_head tx_ind_q;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
int quota = 0, done, num_rx_msdus;
|
||||
int quota = 0, done, ret;
|
||||
bool resched_napi = false;
|
||||
|
||||
__skb_queue_head_init(&tx_ind_q);
|
||||
|
||||
/* Since in-ord-ind can deliver more than 1 A-MSDU in single event,
|
||||
* process it first to utilize full available quota.
|
||||
/* Process pending frames before dequeuing more data
|
||||
* from hardware.
|
||||
*/
|
||||
while (quota < budget) {
|
||||
if (skb_queue_empty(&htt->rx_in_ord_compl_q))
|
||||
break;
|
||||
|
||||
skb = __skb_dequeue(&htt->rx_in_ord_compl_q);
|
||||
if (!skb) {
|
||||
quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
|
||||
if (quota == budget) {
|
||||
resched_napi = true;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
|
||||
spin_lock_bh(&htt->rx_ring.lock);
|
||||
num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
|
||||
ret = ath10k_htt_rx_in_ord_ind(ar, skb);
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
if (num_rx_msdus < 0) {
|
||||
resched_napi = true;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
if (num_rx_msdus > 0)
|
||||
quota += num_rx_msdus;
|
||||
|
||||
if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
|
||||
!skb_queue_empty(&htt->rx_in_ord_compl_q)) {
|
||||
if (ret == -EIO) {
|
||||
resched_napi = true;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
while (quota < budget) {
|
||||
/* no more data to receive */
|
||||
if (!atomic_read(&htt->num_mpdus_ready))
|
||||
break;
|
||||
|
||||
num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
|
||||
if (num_rx_msdus < 0) {
|
||||
while (atomic_read(&htt->num_mpdus_ready)) {
|
||||
ret = ath10k_htt_rx_handle_amsdu(htt);
|
||||
if (ret == -EIO) {
|
||||
resched_napi = true;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
quota += num_rx_msdus;
|
||||
atomic_dec(&htt->num_mpdus_ready);
|
||||
if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
|
||||
atomic_read(&htt->num_mpdus_ready)) {
|
||||
resched_napi = true;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deliver received data after processing data from hardware */
|
||||
quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
|
||||
|
||||
/* From NAPI documentation:
|
||||
* The napi poll() function may also process TX completions, in which
|
||||
* case if it processes the entire TX ring then it should count that
|
||||
|
|
|
@ -931,3 +931,5 @@ const struct ath10k_hw_ops qca6174_ops = {
|
|||
.set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
|
||||
.enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock,
|
||||
};
|
||||
|
||||
const struct ath10k_hw_ops wcn3990_ops = {};
|
||||
|
|
|
@ -128,6 +128,10 @@ enum qca9377_chip_id_rev {
|
|||
#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
/* WCN3990 1.0 definitions */
|
||||
#define WCN3990_HW_1_0_DEV_VERSION ATH10K_HW_WCN3990
|
||||
#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw3.0"
|
||||
|
||||
#define ATH10K_FW_FILE_BASE "firmware"
|
||||
#define ATH10K_FW_API_MAX 6
|
||||
#define ATH10K_FW_API_MIN 2
|
||||
|
@ -553,6 +557,10 @@ struct ath10k_hw_params {
|
|||
|
||||
/* Number of ciphers supported (i.e First N) in cipher_suites array */
|
||||
int n_cipher_suites;
|
||||
|
||||
u32 num_peers;
|
||||
u32 ast_skid_limit;
|
||||
u32 num_wds_entries;
|
||||
};
|
||||
|
||||
struct htt_rx_desc;
|
||||
|
@ -567,6 +575,7 @@ struct ath10k_hw_ops {
|
|||
extern const struct ath10k_hw_ops qca988x_ops;
|
||||
extern const struct ath10k_hw_ops qca99x0_ops;
|
||||
extern const struct ath10k_hw_ops qca6174_ops;
|
||||
extern const struct ath10k_hw_ops wcn3990_ops;
|
||||
|
||||
extern const struct ath10k_hw_clk_params qca6174_clk[];
|
||||
|
||||
|
@ -663,6 +672,11 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
|
|||
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
|
||||
#define TARGET_TLV_NUM_WOW_PATTERNS 22
|
||||
|
||||
/* Target specific defines for WMI-HL-1.0 firmware */
|
||||
#define TARGET_HL_10_TLV_NUM_PEERS 14
|
||||
#define TARGET_HL_10_TLV_AST_SKID_LIMIT 6
|
||||
#define TARGET_HL_10_TLV_NUM_WDS_ENTRIES 2
|
||||
|
||||
/* Diagnostic Window */
|
||||
#define CE_DIAG_PIPE 7
|
||||
|
||||
|
|
|
@ -2563,7 +2563,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
|
|||
}
|
||||
break;
|
||||
case WMI_VDEV_TYPE_STA:
|
||||
if (vif->bss_conf.qos)
|
||||
if (sta->wme)
|
||||
arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
|
||||
break;
|
||||
case WMI_VDEV_TYPE_IBSS:
|
||||
|
@ -3574,7 +3574,9 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
|
|||
return ATH10K_MAC_TX_HTT;
|
||||
case ATH10K_HW_TXRX_MGMT:
|
||||
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
ar->running_fw->fw_file.fw_features) ||
|
||||
test_bit(WMI_SERVICE_MGMT_TX_WMI,
|
||||
ar->wmi.svc_map))
|
||||
return ATH10K_MAC_TX_WMI_MGMT;
|
||||
else if (ar->htt.target_version_major >= 3)
|
||||
return ATH10K_MAC_TX_HTT;
|
||||
|
@ -6201,6 +6203,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
"mac vdev %d peer delete %pM sta %pK (sta gone)\n",
|
||||
arvif->vdev_id, sta->addr, sta);
|
||||
|
||||
if (sta->tdls) {
|
||||
ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id,
|
||||
sta,
|
||||
WMI_TDLS_PEER_STATE_TEARDOWN);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n",
|
||||
sta->addr,
|
||||
WMI_TDLS_PEER_STATE_TEARDOWN, ret);
|
||||
}
|
||||
|
||||
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
|
||||
|
@ -7536,6 +7548,16 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
arvif->vdev_id, ret);
|
||||
}
|
||||
|
||||
if (ath10k_peer_stats_enabled(ar)) {
|
||||
ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS;
|
||||
ret = ath10k_wmi_pdev_pktlog_enable(ar,
|
||||
ar->pktlog_filter);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to enable pktlog %d\n", ret);
|
||||
goto err_stop;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
|
||||
|
@ -7620,6 +7642,34 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
|
|||
peer->removed = true;
|
||||
}
|
||||
|
||||
static void ath10k_sta_statistics(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
return;
|
||||
|
||||
sinfo->rx_duration = arsta->rx_duration;
|
||||
sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
|
||||
|
||||
if (!arsta->txrate.legacy && !arsta->txrate.nss)
|
||||
return;
|
||||
|
||||
if (arsta->txrate.legacy) {
|
||||
sinfo->txrate.legacy = arsta->txrate.legacy;
|
||||
} else {
|
||||
sinfo->txrate.mcs = arsta->txrate.mcs;
|
||||
sinfo->txrate.nss = arsta->txrate.nss;
|
||||
sinfo->txrate.bw = arsta->txrate.bw;
|
||||
}
|
||||
sinfo->txrate.flags = arsta->txrate.flags;
|
||||
sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx = ath10k_mac_op_tx,
|
||||
.wake_tx_queue = ath10k_mac_op_wake_tx_queue,
|
||||
|
@ -7661,6 +7711,7 @@ static const struct ieee80211_ops ath10k_ops = {
|
|||
.unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
|
||||
.switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
|
||||
.sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove,
|
||||
.sta_statistics = ath10k_sta_statistics,
|
||||
|
||||
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
|
||||
|
||||
|
@ -7671,7 +7722,6 @@ static const struct ieee80211_ops ath10k_ops = {
|
|||
#endif
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
.sta_add_debugfs = ath10k_sta_add_debugfs,
|
||||
.sta_statistics = ath10k_sta_statistics,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -8329,15 +8379,6 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
|
||||
}
|
||||
|
||||
/* Current wake_tx_queue implementation imposes a significant
|
||||
* performance penalty in some setups. The tx scheduling code needs
|
||||
* more work anyway so disable the wake_tx_queue unless firmware
|
||||
* supports the pull-push mechanism.
|
||||
*/
|
||||
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
ar->ops->wake_tx_queue = NULL;
|
||||
|
||||
ret = ath10k_mac_init_rd(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to derive regdom: %d\n", ret);
|
||||
|
|
|
@ -44,7 +44,7 @@ enum ath10k_spectral_mode {
|
|||
SPECTRAL_MANUAL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
#ifdef CONFIG_ATH10K_SPECTRAL
|
||||
|
||||
int ath10k_spectral_process_fft(struct ath10k *ar,
|
||||
struct wmi_phyerr_ev_arg *phyerr,
|
||||
|
@ -85,6 +85,6 @@ static inline void ath10k_spectral_destroy(struct ath10k *ar)
|
|||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
#endif /* CONFIG_ATH10K_SPECTRAL */
|
||||
|
||||
#endif /* SPECTRAL_H */
|
||||
|
|
|
@ -377,6 +377,7 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
u32 mgmt_tx_cmdid;
|
||||
|
||||
if (!ar->wmi.ops->gen_mgmt_tx)
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -385,7 +386,13 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
|||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid);
|
||||
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
|
||||
else
|
||||
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
|
||||
|
||||
ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -917,33 +917,69 @@ ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
|
||||
struct sk_buff *skb,
|
||||
struct wmi_svc_rdy_ev_arg *arg)
|
||||
{
|
||||
const void **tb;
|
||||
struct wmi_tlv_svc_rdy_parse {
|
||||
const struct hal_reg_capabilities *reg;
|
||||
const struct wmi_tlv_svc_rdy_ev *ev;
|
||||
const __le32 *svc_bmap;
|
||||
const struct wlan_host_mem_req *mem_reqs;
|
||||
bool svc_bmap_done;
|
||||
bool dbs_hw_mode_done;
|
||||
};
|
||||
|
||||
static int ath10k_wmi_tlv_svc_rdy_parse(struct ath10k *ar, u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
struct wmi_tlv_svc_rdy_parse *svc_rdy = data;
|
||||
|
||||
switch (tag) {
|
||||
case WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT:
|
||||
svc_rdy->ev = ptr;
|
||||
break;
|
||||
case WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES:
|
||||
svc_rdy->reg = ptr;
|
||||
break;
|
||||
case WMI_TLV_TAG_ARRAY_STRUCT:
|
||||
svc_rdy->mem_reqs = ptr;
|
||||
break;
|
||||
case WMI_TLV_TAG_ARRAY_UINT32:
|
||||
if (!svc_rdy->svc_bmap_done) {
|
||||
svc_rdy->svc_bmap_done = true;
|
||||
svc_rdy->svc_bmap = ptr;
|
||||
} else if (!svc_rdy->dbs_hw_mode_done) {
|
||||
svc_rdy->dbs_hw_mode_done = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
|
||||
struct sk_buff *skb,
|
||||
struct wmi_svc_rdy_ev_arg *arg)
|
||||
{
|
||||
const struct hal_reg_capabilities *reg;
|
||||
const struct wmi_tlv_svc_rdy_ev *ev;
|
||||
const __le32 *svc_bmap;
|
||||
const struct wlan_host_mem_req *mem_reqs;
|
||||
struct wmi_tlv_svc_rdy_parse svc_rdy = { };
|
||||
int ret;
|
||||
|
||||
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
|
||||
if (IS_ERR(tb)) {
|
||||
ret = PTR_ERR(tb);
|
||||
ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
|
||||
ath10k_wmi_tlv_svc_rdy_parse, &svc_rdy);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT];
|
||||
reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES];
|
||||
svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32];
|
||||
mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT];
|
||||
ev = svc_rdy.ev;
|
||||
reg = svc_rdy.reg;
|
||||
svc_bmap = svc_rdy.svc_bmap;
|
||||
mem_reqs = svc_rdy.mem_reqs;
|
||||
|
||||
if (!ev || !reg || !svc_bmap || !mem_reqs) {
|
||||
kfree(tb);
|
||||
if (!ev || !reg || !svc_bmap || !mem_reqs)
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
/* This is an internal ABI compatibility check for WMI TLV so check it
|
||||
* here instead of the generic WMI code.
|
||||
|
@ -961,7 +997,6 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
|
|||
__le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
|
||||
__le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
|
||||
__le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
|
||||
kfree(tb);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
|
@ -982,12 +1017,10 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
|
|||
ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
|
||||
ath10k_wmi_tlv_parse_mem_reqs, arg);
|
||||
if (ret) {
|
||||
kfree(tb);
|
||||
ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kfree(tb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1406,7 +1439,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
|
|||
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
|
||||
|
||||
cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
|
||||
cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
|
||||
|
||||
cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers);
|
||||
cfg->ast_skid_limit = __cpu_to_le32(ar->hw_params.ast_skid_limit);
|
||||
cfg->num_wds_entries = __cpu_to_le32(ar->hw_params.num_wds_entries);
|
||||
|
||||
if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
|
||||
cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
|
||||
|
@ -1418,7 +1454,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
|
|||
|
||||
cfg->num_peer_keys = __cpu_to_le32(2);
|
||||
cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
|
||||
cfg->ast_skid_limit = __cpu_to_le32(0x10);
|
||||
cfg->tx_chain_mask = __cpu_to_le32(0x7);
|
||||
cfg->rx_chain_mask = __cpu_to_le32(0x7);
|
||||
cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
|
||||
|
@ -1434,7 +1469,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
|
|||
cfg->num_mcast_table_elems = __cpu_to_le32(0);
|
||||
cfg->mcast2ucast_mode = __cpu_to_le32(0);
|
||||
cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
|
||||
cfg->num_wds_entries = __cpu_to_le32(0x20);
|
||||
cfg->dma_burst_size = __cpu_to_le32(0);
|
||||
cfg->mac_aggr_delim = __cpu_to_le32(0);
|
||||
cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
|
||||
|
@ -2449,6 +2483,82 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
|
|||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
||||
{
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
|
||||
struct wmi_tlv_mgmt_tx_cmd *cmd;
|
||||
struct wmi_tlv *tlv;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
void *ptr;
|
||||
int len;
|
||||
u32 buf_len = msdu->len;
|
||||
u16 fc;
|
||||
struct ath10k_vif *arvif;
|
||||
dma_addr_t mgmt_frame_dma;
|
||||
u32 vdev_id;
|
||||
|
||||
if (!cb->vif)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
arvif = (void *)cb->vif->drv_priv;
|
||||
vdev_id = arvif->vdev_id;
|
||||
|
||||
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
len = sizeof(*cmd) + 2 * sizeof(*tlv);
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
len += IEEE80211_CCMP_MIC_LEN;
|
||||
buf_len += IEEE80211_CCMP_MIC_LEN;
|
||||
}
|
||||
|
||||
buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
|
||||
buf_len = round_up(buf_len, 4);
|
||||
|
||||
len += buf_len;
|
||||
len = round_up(len, 4);
|
||||
skb = ath10k_wmi_alloc_skb(ar, len);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ptr = (void *)skb->data;
|
||||
tlv = ptr;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
|
||||
tlv->len = __cpu_to_le16(sizeof(*cmd));
|
||||
cmd = (void *)tlv->value;
|
||||
cmd->vdev_id = __cpu_to_le32(vdev_id);
|
||||
cmd->desc_id = 0;
|
||||
cmd->chanfreq = 0;
|
||||
cmd->buf_len = __cpu_to_le32(buf_len);
|
||||
cmd->frame_len = __cpu_to_le32(msdu->len);
|
||||
mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data,
|
||||
msdu->len, DMA_TO_DEVICE);
|
||||
if (!mgmt_frame_dma)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
|
||||
|
||||
ptr += sizeof(*tlv);
|
||||
ptr += sizeof(*cmd);
|
||||
|
||||
tlv = ptr;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
|
||||
tlv->len = __cpu_to_le16(buf_len);
|
||||
|
||||
ptr += sizeof(*tlv);
|
||||
memcpy(ptr, msdu->data, buf_len);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
|
||||
enum wmi_force_fw_hang_type type,
|
||||
|
@ -3258,6 +3368,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
|
|||
.bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
|
||||
.prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
|
||||
.mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
|
||||
.mgmt_tx_send_cmdid = WMI_TLV_MGMT_TX_SEND_CMD,
|
||||
.prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
|
||||
.addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
|
||||
.addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
|
||||
|
@ -3592,6 +3703,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
|||
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
|
||||
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
|
||||
/* .gen_mgmt_tx = not implemented; HTT is used */
|
||||
.gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
|
||||
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
|
||||
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
|
||||
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define WMI_TLV_CMD_UNSUPPORTED 0
|
||||
#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
|
||||
#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
|
||||
#define WMI_TLV_MGMT_TX_FRAME_MAX_LEN 64
|
||||
|
||||
enum wmi_tlv_grp_id {
|
||||
WMI_TLV_GRP_START = 0x3,
|
||||
|
@ -132,6 +133,7 @@ enum wmi_tlv_cmd_id {
|
|||
WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
|
||||
WMI_TLV_MGMT_TX_CMDID,
|
||||
WMI_TLV_PRB_TMPL_CMDID,
|
||||
WMI_TLV_MGMT_TX_SEND_CMD,
|
||||
WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
|
||||
WMI_TLV_ADDBA_SEND_CMDID,
|
||||
WMI_TLV_ADDBA_STATUS_CMDID,
|
||||
|
@ -890,6 +892,63 @@ enum wmi_tlv_tag {
|
|||
WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
|
||||
WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_RESP_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SET_UTC_TIME_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_START_TIMING_ADVERT_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_STOP_TIMING_ADVERT_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_CMD,
|
||||
WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_RESP_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_DCC_GET_STATS_CMD,
|
||||
WMI_TLV_TAG_STRUCT_DCC_CHANNEL_STATS_REQUEST,
|
||||
WMI_TLV_TAG_STRUCT_DCC_GET_STATS_RESP_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_DCC_CLEAR_STATS_CMD,
|
||||
WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_CMD,
|
||||
WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_RESP_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_DCC_STATS_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_OCB_CHANNEL,
|
||||
WMI_TLV_TAG_STRUCT_OCB_SCHEDULE_ELEMENT,
|
||||
WMI_TLV_TAG_STRUCT_DCC_NDL_STATS_PER_CHANNEL,
|
||||
WMI_TLV_TAG_STRUCT_DCC_NDL_CHAN,
|
||||
WMI_TLV_TAG_STRUCT_QOS_PARAMETER,
|
||||
WMI_TLV_TAG_STRUCT_DCC_NDL_ACTIVE_STATE_CONFIG,
|
||||
WMI_TLV_TAG_STRUCT_ROAM_SCAN_EXTENDED_THRESHOLD_PARAM,
|
||||
WMI_TLV_TAG_STRUCT_ROAM_FILTER_FIXED_PARAM,
|
||||
WMI_TLV_TAG_STRUCT_PASSPOINT_CONFIG_CMD,
|
||||
WMI_TLV_TAG_STRUCT_PASSPOINT_EVENT_HDR,
|
||||
WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMD,
|
||||
WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_SSID_MATCH_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_VDEV_TSF_TSTAMP_ACTION_CMD,
|
||||
WMI_TLV_TAG_STRUCT_VDEV_TSF_REPORT_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_GET_FW_MEM_DUMP,
|
||||
WMI_TLV_TAG_STRUCT_UPDATE_FW_MEM_DUMP,
|
||||
WMI_TLV_TAG_STRUCT_FW_MEM_DUMP_PARAMS,
|
||||
WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH,
|
||||
WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH_COMPLETE,
|
||||
WMI_TLV_TAG_STRUCT_PEER_SET_RATE_REPORT_CONDITION,
|
||||
WMI_TLV_TAG_STRUCT_ROAM_SUBNET_CHANGE_CONFIG,
|
||||
WMI_TLV_TAG_STRUCT_VDEV_SET_IE_CMD,
|
||||
WMI_TLV_TAG_STRUCT_RSSI_BREACH_MONITOR_CONFIG,
|
||||
WMI_TLV_TAG_STRUCT_RSSI_BREACH_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_EVENT_INITIAL_WAKEUP,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_PCL_CMD,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_CMD,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_SOC_HW_MODE_TRANSITION_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_VDEV_TXRX_STREAMS,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_CMD,
|
||||
WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_RESPONSE_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_IOAC_SOCK_PATTERN_T,
|
||||
WMI_TLV_TAG_STRUCT_WOW_ENABLE_ICMPV6_NA_FLT_CMD,
|
||||
WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_CONFIG,
|
||||
WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_SUPPORTED_EVENT,
|
||||
WMI_TLV_TAG_STRUCT_PACKET_FILTER_CONFIG,
|
||||
WMI_TLV_TAG_STRUCT_PACKET_FILTER_ENABLE,
|
||||
WMI_TLV_TAG_STRUCT_SAP_SET_BLACKLIST_PARAM_CMD,
|
||||
WMI_TLV_TAG_STRUCT_MGMT_TX_CMD,
|
||||
|
||||
WMI_TLV_TAG_MAX
|
||||
};
|
||||
|
@ -965,6 +1024,50 @@ enum wmi_tlv_service {
|
|||
WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
|
||||
WMI_TLV_SERVICE_MDNS_OFFLOAD,
|
||||
WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
|
||||
WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
|
||||
WMI_TLV_SERVICE_OCB,
|
||||
WMI_TLV_SERVICE_AP_ARPNS_OFFLOAD,
|
||||
WMI_TLV_SERVICE_PER_BAND_CHAINMASK_SUPPORT,
|
||||
WMI_TLV_SERVICE_PACKET_FILTER_OFFLOAD,
|
||||
WMI_TLV_SERVICE_MGMT_TX_HTT,
|
||||
WMI_TLV_SERVICE_MGMT_TX_WMI,
|
||||
WMI_TLV_SERVICE_EXT_MSG,
|
||||
WMI_TLV_SERVICE_MAWC,
|
||||
WMI_TLV_SERVICE_PEER_ASSOC_CONF,
|
||||
WMI_TLV_SERVICE_EGAP,
|
||||
WMI_TLV_SERVICE_STA_PMF_OFFLOAD,
|
||||
WMI_TLV_SERVICE_UNIFIED_WOW_CAPABILITY,
|
||||
WMI_TLV_SERVICE_ENHANCED_PROXY_STA,
|
||||
WMI_TLV_SERVICE_ATF,
|
||||
WMI_TLV_SERVICE_COEX_GPIO,
|
||||
WMI_TLV_SERVICE_AUX_SPECTRAL_INTF,
|
||||
WMI_TLV_SERVICE_AUX_CHAN_LOAD_INTF,
|
||||
WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64,
|
||||
WMI_TLV_SERVICE_ENTERPRISE_MESH,
|
||||
WMI_TLV_SERVICE_RESTRT_CHNL_SUPPORT,
|
||||
WMI_TLV_SERVICE_BPF_OFFLOAD,
|
||||
WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
|
||||
WMI_TLV_SERVICE_SMART_ANTENNA_SW_SUPPORT,
|
||||
WMI_TLV_SERVICE_SMART_ANTENNA_HW_SUPPORT,
|
||||
WMI_TLV_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES,
|
||||
WMI_TLV_SERVICE_NAN_DATA,
|
||||
WMI_TLV_SERVICE_NAN_RTT,
|
||||
WMI_TLV_SERVICE_11AX,
|
||||
WMI_TLV_SERVICE_DEPRECATED_REPLACE,
|
||||
WMI_TLV_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
|
||||
WMI_TLV_SERVICE_ENHANCED_MCAST_FILTER,
|
||||
WMI_TLV_SERVICE_PERIODIC_CHAN_STAT_SUPPORT,
|
||||
WMI_TLV_SERVICE_MESH_11S,
|
||||
WMI_TLV_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT,
|
||||
WMI_TLV_SERVICE_VDEV_RX_FILTER,
|
||||
WMI_TLV_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT,
|
||||
WMI_TLV_SERVICE_MARK_FIRST_WAKEUP_PACKET,
|
||||
WMI_TLV_SERVICE_MULTIPLE_MCAST_FILTER_SET,
|
||||
WMI_TLV_SERVICE_HOST_MANAGED_RX_REORDER,
|
||||
WMI_TLV_SERVICE_FLASH_RDWR_SUPPORT,
|
||||
WMI_TLV_SERVICE_WLAN_STATS_REPORT,
|
||||
WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT,
|
||||
WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD,
|
||||
};
|
||||
|
||||
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
|
||||
|
@ -1121,6 +1224,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
|
|||
WMI_SERVICE_MDNS_OFFLOAD, len);
|
||||
SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
|
||||
WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
|
||||
SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
|
||||
WMI_SERVICE_MGMT_TX_WMI, len);
|
||||
}
|
||||
|
||||
#undef SVCMAP
|
||||
|
@ -1643,4 +1748,12 @@ struct wmi_tlv_tx_pause_ev {
|
|||
|
||||
void ath10k_wmi_tlv_attach(struct ath10k *ar);
|
||||
|
||||
struct wmi_tlv_mgmt_tx_cmd {
|
||||
__le32 vdev_id;
|
||||
__le32 desc_id;
|
||||
__le32 chanfreq;
|
||||
__le64 paddr;
|
||||
__le32 frame_len;
|
||||
__le32 buf_len;
|
||||
} __packed;
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "p2p.h"
|
||||
#include "hw.h"
|
||||
#include "hif.h"
|
||||
#include "txrx.h"
|
||||
|
||||
#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9
|
||||
#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ)
|
||||
|
@ -4456,6 +4457,74 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|||
__le32_to_cpu(ev->rate_max));
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_tdls_peer_event *ev;
|
||||
struct ath10k_peer *peer;
|
||||
struct ath10k_vif *arvif;
|
||||
int vdev_id;
|
||||
int peer_status;
|
||||
int peer_reason;
|
||||
u8 reason;
|
||||
|
||||
if (skb->len < sizeof(*ev)) {
|
||||
ath10k_err(ar, "received tdls peer event with invalid size (%d bytes)\n",
|
||||
skb->len);
|
||||
return;
|
||||
}
|
||||
|
||||
ev = (struct wmi_tdls_peer_event *)skb->data;
|
||||
vdev_id = __le32_to_cpu(ev->vdev_id);
|
||||
peer_status = __le32_to_cpu(ev->peer_status);
|
||||
peer_reason = __le32_to_cpu(ev->peer_reason);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find(ar, vdev_id, ev->peer_macaddr.addr);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "failed to find peer entry for %pM\n",
|
||||
ev->peer_macaddr.addr);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (peer_status) {
|
||||
case WMI_TDLS_SHOULD_TEARDOWN:
|
||||
switch (peer_reason) {
|
||||
case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
|
||||
case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE:
|
||||
case WMI_TDLS_TEARDOWN_REASON_RSSI:
|
||||
reason = WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE;
|
||||
break;
|
||||
default:
|
||||
reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
|
||||
break;
|
||||
}
|
||||
|
||||
arvif = ath10k_get_arvif(ar, vdev_id);
|
||||
if (!arvif) {
|
||||
ath10k_warn(ar, "received tdls peer event for invalid vdev id %u\n",
|
||||
vdev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_tdls_oper_request(arvif->vif, ev->peer_macaddr.addr,
|
||||
NL80211_TDLS_TEARDOWN, reason,
|
||||
GFP_ATOMIC);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"received tdls teardown event for peer %pM reason %u\n",
|
||||
ev->peer_macaddr.addr, peer_reason);
|
||||
break;
|
||||
default:
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"received unknown tdls peer event %u\n",
|
||||
peer_status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
|
||||
|
@ -5477,6 +5546,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
case WMI_10_4_PDEV_TPC_CONFIG_EVENTID:
|
||||
ath10k_wmi_event_pdev_tpc_config(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_TDLS_PEER_EVENTID:
|
||||
ath10k_wmi_handle_tdls_peer_event(ar, skb);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "Unknown eventid: %d\n", id);
|
||||
break;
|
||||
|
|
|
@ -195,6 +195,7 @@ enum wmi_service {
|
|||
WMI_SERVICE_SMART_LOGGING_SUPPORT,
|
||||
WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
|
||||
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
|
||||
WMI_SERVICE_MGMT_TX_WMI,
|
||||
|
||||
/* keep last */
|
||||
WMI_SERVICE_MAX,
|
||||
|
@ -797,6 +798,7 @@ struct wmi_cmd_map {
|
|||
u32 bcn_filter_rx_cmdid;
|
||||
u32 prb_req_filter_rx_cmdid;
|
||||
u32 mgmt_tx_cmdid;
|
||||
u32 mgmt_tx_send_cmdid;
|
||||
u32 prb_tmpl_cmdid;
|
||||
u32 addba_clear_resp_cmdid;
|
||||
u32 addba_send_cmdid;
|
||||
|
@ -5236,7 +5238,8 @@ enum wmi_10_4_vdev_param {
|
|||
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
|
||||
|
||||
#define WMI_TXBF_STS_CAP_OFFSET_LSB 4
|
||||
#define WMI_TXBF_STS_CAP_OFFSET_MASK 0xf0
|
||||
#define WMI_TXBF_STS_CAP_OFFSET_MASK 0x70
|
||||
#define WMI_TXBF_CONF_IMPLICIT_BF BIT(7)
|
||||
#define WMI_BF_SOUND_DIM_OFFSET_LSB 8
|
||||
#define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00
|
||||
|
||||
|
|
|
@ -2766,7 +2766,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
struct ieee80211_mgmt *mgmt;
|
||||
bool hidden = false;
|
||||
u8 *ies;
|
||||
int ies_len;
|
||||
struct wmi_connect_cmd p;
|
||||
int res;
|
||||
int i, ret;
|
||||
|
@ -2804,7 +2803,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
ies = mgmt->u.beacon.variable;
|
||||
if (ies > info->beacon.head + info->beacon.head_len)
|
||||
return -EINVAL;
|
||||
ies_len = info->beacon.head + info->beacon.head_len - ies;
|
||||
|
||||
if (info->ssid == NULL)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -1001,7 +1001,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr,
|
|||
|
||||
while (amsdu_len > mac_hdr_len) {
|
||||
hdr = (struct ethhdr *) framep;
|
||||
payload_8023_len = ntohs(hdr->h_proto);
|
||||
payload_8023_len = be16_to_cpu(hdr->h_proto);
|
||||
|
||||
if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN ||
|
||||
payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
|
||||
|
|
|
@ -61,13 +61,12 @@ config ATH9K_DEBUGFS
|
|||
depends on ATH9K && DEBUG_FS
|
||||
select MAC80211_DEBUGFS
|
||||
select ATH9K_COMMON_DEBUG
|
||||
select RELAY
|
||||
---help---
|
||||
Say Y, if you need access to ath9k's statistics for
|
||||
interrupts, rate control, etc.
|
||||
|
||||
Also required for changing debug message flags at run time.
|
||||
As well as access to the FFT/spectral data and TX99.
|
||||
Also required for changing debug message flags at run time and for
|
||||
TX99.
|
||||
|
||||
config ATH9K_STATION_STATISTICS
|
||||
bool "Detailed station statistics"
|
||||
|
@ -177,7 +176,6 @@ config ATH9K_HTC_DEBUGFS
|
|||
bool "Atheros ath9k_htc debugging"
|
||||
depends on ATH9K_HTC && DEBUG_FS
|
||||
select ATH9K_COMMON_DEBUG
|
||||
select RELAY
|
||||
---help---
|
||||
Say Y, if you need access to ath9k_htc's statistics.
|
||||
As well as access to the FFT/spectral data.
|
||||
|
@ -192,3 +190,11 @@ config ATH9K_HWRNG
|
|||
|
||||
Say Y, feeds the entropy directly from the WiFi driver to the input
|
||||
pool.
|
||||
|
||||
config ATH9K_COMMON_SPECTRAL
|
||||
bool "Atheros ath9k/ath9k_htc spectral scan support"
|
||||
depends on ATH9K_DEBUGFS || ATH9K_HTC_DEBUGFS
|
||||
select RELAY
|
||||
default n
|
||||
---help---
|
||||
Say Y to enable access to the FFT/spectral data via debugfs.
|
||||
|
|
|
@ -62,8 +62,8 @@ ath9k_common-y:= common.o \
|
|||
common-init.o \
|
||||
common-beacon.o \
|
||||
|
||||
ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o \
|
||||
common-spectral.o
|
||||
ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o
|
||||
ath9k_common-$(CONFIG_ATH9K_COMMON_SPECTRAL) += common-spectral.o
|
||||
|
||||
ath9k_htc-y += htc_hst.o \
|
||||
hif_usb.o \
|
||||
|
|
|
@ -151,7 +151,7 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
|
|||
return bins[0] & 0x3f;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATH9K_COMMON_DEBUG
|
||||
#ifdef CONFIG_ATH9K_COMMON_SPECTRAL
|
||||
void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy);
|
||||
void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv);
|
||||
|
||||
|
@ -183,6 +183,6 @@ static inline int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ATH9K_COMMON_DEBUG */
|
||||
#endif /* CONFIG_ATH9K_COMMON_SPECTRAL */
|
||||
|
||||
#endif /* SPECTRAL_H */
|
||||
|
|
|
@ -123,11 +123,9 @@ static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
|
|||
fft = (struct ath9k_dfs_fft_40 *) (data + 2);
|
||||
ath_dbg(common, DFS, "fixing datalen by 2\n");
|
||||
}
|
||||
if (IS_CHAN_HT40MINUS(ah->curchan)) {
|
||||
int temp = is_ctl;
|
||||
is_ctl = is_ext;
|
||||
is_ext = temp;
|
||||
}
|
||||
if (IS_CHAN_HT40MINUS(ah->curchan))
|
||||
swap(is_ctl, is_ext);
|
||||
|
||||
for (i = 0; i < FFT_NUM_SAMPLES; i++)
|
||||
max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
|
||||
is_ext);
|
||||
|
|
|
@ -1683,6 +1683,10 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
if (tid >= ATH9K_HTC_MAX_TID) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
||||
spin_lock_bh(&priv->tx.tx_lock);
|
||||
ista->tid_state[tid] = AGGR_OPERATIONAL;
|
||||
|
|
|
@ -348,6 +348,13 @@ enum wcn36xx_hal_host_msg_type {
|
|||
WCN36XX_HAL_DHCP_START_IND = 189,
|
||||
WCN36XX_HAL_DHCP_STOP_IND = 190,
|
||||
|
||||
/* Scan Offload(hw) APIs */
|
||||
WCN36XX_HAL_START_SCAN_OFFLOAD_REQ = 204,
|
||||
WCN36XX_HAL_START_SCAN_OFFLOAD_RSP = 205,
|
||||
WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ = 206,
|
||||
WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP = 207,
|
||||
WCN36XX_HAL_SCAN_OFFLOAD_IND = 210,
|
||||
|
||||
WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
|
||||
|
||||
WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
|
||||
|
@ -1115,6 +1122,101 @@ struct wcn36xx_hal_finish_scan_rsp_msg {
|
|||
|
||||
} __packed;
|
||||
|
||||
enum wcn36xx_hal_scan_type {
|
||||
WCN36XX_HAL_SCAN_TYPE_PASSIVE = 0x00,
|
||||
WCN36XX_HAL_SCAN_TYPE_ACTIVE = WCN36XX_HAL_MAX_ENUM_SIZE
|
||||
};
|
||||
|
||||
struct wcn36xx_hal_mac_ssid {
|
||||
u8 length;
|
||||
u8 ssid[32];
|
||||
} __packed;
|
||||
|
||||
struct wcn36xx_hal_start_scan_offload_req_msg {
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
|
||||
/* BSSIDs hot list */
|
||||
u8 num_bssid;
|
||||
u8 bssids[4][ETH_ALEN];
|
||||
|
||||
/* Directed probe-requests will be sent for listed SSIDs (max 10)*/
|
||||
u8 num_ssid;
|
||||
struct wcn36xx_hal_mac_ssid ssids[10];
|
||||
|
||||
/* Report AP with hidden ssid */
|
||||
u8 scan_hidden;
|
||||
|
||||
/* Self MAC address */
|
||||
u8 mac[ETH_ALEN];
|
||||
|
||||
/* BSS type */
|
||||
enum wcn36xx_hal_bss_type bss_type;
|
||||
|
||||
/* Scan type */
|
||||
enum wcn36xx_hal_scan_type scan_type;
|
||||
|
||||
/* Minimum scanning time on each channel (ms) */
|
||||
u32 min_ch_time;
|
||||
|
||||
/* Maximum scanning time on each channel */
|
||||
u32 max_ch_time;
|
||||
|
||||
/* Is a p2p search */
|
||||
u8 p2p_search;
|
||||
|
||||
/* Channels to scan */
|
||||
u8 num_channel;
|
||||
u8 channels[80];
|
||||
|
||||
/* IE field */
|
||||
u16 ie_len;
|
||||
u8 ie[0];
|
||||
} __packed;
|
||||
|
||||
struct wcn36xx_hal_start_scan_offload_rsp_msg {
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
|
||||
/* success or failure */
|
||||
u32 status;
|
||||
} __packed;
|
||||
|
||||
enum wcn36xx_hal_scan_offload_ind_type {
|
||||
/* Scan has been started */
|
||||
WCN36XX_HAL_SCAN_IND_STARTED = 0x01,
|
||||
/* Scan has been completed */
|
||||
WCN36XX_HAL_SCAN_IND_COMPLETED = 0x02,
|
||||
/* Moved to foreign channel */
|
||||
WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL = 0x08,
|
||||
/* scan request has been dequeued */
|
||||
WCN36XX_HAL_SCAN_IND_DEQUEUED = 0x10,
|
||||
/* preempted by other high priority scan */
|
||||
WCN36XX_HAL_SCAN_IND_PREEMPTED = 0x20,
|
||||
/* scan start failed */
|
||||
WCN36XX_HAL_SCAN_IND_FAILED = 0x40,
|
||||
/*scan restarted */
|
||||
WCN36XX_HAL_SCAN_IND_RESTARTED = 0x80,
|
||||
WCN36XX_HAL_SCAN_IND_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
|
||||
};
|
||||
|
||||
struct wcn36xx_hal_scan_offload_ind {
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
|
||||
u32 type;
|
||||
u32 channel_mhz;
|
||||
u32 scan_id;
|
||||
} __packed;
|
||||
|
||||
struct wcn36xx_hal_stop_scan_offload_req_msg {
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
} __packed;
|
||||
|
||||
struct wcn36xx_hal_stop_scan_offload_rsp_msg {
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
|
||||
/* success or failure */
|
||||
u32 status;
|
||||
} __packed;
|
||||
|
||||
enum wcn36xx_hal_rate_index {
|
||||
HW_RATE_INDEX_1MBPS = 0x82,
|
||||
HW_RATE_INDEX_2MBPS = 0x84,
|
||||
|
@ -1507,11 +1609,6 @@ struct wcn36xx_hal_edca_param_record {
|
|||
u16 txop_limit;
|
||||
} __packed;
|
||||
|
||||
struct wcn36xx_hal_mac_ssid {
|
||||
u8 length;
|
||||
u8 ssid[32];
|
||||
} __packed;
|
||||
|
||||
/* Concurrency role. These are generic IDs that identify the various roles
|
||||
* in the software system. */
|
||||
enum wcn36xx_hal_con_mode {
|
||||
|
|
|
@ -629,7 +629,6 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
|
|||
struct ieee80211_scan_request *hw_req)
|
||||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
|
||||
mutex_lock(&wcn->scan_lock);
|
||||
if (wcn->scan_req) {
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
|
@ -638,11 +637,16 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
wcn->scan_aborted = false;
|
||||
wcn->scan_req = &hw_req->req;
|
||||
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
|
||||
if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) {
|
||||
/* legacy manual/sw scan */
|
||||
schedule_work(&wcn->scan_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wcn36xx_smd_start_hw_scan(wcn, vif, &hw_req->req);
|
||||
}
|
||||
|
||||
static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
|
||||
|
@ -650,6 +654,12 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
|
||||
if (!wcn36xx_smd_stop_hw_scan(wcn)) {
|
||||
struct cfg80211_scan_info scan_info = { .aborted = true };
|
||||
|
||||
ieee80211_scan_completed(wcn->hw, &scan_info);
|
||||
}
|
||||
|
||||
mutex_lock(&wcn->scan_lock);
|
||||
wcn->scan_aborted = true;
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
|
|
|
@ -73,6 +73,8 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
|
|||
WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
|
||||
WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
|
||||
WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
|
||||
WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000),
|
||||
WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000),
|
||||
WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
|
||||
WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
|
||||
};
|
||||
|
@ -613,6 +615,85 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct wcn36xx_hal_start_scan_offload_req_msg msg_body;
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&wcn->hal_mutex);
|
||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);
|
||||
|
||||
msg_body.scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;
|
||||
msg_body.min_ch_time = 30;
|
||||
msg_body.min_ch_time = 100;
|
||||
msg_body.scan_hidden = 1;
|
||||
memcpy(msg_body.mac, vif->addr, ETH_ALEN);
|
||||
msg_body.p2p_search = vif->p2p;
|
||||
|
||||
msg_body.num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body.ssids));
|
||||
for (i = 0; i < msg_body.num_ssid; i++) {
|
||||
msg_body.ssids[i].length = min_t(u8, req->ssids[i].ssid_len,
|
||||
sizeof(msg_body.ssids[i].ssid));
|
||||
memcpy(msg_body.ssids[i].ssid, req->ssids[i].ssid,
|
||||
msg_body.ssids[i].length);
|
||||
}
|
||||
|
||||
msg_body.num_channel = min_t(u8, req->n_channels,
|
||||
sizeof(msg_body.channels));
|
||||
for (i = 0; i < msg_body.num_channel; i++)
|
||||
msg_body.channels[i] = req->channels[i]->hw_value;
|
||||
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL,
|
||||
"hal start hw-scan (channels: %u; ssids: %u; p2p: %s)\n",
|
||||
msg_body.num_channel, msg_body.num_ssid,
|
||||
msg_body.p2p_search ? "yes" : "no");
|
||||
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
|
||||
if (ret) {
|
||||
wcn36xx_err("Sending hal_start_scan_offload failed\n");
|
||||
goto out;
|
||||
}
|
||||
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
|
||||
if (ret) {
|
||||
wcn36xx_err("hal_start_scan_offload response failed err=%d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wcn->hal_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn)
|
||||
{
|
||||
struct wcn36xx_hal_stop_scan_offload_req_msg msg_body;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wcn->hal_mutex);
|
||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ);
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL, "hal stop hw-scan\n");
|
||||
|
||||
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
|
||||
if (ret) {
|
||||
wcn36xx_err("Sending hal_stop_scan_offload failed\n");
|
||||
goto out;
|
||||
}
|
||||
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
|
||||
if (ret) {
|
||||
wcn36xx_err("hal_stop_scan_offload response failed err=%d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wcn->hal_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)
|
||||
{
|
||||
struct wcn36xx_hal_switch_channel_rsp_msg *rsp;
|
||||
|
@ -2039,6 +2120,40 @@ static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
|
||||
{
|
||||
struct wcn36xx_hal_scan_offload_ind *rsp = buf;
|
||||
struct cfg80211_scan_info scan_info = {};
|
||||
|
||||
if (len != sizeof(*rsp)) {
|
||||
wcn36xx_warn("Corrupted delete scan indication\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)", rsp->type);
|
||||
|
||||
switch (rsp->type) {
|
||||
case WCN36XX_HAL_SCAN_IND_FAILED:
|
||||
scan_info.aborted = true;
|
||||
case WCN36XX_HAL_SCAN_IND_COMPLETED:
|
||||
mutex_lock(&wcn->scan_lock);
|
||||
wcn->scan_req = NULL;
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
ieee80211_scan_completed(wcn->hw, &scan_info);
|
||||
break;
|
||||
case WCN36XX_HAL_SCAN_IND_STARTED:
|
||||
case WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL:
|
||||
case WCN36XX_HAL_SCAN_IND_DEQUEUED:
|
||||
case WCN36XX_HAL_SCAN_IND_PREEMPTED:
|
||||
case WCN36XX_HAL_SCAN_IND_RESTARTED:
|
||||
break;
|
||||
default:
|
||||
wcn36xx_warn("Unknown scan indication type %x\n", rsp->type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
|
||||
void *buf,
|
||||
size_t len)
|
||||
|
@ -2250,6 +2365,8 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
|
|||
case WCN36XX_HAL_CH_SWITCH_RSP:
|
||||
case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
|
||||
case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
|
||||
case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP:
|
||||
case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP:
|
||||
memcpy(wcn->hal_buf, buf, len);
|
||||
wcn->hal_rsp_len = len;
|
||||
complete(&wcn->hal_rsp_compl);
|
||||
|
@ -2262,6 +2379,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
|
|||
case WCN36XX_HAL_MISSED_BEACON_IND:
|
||||
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
|
||||
case WCN36XX_HAL_PRINT_REG_INFO_IND:
|
||||
case WCN36XX_HAL_SCAN_OFFLOAD_IND:
|
||||
msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
|
||||
if (!msg_ind) {
|
||||
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
|
||||
|
@ -2298,6 +2416,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
|
|||
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
|
||||
struct wcn36xx_hal_ind_msg,
|
||||
list);
|
||||
list_del(wcn->hal_ind_queue.next);
|
||||
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
|
||||
|
||||
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
|
||||
|
||||
|
@ -2326,12 +2446,14 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
|
|||
hal_ind_msg->msg,
|
||||
hal_ind_msg->msg_len);
|
||||
break;
|
||||
case WCN36XX_HAL_SCAN_OFFLOAD_IND:
|
||||
wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
|
||||
hal_ind_msg->msg_len);
|
||||
break;
|
||||
default:
|
||||
wcn36xx_err("SMD_EVENT (%d) not supported\n",
|
||||
msg_header->msg_type);
|
||||
}
|
||||
list_del(wcn->hal_ind_queue.next);
|
||||
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
|
||||
kfree(hal_ind_msg);
|
||||
}
|
||||
int wcn36xx_smd_open(struct wcn36xx *wcn)
|
||||
|
|
|
@ -65,6 +65,9 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
|
|||
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
|
||||
enum wcn36xx_hal_sys_mode mode);
|
||||
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
|
||||
int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn);
|
||||
int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
|
||||
int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
|
||||
int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
|
||||
|
|
|
@ -901,7 +901,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
u64 *cookie)
|
||||
{
|
||||
const u8 *buf = params->buf;
|
||||
size_t len = params->len;
|
||||
size_t len = params->len, total;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
bool tx_status = false;
|
||||
|
@ -926,7 +926,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
if (len < sizeof(struct ieee80211_hdr_3addr))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
|
||||
total = sizeof(*cmd) + len;
|
||||
if (total < len)
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kmalloc(total, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -936,7 +940,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
cmd->len = cpu_to_le16(len);
|
||||
memcpy(cmd->payload, buf, len);
|
||||
|
||||
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
|
||||
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total,
|
||||
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
||||
if (rc == 0)
|
||||
tx_status = !evt.evt.status;
|
||||
|
@ -1727,9 +1731,12 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
|
|||
|
||||
wil_dbg_pm(wil, "suspending\n");
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
wil_p2p_stop_radio_operations(wil);
|
||||
wil_abort_scan(wil, true);
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
|
|
@ -242,12 +242,19 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
|
|||
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
int ret;
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx));
|
||||
wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, rx));
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -265,15 +272,37 @@ static const struct file_operations fops_mbox = {
|
|||
|
||||
static int wil_debugfs_iomem_x32_set(void *data, u64 val)
|
||||
{
|
||||
writel(val, (void __iomem *)data);
|
||||
struct wil_debugfs_iomem_data *d = (struct
|
||||
wil_debugfs_iomem_data *)data;
|
||||
struct wil6210_priv *wil = d->wil;
|
||||
int ret;
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
writel(val, (void __iomem *)d->offset);
|
||||
wmb(); /* make sure write propagated to HW */
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
|
||||
{
|
||||
*val = readl((void __iomem *)data);
|
||||
struct wil_debugfs_iomem_data *d = (struct
|
||||
wil_debugfs_iomem_data *)data;
|
||||
struct wil6210_priv *wil = d->wil;
|
||||
int ret;
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = readl((void __iomem *)d->offset);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -284,10 +313,21 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
|
|||
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
|
||||
umode_t mode,
|
||||
struct dentry *parent,
|
||||
void *value)
|
||||
void *value,
|
||||
struct wil6210_priv *wil)
|
||||
{
|
||||
return debugfs_create_file(name, mode, parent, value,
|
||||
&fops_iomem_x32);
|
||||
struct dentry *file;
|
||||
struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
|
||||
wil->dbg_data.iomem_data_count];
|
||||
|
||||
data->wil = wil;
|
||||
data->offset = value;
|
||||
|
||||
file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
|
||||
if (!IS_ERR_OR_NULL(file))
|
||||
wil->dbg_data.iomem_data_count++;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static int wil_debugfs_ulong_set(void *data, u64 val)
|
||||
|
@ -346,7 +386,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
|
|||
case doff_io32:
|
||||
f = wil_debugfs_create_iomem_x32(tbl[i].name,
|
||||
tbl[i].mode, dbg,
|
||||
base + tbl[i].off);
|
||||
base + tbl[i].off,
|
||||
wil);
|
||||
break;
|
||||
case doff_u8:
|
||||
f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
|
||||
|
@ -475,13 +516,22 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
|
|||
static int wil_memread_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
|
||||
void __iomem *a;
|
||||
int ret;
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
a = wmi_buffer(wil, cpu_to_le32(mem_addr));
|
||||
|
||||
if (a)
|
||||
seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
|
||||
else
|
||||
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -502,10 +552,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
|||
{
|
||||
enum { max_count = 4096 };
|
||||
struct wil_blob_wrapper *wil_blob = file->private_data;
|
||||
struct wil6210_priv *wil = wil_blob->wil;
|
||||
loff_t pos = *ppos;
|
||||
size_t available = wil_blob->blob.size;
|
||||
void *buf;
|
||||
size_t ret;
|
||||
int rc;
|
||||
|
||||
if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
|
||||
test_bit(wil_status_suspended, wil_blob->wil->status))
|
||||
|
@ -526,10 +578,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = wil_pm_runtime_get(wil);
|
||||
if (rc < 0) {
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_memcpy_fromio_32(buf, (const void __iomem *)
|
||||
wil_blob->blob.data + pos, count);
|
||||
|
||||
ret = copy_to_user(user_buf, buf, count);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
kfree(buf);
|
||||
if (ret == count)
|
||||
return -EFAULT;
|
||||
|
@ -1571,8 +1632,6 @@ static ssize_t wil_write_suspend_stats(struct file *file,
|
|||
struct wil6210_priv *wil = file->private_data;
|
||||
|
||||
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
|
||||
wil->suspend_stats.min_suspend_time = ULONG_MAX;
|
||||
wil->suspend_stats.collection_start = ktime_get();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -1582,33 +1641,41 @@ static ssize_t wil_read_suspend_stats(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
static char text[400];
|
||||
int n;
|
||||
unsigned long long stats_collection_time =
|
||||
ktime_to_us(ktime_sub(ktime_get(),
|
||||
wil->suspend_stats.collection_start));
|
||||
char *text;
|
||||
int n, ret, text_size = 500;
|
||||
|
||||
n = snprintf(text, sizeof(text),
|
||||
"Suspend statistics:\n"
|
||||
text = kmalloc(text_size, GFP_KERNEL);
|
||||
if (!text)
|
||||
return -ENOMEM;
|
||||
|
||||
n = snprintf(text, text_size,
|
||||
"Radio on suspend statistics:\n"
|
||||
"successful suspends:%ld failed suspends:%ld\n"
|
||||
"successful resumes:%ld failed resumes:%ld\n"
|
||||
"rejected by host:%ld rejected by device:%ld\n"
|
||||
"total suspend time:%lld min suspend time:%lld\n"
|
||||
"max suspend time:%lld stats collection time: %lld\n",
|
||||
wil->suspend_stats.successful_suspends,
|
||||
wil->suspend_stats.failed_suspends,
|
||||
wil->suspend_stats.successful_resumes,
|
||||
wil->suspend_stats.failed_resumes,
|
||||
wil->suspend_stats.rejected_by_host,
|
||||
"rejected by device:%ld\n"
|
||||
"Radio off suspend statistics:\n"
|
||||
"successful suspends:%ld failed suspends:%ld\n"
|
||||
"successful resumes:%ld failed resumes:%ld\n"
|
||||
"General statistics:\n"
|
||||
"rejected by host:%ld\n",
|
||||
wil->suspend_stats.r_on.successful_suspends,
|
||||
wil->suspend_stats.r_on.failed_suspends,
|
||||
wil->suspend_stats.r_on.successful_resumes,
|
||||
wil->suspend_stats.r_on.failed_resumes,
|
||||
wil->suspend_stats.rejected_by_device,
|
||||
wil->suspend_stats.total_suspend_time,
|
||||
wil->suspend_stats.min_suspend_time,
|
||||
wil->suspend_stats.max_suspend_time,
|
||||
stats_collection_time);
|
||||
wil->suspend_stats.r_off.successful_suspends,
|
||||
wil->suspend_stats.r_off.failed_suspends,
|
||||
wil->suspend_stats.r_off.successful_resumes,
|
||||
wil->suspend_stats.r_off.failed_resumes,
|
||||
wil->suspend_stats.rejected_by_host);
|
||||
|
||||
n = min_t(int, n, sizeof(text));
|
||||
n = min_t(int, n, text_size);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, text, n);
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
|
||||
|
||||
kfree(text);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_suspend_stats = {
|
||||
|
@ -1736,14 +1803,31 @@ static const struct dbg_off dbg_statics[] = {
|
|||
{},
|
||||
};
|
||||
|
||||
static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
|
||||
ARRAY_SIZE(dbg_wil_regs) - 1 +
|
||||
ARRAY_SIZE(pseudo_isr_off) - 1 +
|
||||
ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
|
||||
ARRAY_SIZE(tx_itr_cnt_off) - 1 +
|
||||
ARRAY_SIZE(rx_itr_cnt_off) - 1;
|
||||
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil)
|
||||
{
|
||||
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
|
||||
wil_to_wiphy(wil)->debugfsdir);
|
||||
|
||||
if (IS_ERR_OR_NULL(dbg))
|
||||
return -ENODEV;
|
||||
|
||||
wil->dbg_data.data_arr = kcalloc(dbg_off_count,
|
||||
sizeof(struct wil_debugfs_iomem_data),
|
||||
GFP_KERNEL);
|
||||
if (!wil->dbg_data.data_arr) {
|
||||
debugfs_remove_recursive(dbg);
|
||||
wil->debug = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wil->dbg_data.iomem_data_count = 0;
|
||||
|
||||
wil_pmc_init(wil);
|
||||
|
||||
wil6210_debugfs_init_files(wil, dbg);
|
||||
|
@ -1758,8 +1842,6 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
|||
|
||||
wil6210_debugfs_create_ITR_CNT(wil, dbg);
|
||||
|
||||
wil->suspend_stats.collection_start = ktime_get();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1768,6 +1850,8 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
|
|||
debugfs_remove_recursive(wil->debug);
|
||||
wil->debug = NULL;
|
||||
|
||||
kfree(wil->dbg_data.data_arr);
|
||||
|
||||
/* free pmc memory without sending command to fw, as it will
|
||||
* be reset on the way down anyway
|
||||
*/
|
||||
|
|
|
@ -47,9 +47,14 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
|
|||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
u32 tx_itr_en, tx_itr_val = 0;
|
||||
u32 rx_itr_en, rx_itr_val = 0;
|
||||
int ret;
|
||||
|
||||
wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
|
||||
if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
|
||||
tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH);
|
||||
|
@ -58,6 +63,8 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
|
|||
if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
|
||||
rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
cp->tx_coalesce_usecs = tx_itr_val;
|
||||
cp->rx_coalesce_usecs = rx_itr_val;
|
||||
return 0;
|
||||
|
@ -67,6 +74,7 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
|
|||
struct ethtool_coalesce *cp)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
int ret;
|
||||
|
||||
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
|
||||
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
|
||||
|
@ -86,8 +94,15 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
|
|||
|
||||
wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
|
||||
wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
|
||||
|
||||
ret = wil_pm_runtime_get(wil);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wil_configure_interrupt_moderation(wil);
|
||||
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return 0;
|
||||
|
||||
out_bad:
|
||||
|
|
|
@ -26,14 +26,17 @@
|
|||
prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii)
|
||||
|
||||
#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
|
||||
ioaddr = wmi_buffer(wil, val); \
|
||||
if (!ioaddr) { \
|
||||
wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
|
||||
le32_to_cpu(val)); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
static bool wil_fw_addr_check(struct wil6210_priv *wil,
|
||||
void __iomem **ioaddr, __le32 val,
|
||||
u32 size, const char *msg)
|
||||
{
|
||||
*ioaddr = wmi_buffer_block(wil, val, size);
|
||||
if (!(*ioaddr)) {
|
||||
wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* wil_fw_verify - verify firmware file validity
|
||||
|
@ -124,24 +127,19 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
|
||||
fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
const struct wil_fw_record_capabilities *rec = data;
|
||||
size_t capa_size;
|
||||
|
||||
if (size < sizeof(*rec) ||
|
||||
le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
|
||||
le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
capa_size = size - offsetof(struct wil_fw_record_capabilities,
|
||||
capabilities);
|
||||
|
@ -165,7 +163,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
FW_ADDR_CHECK(dst, d->addr, "address");
|
||||
if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
|
||||
return -EINVAL;
|
||||
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
|
||||
s);
|
||||
wil_memcpy_toio_32(dst, d->data, s);
|
||||
|
@ -197,7 +196,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
FW_ADDR_CHECK(dst, d->addr, "address");
|
||||
if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
|
||||
return -EINVAL;
|
||||
|
||||
v = le32_to_cpu(d->value);
|
||||
wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
|
||||
|
@ -253,7 +253,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
|
|||
u32 v = le32_to_cpu(block[i].value);
|
||||
u32 x, y;
|
||||
|
||||
FW_ADDR_CHECK(dst, block[i].addr, "address");
|
||||
if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address"))
|
||||
return -EINVAL;
|
||||
|
||||
x = readl(dst);
|
||||
y = (x & m) | (v & ~m);
|
||||
|
@ -319,10 +320,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
|
|||
wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
|
||||
n, gw_cmd);
|
||||
|
||||
FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
|
||||
FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
|
||||
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
|
||||
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
|
||||
if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
|
||||
"gateway_addr_addr") ||
|
||||
!wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0,
|
||||
"gateway_value_addr") ||
|
||||
!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
|
||||
"gateway_cmd_addr") ||
|
||||
!wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
|
||||
"gateway_ctrl_address"))
|
||||
return -EINVAL;
|
||||
|
||||
wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
|
||||
" cmd 0x%08x ctl 0x%08x\n",
|
||||
|
@ -378,12 +384,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
|
|||
wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
|
||||
n, gw_cmd);
|
||||
|
||||
FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
|
||||
if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
|
||||
"gateway_addr_addr"))
|
||||
return -EINVAL;
|
||||
for (k = 0; k < ARRAY_SIZE(block->value); k++)
|
||||
FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
|
||||
"gateway_value_addr");
|
||||
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
|
||||
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
|
||||
if (!wil_fw_addr_check(wil, &gwa_val[k],
|
||||
d->gateway_value_addr[k],
|
||||
0, "gateway_value_addr"))
|
||||
return -EINVAL;
|
||||
if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
|
||||
"gateway_cmd_addr") ||
|
||||
!wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
|
||||
"gateway_ctrl_address"))
|
||||
return -EINVAL;
|
||||
|
||||
wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
|
||||
le32_to_cpu(d->gateway_addr_addr),
|
||||
|
@ -422,7 +435,7 @@ static const struct {
|
|||
int (*parse_handler)(struct wil6210_priv *wil, const void *data,
|
||||
size_t size);
|
||||
} wil_fw_handlers[] = {
|
||||
{wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
|
||||
{wil_fw_type_comment, fw_handle_comment, fw_handle_comment},
|
||||
{wil_fw_type_data, fw_handle_data, fw_ignore_section},
|
||||
{wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
|
||||
/* wil_fw_type_action */
|
||||
|
@ -517,7 +530,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
|||
|
||||
rc = request_firmware(&fw, name, wil_to_dev(wil));
|
||||
if (rc) {
|
||||
wil_err_fw(wil, "Failed to load firmware %s\n", name);
|
||||
wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc);
|
||||
return rc;
|
||||
}
|
||||
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
|
||||
|
|
|
@ -358,6 +358,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil)
|
|||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
|
||||
}
|
||||
|
||||
static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
|
||||
{
|
||||
size_t min_size = sizeof(struct wil6210_mbox_hdr) +
|
||||
sizeof(struct wmi_cmd_hdr);
|
||||
|
||||
if (wil->mbox_ctl.rx.entry_size < min_size) {
|
||||
wil_err(wil, "rx mbox entry too small (%d)\n",
|
||||
wil->mbox_ctl.rx.entry_size);
|
||||
return false;
|
||||
}
|
||||
if (wil->mbox_ctl.tx.entry_size < min_size) {
|
||||
wil_err(wil, "tx mbox entry too small (%d)\n",
|
||||
wil->mbox_ctl.tx.entry_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
|
@ -393,6 +412,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
|||
if (isr & ISR_MISC_FW_READY) {
|
||||
wil_dbg_irq(wil, "IRQ: FW ready\n");
|
||||
wil_cache_mbox_regs(wil);
|
||||
if (wil_validate_mbox_regs(wil))
|
||||
set_bit(wil_status_mbox_ready, wil->status);
|
||||
/**
|
||||
* Actual FW ready indicated by the
|
||||
|
|
|
@ -579,7 +579,6 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
|
||||
WMI_WAKEUP_TRIGGER_BCAST;
|
||||
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
|
||||
wil->suspend_stats.min_suspend_time = ULONG_MAX;
|
||||
wil->vring_idle_trsh = 16;
|
||||
|
||||
return 0;
|
||||
|
@ -760,6 +759,8 @@ static void wil_collect_fw_info(struct wil6210_priv *wil)
|
|||
u8 retry_short;
|
||||
int rc;
|
||||
|
||||
wil_refresh_fw_capabilities(wil);
|
||||
|
||||
rc = wmi_get_mgmt_retry(wil, &retry_short);
|
||||
if (!rc) {
|
||||
wiphy->retry_short = retry_short;
|
||||
|
@ -767,6 +768,25 @@ static void wil_collect_fw_info(struct wil6210_priv *wil)
|
|||
}
|
||||
}
|
||||
|
||||
void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
|
||||
wil->keep_radio_on_during_sleep =
|
||||
wil->platform_ops.keep_radio_on_during_sleep &&
|
||||
wil->platform_ops.keep_radio_on_during_sleep(
|
||||
wil->platform_handle) &&
|
||||
test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
|
||||
|
||||
wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
|
||||
wil->keep_radio_on_during_sleep);
|
||||
|
||||
if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
else
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
|
||||
}
|
||||
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
|
||||
{
|
||||
le32_to_cpus(&r->base);
|
||||
|
@ -1071,11 +1091,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
return rc;
|
||||
}
|
||||
|
||||
wil_collect_fw_info(wil);
|
||||
|
||||
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
|
||||
wil_ps_update(wil, wil->ps_profile);
|
||||
|
||||
wil_collect_fw_info(wil);
|
||||
|
||||
if (wil->platform_ops.notify) {
|
||||
rc = wil->platform_ops.notify(wil->platform_handle,
|
||||
WIL_PLATFORM_EVT_FW_RDY);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
static int wil_open(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "open\n");
|
||||
|
||||
|
@ -30,16 +31,29 @@ static int wil_open(struct net_device *ndev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return wil_up(wil);
|
||||
rc = wil_pm_runtime_get(wil);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = wil_up(wil);
|
||||
if (rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_stop(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "stop\n");
|
||||
|
||||
return wil_down(wil);
|
||||
rc = wil_down(wil);
|
||||
if (!rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct net_device_ops wil_netdev_ops = {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/suspend.h>
|
||||
#include "wil6210.h"
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
static bool use_msi = true;
|
||||
module_param(use_msi, bool, 0444);
|
||||
|
@ -31,10 +32,8 @@ module_param(ftm_mode, bool, 0444);
|
|||
MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int wil6210_pm_notify(struct notifier_block *notify_block,
|
||||
unsigned long mode, void *unused);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static
|
||||
|
@ -84,9 +83,7 @@ void wil_set_capabilities(struct wil6210_priv *wil)
|
|||
|
||||
/* extract FW capabilities from file without loading the FW */
|
||||
wil_request_firmware(wil, wil->wil_fw_name, false);
|
||||
|
||||
if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
|
||||
wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
wil_refresh_fw_capabilities(wil);
|
||||
}
|
||||
|
||||
void wil_disable_irq(struct wil6210_priv *wil)
|
||||
|
@ -296,15 +293,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
wil_set_capabilities(wil);
|
||||
wil6210_clear_irq(wil);
|
||||
|
||||
wil->keep_radio_on_during_sleep =
|
||||
wil->platform_ops.keep_radio_on_during_sleep &&
|
||||
wil->platform_ops.keep_radio_on_during_sleep(
|
||||
wil->platform_handle) &&
|
||||
test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
|
||||
|
||||
wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
|
||||
wil->keep_radio_on_during_sleep);
|
||||
|
||||
/* FW should raise IRQ when ready */
|
||||
rc = wil_if_pcie_enable(wil);
|
||||
if (rc) {
|
||||
|
@ -320,7 +308,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
wil->pm_notify.notifier_call = wil6210_pm_notify;
|
||||
rc = register_pm_notifier(&wil->pm_notify);
|
||||
if (rc)
|
||||
|
@ -328,11 +315,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
* be prevented in a later phase if needed
|
||||
*/
|
||||
wil_err(wil, "register_pm_notifier failed: %d\n", rc);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
wil6210_debugfs_init(wil);
|
||||
|
||||
wil_pm_runtime_allow(wil);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -360,11 +347,11 @@ static void wil_pcie_remove(struct pci_dev *pdev)
|
|||
wil_dbg_misc(wil, "pcie_remove\n");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
unregister_pm_notifier(&wil->pm_notify);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
wil_pm_runtime_forbid(wil);
|
||||
|
||||
wil6210_debugfs_remove(wil);
|
||||
rtnl_lock();
|
||||
wil_p2p_wdev_free(wil);
|
||||
|
@ -386,13 +373,15 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
|
|||
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int wil6210_suspend(struct device *dev, bool is_runtime)
|
||||
{
|
||||
int rc = 0;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
|
||||
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
|
@ -400,16 +389,18 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = wil_suspend(wil, is_runtime);
|
||||
rc = wil_suspend(wil, is_runtime, keep_radio_on);
|
||||
if (!rc) {
|
||||
wil->suspend_stats.successful_suspends++;
|
||||
|
||||
/* If platform device supports keep_radio_on_during_sleep
|
||||
* it will control PCIe master
|
||||
/* In case radio stays on, platform device will control
|
||||
* PCIe master
|
||||
*/
|
||||
if (!wil->keep_radio_on_during_sleep)
|
||||
if (!keep_radio_on) {
|
||||
/* disable bus mastering */
|
||||
pci_clear_master(pdev);
|
||||
wil->suspend_stats.r_off.successful_suspends++;
|
||||
} else {
|
||||
wil->suspend_stats.r_on.successful_suspends++;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
|
@ -420,23 +411,32 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
|
|||
int rc = 0;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
|
||||
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
/* If platform device supports keep_radio_on_during_sleep it will
|
||||
* control PCIe master
|
||||
/* In case radio stays on, platform device will control
|
||||
* PCIe master
|
||||
*/
|
||||
if (!wil->keep_radio_on_during_sleep)
|
||||
if (!keep_radio_on)
|
||||
/* allow master */
|
||||
pci_set_master(pdev);
|
||||
rc = wil_resume(wil, is_runtime);
|
||||
rc = wil_resume(wil, is_runtime, keep_radio_on);
|
||||
if (rc) {
|
||||
wil_err(wil, "device failed to resume (%d)\n", rc);
|
||||
wil->suspend_stats.failed_resumes++;
|
||||
if (!wil->keep_radio_on_during_sleep)
|
||||
if (!keep_radio_on) {
|
||||
pci_clear_master(pdev);
|
||||
wil->suspend_stats.r_off.failed_resumes++;
|
||||
} else {
|
||||
wil->suspend_stats.successful_resumes++;
|
||||
wil->suspend_stats.r_on.failed_resumes++;
|
||||
}
|
||||
} else {
|
||||
if (keep_radio_on)
|
||||
wil->suspend_stats.r_on.successful_resumes++;
|
||||
else
|
||||
wil->suspend_stats.r_off.successful_resumes++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -490,12 +490,43 @@ static int wil6210_pm_resume(struct device *dev)
|
|||
{
|
||||
return wil6210_resume(dev, false);
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int wil6210_pm_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
|
||||
wil_dbg_pm(wil, "Runtime idle\n");
|
||||
|
||||
return wil_can_suspend(wil, true);
|
||||
}
|
||||
|
||||
static int wil6210_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
return wil6210_resume(dev, true);
|
||||
}
|
||||
|
||||
static int wil6210_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
|
||||
if (test_bit(wil_status_suspended, wil->status)) {
|
||||
wil_dbg_pm(wil, "trying to suspend while suspended\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return wil6210_suspend(dev, true);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops wil6210_pm_ops = {
|
||||
#ifdef CONFIG_PM
|
||||
SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
|
||||
SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
|
||||
wil6210_pm_runtime_resume,
|
||||
wil6210_pm_runtime_idle)
|
||||
#endif /* CONFIG_PM */
|
||||
};
|
||||
|
||||
static struct pci_driver wil6210_driver = {
|
||||
|
|
|
@ -16,15 +16,30 @@
|
|||
|
||||
#include "wil6210.h"
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
|
||||
|
||||
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
|
||||
wil->fw_capabilities);
|
||||
|
||||
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
if (wmi_only || debug_fw) {
|
||||
wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
|
||||
wmi_only ? "wmi_only" : "debug_fw");
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (is_runtime && !wil->platform_ops.suspend) {
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (!(ndev->flags & IFF_UP)) {
|
||||
/* can always sleep when down */
|
||||
wil_dbg_pm(wil, "Interface is down\n");
|
||||
|
@ -44,6 +59,10 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
/* interface is running */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
wil_dbg_pm(wil, "Sniffer\n");
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
/* for STA-like interface, don't runtime suspend */
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (test_bit(wil_status_fwconnecting, wil->status)) {
|
||||
|
@ -51,6 +70,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
/* Runtime pm not supported in case the interface is up */
|
||||
if (is_runtime) {
|
||||
wil_dbg_pm(wil, "STA-like interface\n");
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
/* AP-like interface - can't suspend */
|
||||
default:
|
||||
|
@ -158,7 +183,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
|
|||
break;
|
||||
wil_err(wil,
|
||||
"TO waiting for idle RX, suspend failed\n");
|
||||
wil->suspend_stats.failed_suspends++;
|
||||
wil->suspend_stats.r_on.failed_suspends++;
|
||||
goto resume_after_fail;
|
||||
}
|
||||
wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n");
|
||||
|
@ -174,7 +199,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
|
|||
*/
|
||||
if (!wil_is_wmi_idle(wil)) {
|
||||
wil_err(wil, "suspend failed due to pending WMI events\n");
|
||||
wil->suspend_stats.failed_suspends++;
|
||||
wil->suspend_stats.r_on.failed_suspends++;
|
||||
goto resume_after_fail;
|
||||
}
|
||||
|
||||
|
@ -188,7 +213,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
|
|||
if (rc) {
|
||||
wil_err(wil, "platform device failed to suspend (%d)\n",
|
||||
rc);
|
||||
wil->suspend_stats.failed_suspends++;
|
||||
wil->suspend_stats.r_on.failed_suspends++;
|
||||
wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
|
||||
wil_unmask_irq(wil);
|
||||
goto resume_after_fail;
|
||||
|
@ -235,6 +260,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
|
|||
rc = wil_down(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "wil_down : %d\n", rc);
|
||||
wil->suspend_stats.r_off.failed_suspends++;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +273,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
|
|||
rc = wil->platform_ops.suspend(wil->platform_handle, false);
|
||||
if (rc) {
|
||||
wil_enable_irq(wil);
|
||||
wil->suspend_stats.r_off.failed_suspends++;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -279,12 +306,9 @@ static int wil_resume_radio_off(struct wil6210_priv *wil)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
|
||||
int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
|
||||
{
|
||||
int rc = 0;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
|
||||
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
|
@ -301,19 +325,12 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
wil_dbg_pm(wil, "suspend: %s => %d\n",
|
||||
is_runtime ? "runtime" : "system", rc);
|
||||
|
||||
if (!rc)
|
||||
wil->suspend_stats.suspend_start_time = ktime_get();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_resume(struct wil6210_priv *wil, bool is_runtime)
|
||||
int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
|
||||
{
|
||||
int rc = 0;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
unsigned long long suspend_time_usec = 0;
|
||||
|
||||
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
|
@ -331,20 +348,49 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
|
|||
else
|
||||
rc = wil_resume_radio_off(wil);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
suspend_time_usec =
|
||||
ktime_to_us(ktime_sub(ktime_get(),
|
||||
wil->suspend_stats.suspend_start_time));
|
||||
wil->suspend_stats.total_suspend_time += suspend_time_usec;
|
||||
if (suspend_time_usec < wil->suspend_stats.min_suspend_time)
|
||||
wil->suspend_stats.min_suspend_time = suspend_time_usec;
|
||||
if (suspend_time_usec > wil->suspend_stats.max_suspend_time)
|
||||
wil->suspend_stats.max_suspend_time = suspend_time_usec;
|
||||
|
||||
out:
|
||||
wil_dbg_pm(wil, "resume: %s => %d, suspend time %lld usec\n",
|
||||
is_runtime ? "runtime" : "system", rc, suspend_time_usec);
|
||||
wil_dbg_pm(wil, "resume: %s => %d\n", is_runtime ? "runtime" : "system",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_pm_runtime_allow(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_allow(dev);
|
||||
}
|
||||
|
||||
void wil_pm_runtime_forbid(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
pm_runtime_forbid(dev);
|
||||
pm_runtime_get_noresume(dev);
|
||||
}
|
||||
|
||||
int wil_pm_runtime_get(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
rc = pm_runtime_get_sync(dev);
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc);
|
||||
pm_runtime_put_noidle(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_pm_runtime_put(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
|
|
@ -82,18 +82,18 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
|||
*/
|
||||
#define WIL_MAX_MPDU_OVERHEAD (62)
|
||||
|
||||
struct wil_suspend_stats {
|
||||
struct wil_suspend_count_stats {
|
||||
unsigned long successful_suspends;
|
||||
unsigned long failed_suspends;
|
||||
unsigned long successful_resumes;
|
||||
unsigned long failed_suspends;
|
||||
unsigned long failed_resumes;
|
||||
unsigned long rejected_by_device;
|
||||
};
|
||||
|
||||
struct wil_suspend_stats {
|
||||
struct wil_suspend_count_stats r_off;
|
||||
struct wil_suspend_count_stats r_on;
|
||||
unsigned long rejected_by_device; /* only radio on */
|
||||
unsigned long rejected_by_host;
|
||||
unsigned long long total_suspend_time;
|
||||
unsigned long long min_suspend_time;
|
||||
unsigned long long max_suspend_time;
|
||||
ktime_t collection_start;
|
||||
ktime_t suspend_start_time;
|
||||
};
|
||||
|
||||
/* Calculate MAC buffer size for the firmware. It includes all overhead,
|
||||
|
@ -616,6 +616,16 @@ struct blink_on_off_time {
|
|||
u32 off_ms;
|
||||
};
|
||||
|
||||
struct wil_debugfs_iomem_data {
|
||||
void *offset;
|
||||
struct wil6210_priv *wil;
|
||||
};
|
||||
|
||||
struct wil_debugfs_data {
|
||||
struct wil_debugfs_iomem_data *data_arr;
|
||||
int iomem_data_count;
|
||||
};
|
||||
|
||||
extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
|
||||
extern u8 led_id;
|
||||
extern u8 led_polarity;
|
||||
|
@ -708,6 +718,7 @@ struct wil6210_priv {
|
|||
u8 abft_len;
|
||||
u8 wakeup_trigger;
|
||||
struct wil_suspend_stats suspend_stats;
|
||||
struct wil_debugfs_data dbg_data;
|
||||
|
||||
void *platform_handle;
|
||||
struct wil_platform_ops platform_ops;
|
||||
|
@ -732,9 +743,7 @@ struct wil6210_priv {
|
|||
int fw_calib_result;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct notifier_block pm_notify;
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
bool suspend_resp_rcvd;
|
||||
|
@ -861,10 +870,12 @@ int wil_up(struct wil6210_priv *wil);
|
|||
int __wil_up(struct wil6210_priv *wil);
|
||||
int wil_down(struct wil6210_priv *wil);
|
||||
int __wil_down(struct wil6210_priv *wil);
|
||||
void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||
void wil_set_ethtoolops(struct net_device *ndev);
|
||||
|
||||
void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
||||
|
@ -999,9 +1010,14 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
|||
bool load);
|
||||
bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
|
||||
|
||||
void wil_pm_runtime_allow(struct wil6210_priv *wil);
|
||||
void wil_pm_runtime_forbid(struct wil6210_priv *wil);
|
||||
int wil_pm_runtime_get(struct wil6210_priv *wil);
|
||||
void wil_pm_runtime_put(struct wil6210_priv *wil);
|
||||
|
||||
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
|
||||
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
|
||||
int wil_resume(struct wil6210_priv *wil, bool is_runtime);
|
||||
int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on);
|
||||
int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on);
|
||||
bool wil_is_wmi_idle(struct wil6210_priv *wil);
|
||||
int wmi_resume(struct wil6210_priv *wil);
|
||||
int wmi_suspend(struct wil6210_priv *wil);
|
||||
|
|
|
@ -140,13 +140,15 @@ static u32 wmi_addr_remap(u32 x)
|
|||
/**
|
||||
* Check address validity for WMI buffer; remap if needed
|
||||
* @ptr - internal (linker) fw/ucode address
|
||||
* @size - if non zero, validate the block does not
|
||||
* exceed the device memory (bar)
|
||||
*
|
||||
* Valid buffer should be DWORD aligned
|
||||
*
|
||||
* return address for accessing buffer from the host;
|
||||
* if buffer is not valid, return NULL.
|
||||
*/
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
||||
void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
|
||||
{
|
||||
u32 off;
|
||||
u32 ptr = le32_to_cpu(ptr_);
|
||||
|
@ -161,10 +163,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
|||
off = HOSTADDR(ptr);
|
||||
if (off > wil->bar_size - 4)
|
||||
return NULL;
|
||||
if (size && ((off + size > wil->bar_size) || (off + size < off)))
|
||||
return NULL;
|
||||
|
||||
return wil->csr + off;
|
||||
}
|
||||
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
||||
{
|
||||
return wmi_buffer_block(wil, ptr_, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check address validity
|
||||
*/
|
||||
|
@ -198,6 +207,232 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *cmdid2name(u16 cmdid)
|
||||
{
|
||||
switch (cmdid) {
|
||||
case WMI_NOTIFY_REQ_CMDID:
|
||||
return "WMI_NOTIFY_REQ_CMD";
|
||||
case WMI_START_SCAN_CMDID:
|
||||
return "WMI_START_SCAN_CMD";
|
||||
case WMI_CONNECT_CMDID:
|
||||
return "WMI_CONNECT_CMD";
|
||||
case WMI_DISCONNECT_CMDID:
|
||||
return "WMI_DISCONNECT_CMD";
|
||||
case WMI_SW_TX_REQ_CMDID:
|
||||
return "WMI_SW_TX_REQ_CMD";
|
||||
case WMI_GET_RF_SECTOR_PARAMS_CMDID:
|
||||
return "WMI_GET_RF_SECTOR_PARAMS_CMD";
|
||||
case WMI_SET_RF_SECTOR_PARAMS_CMDID:
|
||||
return "WMI_SET_RF_SECTOR_PARAMS_CMD";
|
||||
case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID:
|
||||
return "WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD";
|
||||
case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID:
|
||||
return "WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD";
|
||||
case WMI_BRP_SET_ANT_LIMIT_CMDID:
|
||||
return "WMI_BRP_SET_ANT_LIMIT_CMD";
|
||||
case WMI_TOF_SESSION_START_CMDID:
|
||||
return "WMI_TOF_SESSION_START_CMD";
|
||||
case WMI_AOA_MEAS_CMDID:
|
||||
return "WMI_AOA_MEAS_CMD";
|
||||
case WMI_PMC_CMDID:
|
||||
return "WMI_PMC_CMD";
|
||||
case WMI_TOF_GET_TX_RX_OFFSET_CMDID:
|
||||
return "WMI_TOF_GET_TX_RX_OFFSET_CMD";
|
||||
case WMI_TOF_SET_TX_RX_OFFSET_CMDID:
|
||||
return "WMI_TOF_SET_TX_RX_OFFSET_CMD";
|
||||
case WMI_VRING_CFG_CMDID:
|
||||
return "WMI_VRING_CFG_CMD";
|
||||
case WMI_BCAST_VRING_CFG_CMDID:
|
||||
return "WMI_BCAST_VRING_CFG_CMD";
|
||||
case WMI_TRAFFIC_SUSPEND_CMDID:
|
||||
return "WMI_TRAFFIC_SUSPEND_CMD";
|
||||
case WMI_TRAFFIC_RESUME_CMDID:
|
||||
return "WMI_TRAFFIC_RESUME_CMD";
|
||||
case WMI_ECHO_CMDID:
|
||||
return "WMI_ECHO_CMD";
|
||||
case WMI_SET_MAC_ADDRESS_CMDID:
|
||||
return "WMI_SET_MAC_ADDRESS_CMD";
|
||||
case WMI_LED_CFG_CMDID:
|
||||
return "WMI_LED_CFG_CMD";
|
||||
case WMI_PCP_START_CMDID:
|
||||
return "WMI_PCP_START_CMD";
|
||||
case WMI_PCP_STOP_CMDID:
|
||||
return "WMI_PCP_STOP_CMD";
|
||||
case WMI_SET_SSID_CMDID:
|
||||
return "WMI_SET_SSID_CMD";
|
||||
case WMI_GET_SSID_CMDID:
|
||||
return "WMI_GET_SSID_CMD";
|
||||
case WMI_SET_PCP_CHANNEL_CMDID:
|
||||
return "WMI_SET_PCP_CHANNEL_CMD";
|
||||
case WMI_GET_PCP_CHANNEL_CMDID:
|
||||
return "WMI_GET_PCP_CHANNEL_CMD";
|
||||
case WMI_P2P_CFG_CMDID:
|
||||
return "WMI_P2P_CFG_CMD";
|
||||
case WMI_START_LISTEN_CMDID:
|
||||
return "WMI_START_LISTEN_CMD";
|
||||
case WMI_START_SEARCH_CMDID:
|
||||
return "WMI_START_SEARCH_CMD";
|
||||
case WMI_DISCOVERY_STOP_CMDID:
|
||||
return "WMI_DISCOVERY_STOP_CMD";
|
||||
case WMI_DELETE_CIPHER_KEY_CMDID:
|
||||
return "WMI_DELETE_CIPHER_KEY_CMD";
|
||||
case WMI_ADD_CIPHER_KEY_CMDID:
|
||||
return "WMI_ADD_CIPHER_KEY_CMD";
|
||||
case WMI_SET_APPIE_CMDID:
|
||||
return "WMI_SET_APPIE_CMD";
|
||||
case WMI_CFG_RX_CHAIN_CMDID:
|
||||
return "WMI_CFG_RX_CHAIN_CMD";
|
||||
case WMI_TEMP_SENSE_CMDID:
|
||||
return "WMI_TEMP_SENSE_CMD";
|
||||
case WMI_DEL_STA_CMDID:
|
||||
return "WMI_DEL_STA_CMD";
|
||||
case WMI_DISCONNECT_STA_CMDID:
|
||||
return "WMI_DISCONNECT_STA_CMD";
|
||||
case WMI_VRING_BA_EN_CMDID:
|
||||
return "WMI_VRING_BA_EN_CMD";
|
||||
case WMI_VRING_BA_DIS_CMDID:
|
||||
return "WMI_VRING_BA_DIS_CMD";
|
||||
case WMI_RCP_DELBA_CMDID:
|
||||
return "WMI_RCP_DELBA_CMD";
|
||||
case WMI_RCP_ADDBA_RESP_CMDID:
|
||||
return "WMI_RCP_ADDBA_RESP_CMD";
|
||||
case WMI_PS_DEV_PROFILE_CFG_CMDID:
|
||||
return "WMI_PS_DEV_PROFILE_CFG_CMD";
|
||||
case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
|
||||
return "WMI_SET_MGMT_RETRY_LIMIT_CMD";
|
||||
case WMI_GET_MGMT_RETRY_LIMIT_CMDID:
|
||||
return "WMI_GET_MGMT_RETRY_LIMIT_CMD";
|
||||
case WMI_ABORT_SCAN_CMDID:
|
||||
return "WMI_ABORT_SCAN_CMD";
|
||||
case WMI_NEW_STA_CMDID:
|
||||
return "WMI_NEW_STA_CMD";
|
||||
case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
|
||||
return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
|
||||
case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
|
||||
return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
|
||||
case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
|
||||
return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
|
||||
case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
|
||||
return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
|
||||
default:
|
||||
return "Untracked CMD";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *eventid2name(u16 eventid)
|
||||
{
|
||||
switch (eventid) {
|
||||
case WMI_NOTIFY_REQ_DONE_EVENTID:
|
||||
return "WMI_NOTIFY_REQ_DONE_EVENT";
|
||||
case WMI_DISCONNECT_EVENTID:
|
||||
return "WMI_DISCONNECT_EVENT";
|
||||
case WMI_SW_TX_COMPLETE_EVENTID:
|
||||
return "WMI_SW_TX_COMPLETE_EVENT";
|
||||
case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID:
|
||||
return "WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT";
|
||||
case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID:
|
||||
return "WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT";
|
||||
case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
|
||||
return "WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
|
||||
case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
|
||||
return "WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
|
||||
case WMI_BRP_SET_ANT_LIMIT_EVENTID:
|
||||
return "WMI_BRP_SET_ANT_LIMIT_EVENT";
|
||||
case WMI_FW_READY_EVENTID:
|
||||
return "WMI_FW_READY_EVENT";
|
||||
case WMI_TRAFFIC_RESUME_EVENTID:
|
||||
return "WMI_TRAFFIC_RESUME_EVENT";
|
||||
case WMI_TOF_GET_TX_RX_OFFSET_EVENTID:
|
||||
return "WMI_TOF_GET_TX_RX_OFFSET_EVENT";
|
||||
case WMI_TOF_SET_TX_RX_OFFSET_EVENTID:
|
||||
return "WMI_TOF_SET_TX_RX_OFFSET_EVENT";
|
||||
case WMI_VRING_CFG_DONE_EVENTID:
|
||||
return "WMI_VRING_CFG_DONE_EVENT";
|
||||
case WMI_READY_EVENTID:
|
||||
return "WMI_READY_EVENT";
|
||||
case WMI_RX_MGMT_PACKET_EVENTID:
|
||||
return "WMI_RX_MGMT_PACKET_EVENT";
|
||||
case WMI_TX_MGMT_PACKET_EVENTID:
|
||||
return "WMI_TX_MGMT_PACKET_EVENT";
|
||||
case WMI_SCAN_COMPLETE_EVENTID:
|
||||
return "WMI_SCAN_COMPLETE_EVENT";
|
||||
case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID:
|
||||
return "WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT";
|
||||
case WMI_CONNECT_EVENTID:
|
||||
return "WMI_CONNECT_EVENT";
|
||||
case WMI_EAPOL_RX_EVENTID:
|
||||
return "WMI_EAPOL_RX_EVENT";
|
||||
case WMI_BA_STATUS_EVENTID:
|
||||
return "WMI_BA_STATUS_EVENT";
|
||||
case WMI_RCP_ADDBA_REQ_EVENTID:
|
||||
return "WMI_RCP_ADDBA_REQ_EVENT";
|
||||
case WMI_DELBA_EVENTID:
|
||||
return "WMI_DELBA_EVENT";
|
||||
case WMI_VRING_EN_EVENTID:
|
||||
return "WMI_VRING_EN_EVENT";
|
||||
case WMI_DATA_PORT_OPEN_EVENTID:
|
||||
return "WMI_DATA_PORT_OPEN_EVENT";
|
||||
case WMI_AOA_MEAS_EVENTID:
|
||||
return "WMI_AOA_MEAS_EVENT";
|
||||
case WMI_TOF_SESSION_END_EVENTID:
|
||||
return "WMI_TOF_SESSION_END_EVENT";
|
||||
case WMI_TOF_GET_CAPABILITIES_EVENTID:
|
||||
return "WMI_TOF_GET_CAPABILITIES_EVENT";
|
||||
case WMI_TOF_SET_LCR_EVENTID:
|
||||
return "WMI_TOF_SET_LCR_EVENT";
|
||||
case WMI_TOF_SET_LCI_EVENTID:
|
||||
return "WMI_TOF_SET_LCI_EVENT";
|
||||
case WMI_TOF_FTM_PER_DEST_RES_EVENTID:
|
||||
return "WMI_TOF_FTM_PER_DEST_RES_EVENT";
|
||||
case WMI_TOF_CHANNEL_INFO_EVENTID:
|
||||
return "WMI_TOF_CHANNEL_INFO_EVENT";
|
||||
case WMI_TRAFFIC_SUSPEND_EVENTID:
|
||||
return "WMI_TRAFFIC_SUSPEND_EVENT";
|
||||
case WMI_ECHO_RSP_EVENTID:
|
||||
return "WMI_ECHO_RSP_EVENT";
|
||||
case WMI_LED_CFG_DONE_EVENTID:
|
||||
return "WMI_LED_CFG_DONE_EVENT";
|
||||
case WMI_PCP_STARTED_EVENTID:
|
||||
return "WMI_PCP_STARTED_EVENT";
|
||||
case WMI_PCP_STOPPED_EVENTID:
|
||||
return "WMI_PCP_STOPPED_EVENT";
|
||||
case WMI_GET_SSID_EVENTID:
|
||||
return "WMI_GET_SSID_EVENT";
|
||||
case WMI_GET_PCP_CHANNEL_EVENTID:
|
||||
return "WMI_GET_PCP_CHANNEL_EVENT";
|
||||
case WMI_P2P_CFG_DONE_EVENTID:
|
||||
return "WMI_P2P_CFG_DONE_EVENT";
|
||||
case WMI_LISTEN_STARTED_EVENTID:
|
||||
return "WMI_LISTEN_STARTED_EVENT";
|
||||
case WMI_SEARCH_STARTED_EVENTID:
|
||||
return "WMI_SEARCH_STARTED_EVENT";
|
||||
case WMI_DISCOVERY_STOPPED_EVENTID:
|
||||
return "WMI_DISCOVERY_STOPPED_EVENT";
|
||||
case WMI_CFG_RX_CHAIN_DONE_EVENTID:
|
||||
return "WMI_CFG_RX_CHAIN_DONE_EVENT";
|
||||
case WMI_TEMP_SENSE_DONE_EVENTID:
|
||||
return "WMI_TEMP_SENSE_DONE_EVENT";
|
||||
case WMI_RCP_ADDBA_RESP_SENT_EVENTID:
|
||||
return "WMI_RCP_ADDBA_RESP_SENT_EVENT";
|
||||
case WMI_PS_DEV_PROFILE_CFG_EVENTID:
|
||||
return "WMI_PS_DEV_PROFILE_CFG_EVENT";
|
||||
case WMI_SET_MGMT_RETRY_LIMIT_EVENTID:
|
||||
return "WMI_SET_MGMT_RETRY_LIMIT_EVENT";
|
||||
case WMI_GET_MGMT_RETRY_LIMIT_EVENTID:
|
||||
return "WMI_GET_MGMT_RETRY_LIMIT_EVENT";
|
||||
case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
|
||||
return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
|
||||
case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
|
||||
return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
|
||||
case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
|
||||
return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
|
||||
case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
|
||||
return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
|
||||
default:
|
||||
return "Untracked EVENT";
|
||||
}
|
||||
}
|
||||
|
||||
static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
{
|
||||
struct {
|
||||
|
@ -222,7 +457,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
uint retry;
|
||||
int rc = 0;
|
||||
|
||||
if (sizeof(cmd) + len > r->entry_size) {
|
||||
if (len > r->entry_size - sizeof(cmd)) {
|
||||
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
||||
(int)(sizeof(cmd) + len), r->entry_size);
|
||||
return -ERANGE;
|
||||
|
@ -294,7 +529,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|||
}
|
||||
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
|
||||
/* set command */
|
||||
wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
|
||||
wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n",
|
||||
cmdid2name(cmdid), cmdid, len);
|
||||
wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
|
||||
sizeof(cmd), true);
|
||||
wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
|
||||
|
@ -963,8 +1199,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
|||
}
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
|
||||
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
|
||||
id, wmi->mid, tstamp);
|
||||
wil_dbg_wmi(wil, "recv %s (0x%04x) MID %d @%d msec\n",
|
||||
eventid2name(id), id, wmi->mid, tstamp);
|
||||
trace_wil6210_wmi_event(wmi, &wmi[1],
|
||||
len - sizeof(*wmi));
|
||||
}
|
||||
|
@ -1380,8 +1616,14 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
|
|||
};
|
||||
int rc;
|
||||
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
|
||||
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
|
||||
struct wmi_set_appie_cmd *cmd;
|
||||
|
||||
if (len < ie_len) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd = kzalloc(len, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -1801,6 +2043,16 @@ void wmi_event_flush(struct wil6210_priv *wil)
|
|||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
}
|
||||
|
||||
static const char *suspend_status2name(u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
|
||||
return "LINK_NOT_IDLE";
|
||||
default:
|
||||
return "Untracked status";
|
||||
}
|
||||
}
|
||||
|
||||
int wmi_suspend(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
@ -1816,7 +2068,7 @@ int wmi_suspend(struct wil6210_priv *wil)
|
|||
wil->suspend_resp_rcvd = false;
|
||||
wil->suspend_resp_comp = false;
|
||||
|
||||
reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED;
|
||||
reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
|
||||
|
||||
rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
|
||||
|
@ -1848,8 +2100,9 @@ int wmi_suspend(struct wil6210_priv *wil)
|
|||
}
|
||||
|
||||
wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
|
||||
if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) {
|
||||
wil_dbg_pm(wil, "device rejected the suspend\n");
|
||||
if (reply.evt.status != WMI_TRAFFIC_SUSPEND_APPROVED) {
|
||||
wil_dbg_pm(wil, "device rejected the suspend, %s\n",
|
||||
suspend_status2name(reply.evt.status));
|
||||
wil->suspend_stats.rejected_by_device++;
|
||||
}
|
||||
rc = reply.evt.status;
|
||||
|
@ -1861,21 +2114,50 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void resume_triggers2string(u32 triggers, char *string, int str_size)
|
||||
{
|
||||
string[0] = '\0';
|
||||
|
||||
if (!triggers) {
|
||||
strlcat(string, " UNKNOWN", str_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (triggers & WMI_RESUME_TRIGGER_HOST)
|
||||
strlcat(string, " HOST", str_size);
|
||||
|
||||
if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
|
||||
strlcat(string, " UCAST_RX", str_size);
|
||||
|
||||
if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
|
||||
strlcat(string, " BCAST_RX", str_size);
|
||||
|
||||
if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
|
||||
strlcat(string, " WMI_EVT", str_size);
|
||||
}
|
||||
|
||||
int wmi_resume(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
char string[100];
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_traffic_resume_event evt;
|
||||
} __packed reply;
|
||||
|
||||
reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
|
||||
reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
|
||||
|
||||
rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
|
||||
WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
|
||||
WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
|
||||
if (rc)
|
||||
return rc;
|
||||
resume_triggers2string(le32_to_cpu(reply.evt.resume_triggers), string,
|
||||
sizeof(string));
|
||||
wil_dbg_pm(wil, "device resume %s, resume triggers:%s (0x%x)\n",
|
||||
reply.evt.status ? "failed" : "passed", string,
|
||||
le32_to_cpu(reply.evt.resume_triggers));
|
||||
|
||||
return reply.evt.status;
|
||||
}
|
||||
|
@ -1906,8 +2188,8 @@ static void wmi_event_handle(struct wil6210_priv *wil,
|
|||
void *evt_data = (void *)(&wmi[1]);
|
||||
u16 id = le16_to_cpu(wmi->command_id);
|
||||
|
||||
wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
|
||||
id, wil->reply_id);
|
||||
wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
|
||||
eventid2name(id), id, wil->reply_id);
|
||||
/* check if someone waits for this event */
|
||||
if (wil->reply_id && wil->reply_id == id) {
|
||||
WARN_ON(wil->reply_buf);
|
||||
|
|
|
@ -2268,7 +2268,7 @@ struct wmi_link_maintain_cfg_read_done_event {
|
|||
|
||||
enum wmi_traffic_suspend_status {
|
||||
WMI_TRAFFIC_SUSPEND_APPROVED = 0x0,
|
||||
WMI_TRAFFIC_SUSPEND_REJECTED = 0x1,
|
||||
WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1,
|
||||
};
|
||||
|
||||
/* WMI_TRAFFIC_SUSPEND_EVENTID */
|
||||
|
@ -2282,10 +2282,21 @@ enum wmi_traffic_resume_status {
|
|||
WMI_TRAFFIC_RESUME_FAILED = 0x1,
|
||||
};
|
||||
|
||||
enum wmi_resume_trigger {
|
||||
WMI_RESUME_TRIGGER_UNKNOWN = 0x0,
|
||||
WMI_RESUME_TRIGGER_HOST = 0x1,
|
||||
WMI_RESUME_TRIGGER_UCAST_RX = 0x2,
|
||||
WMI_RESUME_TRIGGER_BCAST_RX = 0x4,
|
||||
WMI_RESUME_TRIGGER_WMI_EVT = 0x8,
|
||||
};
|
||||
|
||||
/* WMI_TRAFFIC_RESUME_EVENTID */
|
||||
struct wmi_traffic_resume_event {
|
||||
/* enum wmi_traffic_resume_status_e */
|
||||
/* enum wmi_traffic_resume_status */
|
||||
u8 status;
|
||||
u8 reserved[3];
|
||||
/* enum wmi_resume_trigger bitmap */
|
||||
__le32 resume_triggers;
|
||||
} __packed;
|
||||
|
||||
/* Power Save command completion status codes */
|
||||
|
|
Loading…
Reference in New Issue