mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
Merge tag 'wireless-drivers-next-for-davem-2015-05-21' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== ath10k: * enable channel 144 on 5 GHz * enable Adaptive Noise Immunity (ANI) by default * add Wake on Wireless LAN (WOW) patterns support * add basic Tunneled Direct Link Setup (TDLS) support * add multi-channel support for QCA6174 * enable IBSS RSN support * enable Bluetooth Coexistance whenever firmware supports it * add more versatile way to set bitrates used by the firmware ath9k: * spectral scan: add support for multiple FFT frames per report iwlwifi: * major rework of the scan code (Luca) * some work on the thermal code (Chaya Rachel) * some work on the firwmare debugging infrastructure brcmfmac: * SDIO suspend and resume fixes * wiphy band info and changes in regulatory settings * add support for BCM4324 SDIO and BCM4358 PCIe * enable support of PCIe devices on router platforms (Hante) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
switch (bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
chip->ngpio = 32;
|
||||
@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
||||
}
|
||||
|
||||
/*
|
||||
* On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
|
||||
* pin numbers. We don't have Device Tree there and we can't really use
|
||||
* relative (per chip) numbers.
|
||||
* So let's use predictable base for BCM47XX and "random" for all other.
|
||||
* Register SoC GPIO devices with absolute GPIO pin base.
|
||||
* On MIPS, we don't have Device Tree and we can't use relative (per chip)
|
||||
* GPIO numbers.
|
||||
* On some ARM devices, user space may want to access some system GPIO
|
||||
* pins directly, which is easier to do with a predictable GPIO base.
|
||||
*/
|
||||
#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
||||
#else
|
||||
chip->base = -1;
|
||||
#endif
|
||||
if (IS_BUILTIN(CONFIG_BCM47XX) ||
|
||||
cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
||||
else
|
||||
chip->base = -1;
|
||||
|
||||
err = bcma_gpio_irq_domain_init(cc);
|
||||
if (err)
|
||||
|
||||
@@ -251,6 +251,7 @@ void ath_printk(const char *level, const struct ath_common *common,
|
||||
* @ATH_DBG_DFS: radar datection
|
||||
* @ATH_DBG_WOW: Wake on Wireless
|
||||
* @ATH_DBG_DYNACK: dynack handling
|
||||
* @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan
|
||||
* @ATH_DBG_ANY: enable all debugging
|
||||
*
|
||||
* The debug level is used to control the amount and type of debugging output
|
||||
@@ -280,6 +281,7 @@ enum ATH_DEBUG {
|
||||
ATH_DBG_WOW = 0x00020000,
|
||||
ATH_DBG_CHAN_CTX = 0x00040000,
|
||||
ATH_DBG_DYNACK = 0x00080000,
|
||||
ATH_DBG_SPECTRAL_SCAN = 0x00100000,
|
||||
ATH_DBG_ANY = 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@ ath10k_core-y += mac.o \
|
||||
wmi.o \
|
||||
wmi-tlv.o \
|
||||
bmi.o \
|
||||
hw.o
|
||||
hw.o \
|
||||
p2p.o
|
||||
|
||||
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
|
||||
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
|
||||
ath10k_core-$(CONFIG_THERMAL) += thermal.o
|
||||
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
|
||||
ath10k_core-$(CONFIG_PM) += wow.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
|
||||
ath10k_pci-y += pci.o \
|
||||
|
||||
@@ -482,6 +482,71 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_spec_board_file(struct ath10k *ar)
|
||||
{
|
||||
char filename[100];
|
||||
|
||||
scnprintf(filename, sizeof(filename), "board-%s-%s.bin",
|
||||
ath10k_bus_str(ar->hif.bus), ar->spec_board_id);
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
|
||||
if (IS_ERR(ar->board))
|
||||
return PTR_ERR(ar->board);
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
ar->spec_board_loaded = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_generic_board_file(struct ath10k *ar)
|
||||
{
|
||||
if (!ar->hw_params.fw.board) {
|
||||
ath10k_err(ar, "failed to find board file fw entry\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board))
|
||||
return PTR_ERR(ar->board);
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
ar->spec_board_loaded = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_board_file(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strlen(ar->spec_board_id) > 0) {
|
||||
ret = ath10k_core_fetch_spec_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_info(ar, "failed to load spec board file, falling back to generic: %d\n",
|
||||
ret);
|
||||
goto generic;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found specific board file for %s\n",
|
||||
ar->spec_board_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
generic:
|
||||
ret = ath10k_core_fetch_generic_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch generic board data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -491,23 +556,6 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ar->hw_params.fw.board == NULL) {
|
||||
ath10k_err(ar, "board data file not defined");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board)) {
|
||||
ret = PTR_ERR(ar->board);
|
||||
ath10k_err(ar, "could not fetch board data (%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
|
||||
ar->firmware = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.fw);
|
||||
@@ -675,6 +723,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
|
||||
ar->wmi.op_version);
|
||||
break;
|
||||
case ATH10K_FW_IE_HTT_OP_VERSION:
|
||||
if (ie_len != sizeof(u32))
|
||||
break;
|
||||
|
||||
version = (__le32 *)data;
|
||||
|
||||
ar->htt.op_version = le32_to_cpup(version);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",
|
||||
ar->htt.op_version);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "Unknown FW IE: %u\n",
|
||||
le32_to_cpu(hdr->id));
|
||||
@@ -695,27 +754,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* now fetch the board file */
|
||||
if (ar->hw_params.fw.board == NULL) {
|
||||
ath10k_err(ar, "board data file not defined");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board)) {
|
||||
ret = PTR_ERR(ar->board);
|
||||
ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
|
||||
ar->hw_params.fw.dir, ar->hw_params.fw.board,
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@@ -730,6 +768,19 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
/* calibration file is optional, don't check for any errors */
|
||||
ath10k_fetch_cal_file(ar);
|
||||
|
||||
ret = ath10k_core_fetch_board_file(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch board file: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->fw_api = 5;
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE);
|
||||
if (ret == 0)
|
||||
goto success;
|
||||
|
||||
ar->fw_api = 4;
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
|
||||
|
||||
@@ -958,6 +1009,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
ar->max_num_stations = TARGET_NUM_STATIONS;
|
||||
ar->max_num_vdevs = TARGET_NUM_VDEVS;
|
||||
ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
|
||||
ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
|
||||
WMI_STAT_PEER;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_1:
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_2:
|
||||
@@ -966,12 +1019,17 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
|
||||
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
|
||||
ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
|
||||
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_TLV:
|
||||
ar->max_num_peers = TARGET_TLV_NUM_PEERS;
|
||||
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
|
||||
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
|
||||
ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
|
||||
ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
|
||||
ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;
|
||||
ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
|
||||
WMI_STAT_PEER;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
||||
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
||||
@@ -979,6 +1037,29 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Backwards compatibility for firmwares without
|
||||
* ATH10K_FW_IE_HTT_OP_VERSION.
|
||||
*/
|
||||
if (ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {
|
||||
switch (ar->wmi.op_version) {
|
||||
case ATH10K_FW_WMI_OP_VERSION_MAIN:
|
||||
ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_1:
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_2:
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
|
||||
ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_TLV:
|
||||
ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
|
||||
break;
|
||||
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
||||
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1080,9 +1161,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
|
||||
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
if (status) {
|
||||
ath10k_warn(ar, "wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_hif_stop;
|
||||
}
|
||||
}
|
||||
@@ -1098,9 +1178,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_unified_ready(ar);
|
||||
if (status <= 0) {
|
||||
if (status) {
|
||||
ath10k_err(ar, "wmi unified ready event not received\n");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
@@ -1151,6 +1230,7 @@ EXPORT_SYMBOL(ath10k_core_start);
|
||||
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
|
||||
reinit_completion(&ar->target_suspend);
|
||||
|
||||
@@ -1160,9 +1240,9 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
|
||||
time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
|
||||
|
||||
if (ret == 0) {
|
||||
if (!time_left) {
|
||||
ath10k_warn(ar, "suspend timed out - target pause event never came\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@@ -1386,6 +1466,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
init_completion(&ar->wow.wakeup_completed);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "../dfs_pattern_detector.h"
|
||||
#include "spectral.h"
|
||||
#include "thermal.h"
|
||||
#include "wow.h"
|
||||
|
||||
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
|
||||
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
||||
@@ -43,15 +44,16 @@
|
||||
#define ATH10K_SCAN_ID 0
|
||||
#define WMI_READY_TIMEOUT (5 * HZ)
|
||||
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
|
||||
#define ATH10K_NUM_CHANS 38
|
||||
#define ATH10K_CONNECTION_LOSS_HZ (3*HZ)
|
||||
#define ATH10K_NUM_CHANS 39
|
||||
|
||||
/* Antenna noise floor */
|
||||
#define ATH10K_DEFAULT_NOISE_FLOOR -95
|
||||
|
||||
#define ATH10K_MAX_NUM_MGMT_PENDING 128
|
||||
|
||||
/* number of failed packets */
|
||||
#define ATH10K_KICKOUT_THRESHOLD 50
|
||||
/* number of failed packets (20 packets with 16 sw reties each) */
|
||||
#define ATH10K_KICKOUT_THRESHOLD (20 * 16)
|
||||
|
||||
/*
|
||||
* Use insanely high numbers to make sure that the firmware implementation
|
||||
@@ -82,6 +84,8 @@ struct ath10k_skb_cb {
|
||||
dma_addr_t paddr;
|
||||
u8 eid;
|
||||
u8 vdev_id;
|
||||
enum ath10k_hw_txrx_mode txmode;
|
||||
bool is_protected;
|
||||
|
||||
struct {
|
||||
u8 tid;
|
||||
@@ -280,6 +284,15 @@ struct ath10k_sta {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ath10k_chanctx {
|
||||
/* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally
|
||||
* mac80211 should allow some sort of explicit locking to guarantee
|
||||
* that the publicly available chanctx_conf can be accessed safely at
|
||||
* all times.
|
||||
*/
|
||||
struct ieee80211_chanctx_conf conf;
|
||||
};
|
||||
|
||||
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
|
||||
|
||||
enum ath10k_beacon_state {
|
||||
@@ -301,6 +314,7 @@ struct ath10k_vif {
|
||||
enum ath10k_beacon_state beacon_state;
|
||||
void *beacon_buf;
|
||||
dma_addr_t beacon_paddr;
|
||||
unsigned long tx_paused; /* arbitrary values defined by target */
|
||||
|
||||
struct ath10k *ar;
|
||||
struct ieee80211_vif *vif;
|
||||
@@ -334,13 +348,13 @@ struct ath10k_vif {
|
||||
} ap;
|
||||
} u;
|
||||
|
||||
u8 fixed_rate;
|
||||
u8 fixed_nss;
|
||||
u8 force_sgi;
|
||||
bool use_cts_prot;
|
||||
int num_legacy_stations;
|
||||
int txpower;
|
||||
struct wmi_wmm_params_all_arg wmm_params;
|
||||
struct work_struct ap_csa_work;
|
||||
struct delayed_work connection_loss_work;
|
||||
struct cfg80211_bitrate_mask bitrate_mask;
|
||||
};
|
||||
|
||||
struct ath10k_vif_iter {
|
||||
@@ -440,6 +454,12 @@ enum ath10k_fw_features {
|
||||
*/
|
||||
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
|
||||
|
||||
/* Some firmware revisions have an incomplete WoWLAN implementation
|
||||
* despite WMI service bit being advertised. This feature flag is used
|
||||
* to distinguish whether WoWLAN is really supported or not.
|
||||
*/
|
||||
ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
@@ -498,6 +518,11 @@ static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
enum ath10k_tx_pause_reason {
|
||||
ATH10K_TX_PAUSE_Q_FULL,
|
||||
ATH10K_TX_PAUSE_MAX,
|
||||
};
|
||||
|
||||
struct ath10k {
|
||||
struct ath_common ath_common;
|
||||
struct ieee80211_hw *hw;
|
||||
@@ -511,12 +536,15 @@ struct ath10k {
|
||||
u32 fw_version_minor;
|
||||
u16 fw_version_release;
|
||||
u16 fw_version_build;
|
||||
u32 fw_stats_req_mask;
|
||||
u32 phy_capability;
|
||||
u32 hw_min_tx_power;
|
||||
u32 hw_max_tx_power;
|
||||
u32 ht_cap_info;
|
||||
u32 vht_cap_info;
|
||||
u32 num_rf_chains;
|
||||
/* protected by conf_mutex */
|
||||
bool ani_enabled;
|
||||
|
||||
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
|
||||
|
||||
@@ -565,6 +593,9 @@ struct ath10k {
|
||||
|
||||
const struct firmware *cal_file;
|
||||
|
||||
char spec_board_id[100];
|
||||
bool spec_board_loaded;
|
||||
|
||||
int fw_api;
|
||||
enum ath10k_cal_mode cal_mode;
|
||||
|
||||
@@ -593,6 +624,7 @@ struct ath10k {
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
unsigned long long free_vdev_map;
|
||||
struct ath10k_vif *monitor_arvif;
|
||||
bool monitor;
|
||||
int monitor_vdev_id;
|
||||
bool monitor_started;
|
||||
@@ -633,6 +665,7 @@ struct ath10k {
|
||||
int max_num_peers;
|
||||
int max_num_stations;
|
||||
int max_num_vdevs;
|
||||
int max_num_tdls_vdevs;
|
||||
|
||||
struct work_struct offchan_tx_work;
|
||||
struct sk_buff_head offchan_tx_queue;
|
||||
@@ -655,6 +688,8 @@ struct ath10k {
|
||||
|
||||
struct dfs_pattern_detector *dfs_detector;
|
||||
|
||||
unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
struct ath10k_debug debug;
|
||||
#endif
|
||||
@@ -686,6 +721,7 @@ struct ath10k {
|
||||
} stats;
|
||||
|
||||
struct ath10k_thermal thermal;
|
||||
struct ath10k_wow wow;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
|
||||
@@ -124,10 +124,14 @@ EXPORT_SYMBOL(ath10k_info);
|
||||
|
||||
void ath10k_print_driver_info(struct ath10k *ar)
|
||||
{
|
||||
ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
|
||||
ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
|
||||
ar->hw_params.name,
|
||||
ar->target_version,
|
||||
ar->chip_id,
|
||||
(strlen(ar->spec_board_id) > 0 ? ", " : ""),
|
||||
ar->spec_board_id,
|
||||
(strlen(ar->spec_board_id) > 0 && !ar->spec_board_loaded
|
||||
? " fallback" : ""),
|
||||
ar->hw->wiphy->fw_version,
|
||||
ar->fw_api,
|
||||
ar->htt.target_version_major,
|
||||
@@ -380,12 +384,12 @@ unlock:
|
||||
|
||||
static int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long timeout, time_left;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(1*HZ);
|
||||
timeout = jiffies + msecs_to_jiffies(1 * HZ);
|
||||
|
||||
ath10k_debug_fw_stats_reset(ar);
|
||||
|
||||
@@ -395,18 +399,16 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
|
||||
reinit_completion(&ar->debug.fw_stats_complete);
|
||||
|
||||
ret = ath10k_wmi_request_stats(ar,
|
||||
WMI_STAT_PDEV |
|
||||
WMI_STAT_VDEV |
|
||||
WMI_STAT_PEER);
|
||||
ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "could not request stats (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
|
||||
1*HZ);
|
||||
if (ret == 0)
|
||||
time_left =
|
||||
wait_for_completion_timeout(&ar->debug.fw_stats_complete,
|
||||
1 * HZ);
|
||||
if (!time_left)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
@@ -1708,6 +1710,61 @@ static int ath10k_debug_cal_data_release(struct inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_write_ani_enable(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
int ret;
|
||||
u8 enable;
|
||||
|
||||
if (kstrtou8_from_user(user_buf, count, 0, &enable))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->ani_enabled == enable) {
|
||||
ret = count;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,
|
||||
enable);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
ar->ani_enabled = enable;
|
||||
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
int len = 0;
|
||||
char buf[32];
|
||||
|
||||
len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
||||
ar->ani_enabled);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ani_enable = {
|
||||
.read = ath10k_read_ani_enable,
|
||||
.write = ath10k_write_ani_enable,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations fops_cal_data = {
|
||||
.open = ath10k_debug_cal_data_open,
|
||||
.read = ath10k_debug_cal_data_read,
|
||||
@@ -1991,6 +2048,50 @@ static const struct file_operations fops_pktlog_filter = {
|
||||
.open = simple_open
|
||||
};
|
||||
|
||||
static ssize_t ath10k_write_quiet_period(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
u32 period;
|
||||
|
||||
if (kstrtouint_from_user(ubuf, count, 0, &period))
|
||||
return -EINVAL;
|
||||
|
||||
if (period < ATH10K_QUIET_PERIOD_MIN) {
|
||||
ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",
|
||||
period);
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ar->thermal.quiet_period = period;
|
||||
ath10k_thermal_set_throttling(ar);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[32];
|
||||
struct ath10k *ar = file->private_data;
|
||||
int len = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
||||
ar->thermal.quiet_period);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_quiet_period = {
|
||||
.read = ath10k_read_quiet_period,
|
||||
.write = ath10k_write_quiet_period,
|
||||
.open = simple_open
|
||||
};
|
||||
|
||||
int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
|
||||
@@ -2068,6 +2169,9 @@ int ath10k_debug_register(struct ath10k *ar)
|
||||
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_cal_data);
|
||||
|
||||
debugfs_create_file("ani_enable", S_IRUSR | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_ani_enable);
|
||||
|
||||
debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
|
||||
|
||||
@@ -2088,6 +2192,9 @@ int ath10k_debug_register(struct ath10k *ar)
|
||||
debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
|
||||
|
||||
debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar, &fops_quiet_period);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,21 +86,6 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
|
||||
}
|
||||
|
||||
/* assumes tx_lock is held */
|
||||
static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
|
||||
{
|
||||
struct ath10k *ar = ep->htc->ar;
|
||||
|
||||
if (!ep->tx_credit_flow_enabled)
|
||||
return false;
|
||||
if (ep->tx_credits >= ep->tx_credits_per_max_message)
|
||||
return false;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
|
||||
ep->eid);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -111,13 +96,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
|
||||
hdr->eid = ep->eid;
|
||||
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
|
||||
hdr->flags = 0;
|
||||
hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
|
||||
|
||||
spin_lock_bh(&ep->htc->tx_lock);
|
||||
hdr->seq_no = ep->seq_no++;
|
||||
|
||||
if (ath10k_htc_ep_need_credit_update(ep))
|
||||
hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
|
||||
|
||||
spin_unlock_bh(&ep->htc->tx_lock);
|
||||
}
|
||||
|
||||
@@ -414,7 +396,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;
|
||||
|
||||
switch (__le16_to_cpu(msg->hdr.message_id)) {
|
||||
default:
|
||||
case ATH10K_HTC_MSG_READY_ID:
|
||||
case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
|
||||
/* handle HTC control message */
|
||||
if (completion_done(&htc->ctl_resp)) {
|
||||
/*
|
||||
@@ -438,6 +421,10 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
|
||||
break;
|
||||
case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
|
||||
htc->htc_ops.target_send_suspend_complete(ar);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n");
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@@ -548,6 +535,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
{
|
||||
struct ath10k *ar = htc->ar;
|
||||
int i, status = 0;
|
||||
unsigned long time_left;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
struct ath10k_htc_msg *msg;
|
||||
@@ -555,9 +543,9 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
u16 credit_count;
|
||||
u16 credit_size;
|
||||
|
||||
status = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_WAIT_TIMEOUT_HZ);
|
||||
if (status == 0) {
|
||||
time_left = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_WAIT_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
/* Workaround: In some cases the PCI HIF doesn't
|
||||
* receive interrupt for the control response message
|
||||
* even if the buffer was completed. It is suspected
|
||||
@@ -569,10 +557,11 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
for (i = 0; i < CE_COUNT; i++)
|
||||
ath10k_hif_send_complete_check(htc->ar, i, 1);
|
||||
|
||||
status = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_WAIT_TIMEOUT_HZ);
|
||||
time_left =
|
||||
wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_WAIT_TIMEOUT_HZ);
|
||||
|
||||
if (status == 0)
|
||||
if (!time_left)
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -646,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
struct sk_buff *skb;
|
||||
unsigned int max_msg_size = 0;
|
||||
int length, status;
|
||||
unsigned long time_left;
|
||||
bool disable_credit_flow_ctrl = false;
|
||||
u16 message_id, service_id, flags = 0;
|
||||
u8 tx_alloc = 0;
|
||||
@@ -701,10 +691,10 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
}
|
||||
|
||||
/* wait for response */
|
||||
status = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
|
||||
if (status == 0) {
|
||||
ath10k_err(ar, "Service connect timeout: %d\n", status);
|
||||
time_left = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
ath10k_err(ar, "Service connect timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,86 @@
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
|
||||
[HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
};
|
||||
|
||||
static const enum htt_t2h_msg_type htt_10x_t2h_msg_types[] = {
|
||||
[HTT_10X_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_10X_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_10X_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_10X_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
[HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
[HTT_10X_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD] = HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
||||
[HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
};
|
||||
|
||||
static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = {
|
||||
[HTT_TLV_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_TLV_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE] =
|
||||
HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
|
||||
[HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
};
|
||||
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
@@ -66,6 +146,24 @@ int ath10k_htt_init(struct ath10k *ar)
|
||||
8 + /* llc snap */
|
||||
2; /* ip4 dscp or ip6 priority */
|
||||
|
||||
switch (ar->htt.op_version) {
|
||||
case ATH10K_FW_HTT_OP_VERSION_10_1:
|
||||
ar->htt.t2h_msg_types = htt_10x_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_TLV:
|
||||
ar->htt.t2h_msg_types = htt_tlv_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_TLV_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_MAIN:
|
||||
ar->htt.t2h_msg_types = htt_main_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_MAIN_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_MAX:
|
||||
case ATH10K_FW_HTT_OP_VERSION_UNSET:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "htc.h"
|
||||
#include "hw.h"
|
||||
#include "rx_desc.h"
|
||||
#include "hw.h"
|
||||
|
||||
enum htt_dbg_stats_type {
|
||||
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
|
||||
@@ -271,35 +273,108 @@ enum htt_mgmt_tx_status {
|
||||
|
||||
/*=== target -> host messages ===============================================*/
|
||||
|
||||
enum htt_t2h_msg_type {
|
||||
HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0,
|
||||
HTT_T2H_MSG_TYPE_RX_IND = 0x1,
|
||||
HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2,
|
||||
HTT_T2H_MSG_TYPE_PEER_MAP = 0x3,
|
||||
HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
|
||||
HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5,
|
||||
HTT_T2H_MSG_TYPE_RX_DELBA = 0x6,
|
||||
HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
|
||||
HTT_T2H_MSG_TYPE_PKTLOG = 0x8,
|
||||
HTT_T2H_MSG_TYPE_STATS_CONF = 0x9,
|
||||
HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
|
||||
HTT_T2H_MSG_TYPE_SEC_IND = 0xb,
|
||||
HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
|
||||
HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe,
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
|
||||
HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10,
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
|
||||
HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
|
||||
enum htt_main_t2h_msg_type {
|
||||
HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF = 0x0,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_IND = 0x1,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH = 0x2,
|
||||
HTT_MAIN_T2H_MSG_TYPE_PEER_MAP = 0x3,
|
||||
HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA = 0x5,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_DELBA = 0x6,
|
||||
HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
|
||||
HTT_MAIN_T2H_MSG_TYPE_PKTLOG = 0x8,
|
||||
HTT_MAIN_T2H_MSG_TYPE_STATS_CONF = 0x9,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
|
||||
HTT_MAIN_T2H_MSG_TYPE_SEC_IND = 0xb,
|
||||
HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
|
||||
HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
|
||||
HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND = 0x10,
|
||||
HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
|
||||
HTT_MAIN_T2H_MSG_TYPE_TEST,
|
||||
/* keep this last */
|
||||
HTT_MAIN_T2H_NUM_MSGS
|
||||
};
|
||||
|
||||
enum htt_10x_t2h_msg_type {
|
||||
HTT_10X_T2H_MSG_TYPE_VERSION_CONF = 0x0,
|
||||
HTT_10X_T2H_MSG_TYPE_RX_IND = 0x1,
|
||||
HTT_10X_T2H_MSG_TYPE_RX_FLUSH = 0x2,
|
||||
HTT_10X_T2H_MSG_TYPE_PEER_MAP = 0x3,
|
||||
HTT_10X_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
|
||||
HTT_10X_T2H_MSG_TYPE_RX_ADDBA = 0x5,
|
||||
HTT_10X_T2H_MSG_TYPE_RX_DELBA = 0x6,
|
||||
HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
|
||||
HTT_10X_T2H_MSG_TYPE_PKTLOG = 0x8,
|
||||
HTT_10X_T2H_MSG_TYPE_STATS_CONF = 0x9,
|
||||
HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
|
||||
HTT_10X_T2H_MSG_TYPE_SEC_IND = 0xb,
|
||||
HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
|
||||
HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
|
||||
HTT_10X_T2H_MSG_TYPE_TEST = 0xe,
|
||||
HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE = 0xf,
|
||||
HTT_10X_T2H_MSG_TYPE_AGGR_CONF = 0x11,
|
||||
HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x12,
|
||||
HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0x13,
|
||||
/* keep this last */
|
||||
HTT_10X_T2H_NUM_MSGS
|
||||
};
|
||||
|
||||
enum htt_tlv_t2h_msg_type {
|
||||
HTT_TLV_T2H_MSG_TYPE_VERSION_CONF = 0x0,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_IND = 0x1,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_FLUSH = 0x2,
|
||||
HTT_TLV_T2H_MSG_TYPE_PEER_MAP = 0x3,
|
||||
HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_ADDBA = 0x5,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_DELBA = 0x6,
|
||||
HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
|
||||
HTT_TLV_T2H_MSG_TYPE_PKTLOG = 0x8,
|
||||
HTT_TLV_T2H_MSG_TYPE_STATS_CONF = 0x9,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
|
||||
HTT_TLV_T2H_MSG_TYPE_SEC_IND = 0xb,
|
||||
HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, /* deprecated */
|
||||
HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
|
||||
HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
|
||||
HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_PN_IND = 0x10,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
|
||||
/* 0x13 reservd */
|
||||
HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
|
||||
HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
|
||||
HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE = 0x15,
|
||||
HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR = 0x16,
|
||||
HTT_TLV_T2H_MSG_TYPE_TEST,
|
||||
/* keep this last */
|
||||
HTT_TLV_T2H_NUM_MSGS
|
||||
};
|
||||
|
||||
/* FIXME: Do not depend on this event id. Numbering of this event id is
|
||||
* broken across different firmware revisions and HTT version fails to
|
||||
* indicate this.
|
||||
*/
|
||||
enum htt_t2h_msg_type {
|
||||
HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
HTT_T2H_MSG_TYPE_RX_IND,
|
||||
HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
|
||||
HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
|
||||
HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
|
||||
HTT_T2H_MSG_TYPE_AGGR_CONF,
|
||||
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
||||
HTT_T2H_MSG_TYPE_TEST,
|
||||
|
||||
/* keep this last */
|
||||
HTT_T2H_NUM_MSGS
|
||||
};
|
||||
@@ -1222,6 +1297,7 @@ struct htt_tx_done {
|
||||
u32 msdu_id;
|
||||
bool discard;
|
||||
bool no_ack;
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct htt_peer_map_event {
|
||||
@@ -1248,6 +1324,10 @@ struct ath10k_htt {
|
||||
u8 target_version_major;
|
||||
u8 target_version_minor;
|
||||
struct completion target_version_received;
|
||||
enum ath10k_fw_htt_op_version op_version;
|
||||
|
||||
const enum htt_t2h_msg_type *t2h_msg_types;
|
||||
u32 t2h_msg_types_max;
|
||||
|
||||
struct {
|
||||
/*
|
||||
|
||||
@@ -637,58 +637,21 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rfc1042_hdr {
|
||||
u8 llc_dsap;
|
||||
u8 llc_ssap;
|
||||
u8 llc_ctrl;
|
||||
u8 snap_oui[3];
|
||||
__be16 snap_type;
|
||||
} __packed;
|
||||
|
||||
struct amsdu_subframe_hdr {
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 src[ETH_ALEN];
|
||||
__be16 len;
|
||||
} __packed;
|
||||
|
||||
static const u8 rx_legacy_rate_idx[] = {
|
||||
3, /* 0x00 - 11Mbps */
|
||||
2, /* 0x01 - 5.5Mbps */
|
||||
1, /* 0x02 - 2Mbps */
|
||||
0, /* 0x03 - 1Mbps */
|
||||
3, /* 0x04 - 11Mbps */
|
||||
2, /* 0x05 - 5.5Mbps */
|
||||
1, /* 0x06 - 2Mbps */
|
||||
0, /* 0x07 - 1Mbps */
|
||||
10, /* 0x08 - 48Mbps */
|
||||
8, /* 0x09 - 24Mbps */
|
||||
6, /* 0x0A - 12Mbps */
|
||||
4, /* 0x0B - 6Mbps */
|
||||
11, /* 0x0C - 54Mbps */
|
||||
9, /* 0x0D - 36Mbps */
|
||||
7, /* 0x0E - 18Mbps */
|
||||
5, /* 0x0F - 9Mbps */
|
||||
};
|
||||
|
||||
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *status,
|
||||
struct htt_rx_desc *rxd)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 cck, rate, bw, sgi, mcs, nss;
|
||||
u8 preamble = 0;
|
||||
u32 info1, info2, info3;
|
||||
|
||||
/* Band value can't be set as undefined but freq can be 0 - use that to
|
||||
* determine whether band is provided.
|
||||
*
|
||||
* FIXME: Perhaps this can go away if CCK rate reporting is a little
|
||||
* reworked?
|
||||
*/
|
||||
if (!status->freq)
|
||||
return;
|
||||
|
||||
band = status->band;
|
||||
info1 = __le32_to_cpu(rxd->ppdu_start.info1);
|
||||
info2 = __le32_to_cpu(rxd->ppdu_start.info2);
|
||||
info3 = __le32_to_cpu(rxd->ppdu_start.info3);
|
||||
@@ -697,31 +660,18 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
|
||||
switch (preamble) {
|
||||
case HTT_RX_LEGACY:
|
||||
/* To get legacy rate index band is required. Since band can't
|
||||
* be undefined check if freq is non-zero.
|
||||
*/
|
||||
if (!status->freq)
|
||||
return;
|
||||
|
||||
cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
|
||||
rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
|
||||
rate_idx = 0;
|
||||
rate &= ~RX_PPDU_START_RATE_FLAG;
|
||||
|
||||
if (rate < 0x08 || rate > 0x0F)
|
||||
break;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (cck)
|
||||
rate &= ~BIT(3);
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
/* We are using same rate table registering
|
||||
HW - ath10k_rates[]. In case of 5GHz skip
|
||||
CCK rates, so -4 here */
|
||||
rate_idx -= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status->rate_idx = rate_idx;
|
||||
sband = &ar->mac.sbands[status->band];
|
||||
status->rate_idx = ath10k_mac_hw_rate_to_idx(sband, rate);
|
||||
break;
|
||||
case HTT_RX_HT:
|
||||
case HTT_RX_HT_WITH_TXBF:
|
||||
@@ -773,8 +723,87 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
}
|
||||
}
|
||||
|
||||
static struct ieee80211_channel *
|
||||
ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
struct ath10k_vif *arvif;
|
||||
struct cfg80211_chan_def def;
|
||||
u16 peer_id;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
if (!rxd)
|
||||
return NULL;
|
||||
|
||||
if (rxd->attention.flags &
|
||||
__cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID))
|
||||
return NULL;
|
||||
|
||||
if (!(rxd->msdu_end.info0 &
|
||||
__cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)))
|
||||
return NULL;
|
||||
|
||||
peer_id = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
RX_MPDU_START_INFO0_PEER_IDX);
|
||||
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
if (!peer)
|
||||
return NULL;
|
||||
|
||||
arvif = ath10k_get_arvif(ar, peer->vdev_id);
|
||||
if (WARN_ON_ONCE(!arvif))
|
||||
return NULL;
|
||||
|
||||
if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
|
||||
return NULL;
|
||||
|
||||
return def.chan;
|
||||
}
|
||||
|
||||
static struct ieee80211_channel *
|
||||
ath10k_htt_rx_h_vdev_channel(struct ath10k *ar, u32 vdev_id)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
struct cfg80211_chan_def def;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
if (arvif->vdev_id == vdev_id &&
|
||||
ath10k_mac_vif_chan(arvif->vif, &def) == 0)
|
||||
return def.chan;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_htt_rx_h_any_chan_iter(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *conf,
|
||||
void *data)
|
||||
{
|
||||
struct cfg80211_chan_def *def = data;
|
||||
|
||||
*def = conf->def;
|
||||
}
|
||||
|
||||
static struct ieee80211_channel *
|
||||
ath10k_htt_rx_h_any_channel(struct ath10k *ar)
|
||||
{
|
||||
struct cfg80211_chan_def def = {};
|
||||
|
||||
ieee80211_iter_chan_contexts_atomic(ar->hw,
|
||||
ath10k_htt_rx_h_any_chan_iter,
|
||||
&def);
|
||||
|
||||
return def.chan;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *status)
|
||||
struct ieee80211_rx_status *status,
|
||||
struct htt_rx_desc *rxd,
|
||||
u32 vdev_id)
|
||||
{
|
||||
struct ieee80211_channel *ch;
|
||||
|
||||
@@ -782,6 +811,12 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
if (!ch)
|
||||
ch = ath10k_htt_rx_h_peer_channel(ar, rxd);
|
||||
if (!ch)
|
||||
ch = ath10k_htt_rx_h_vdev_channel(ar, vdev_id);
|
||||
if (!ch)
|
||||
ch = ath10k_htt_rx_h_any_channel(ar);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!ch)
|
||||
@@ -819,7 +854,8 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
|
||||
|
||||
static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *status)
|
||||
struct ieee80211_rx_status *status,
|
||||
u32 vdev_id)
|
||||
{
|
||||
struct sk_buff *first;
|
||||
struct htt_rx_desc *rxd;
|
||||
@@ -851,7 +887,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
|
||||
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
ath10k_htt_rx_h_signal(ar, status, rxd);
|
||||
ath10k_htt_rx_h_channel(ar, status);
|
||||
ath10k_htt_rx_h_channel(ar, status, rxd, vdev_id);
|
||||
ath10k_htt_rx_h_rates(ar, status, rxd);
|
||||
}
|
||||
|
||||
@@ -1522,7 +1558,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
||||
@@ -1569,7 +1605,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
||||
@@ -1598,6 +1634,7 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
|
||||
tx_done.no_ack = true;
|
||||
break;
|
||||
case HTT_DATA_TX_STATUS_OK:
|
||||
tx_done.success = true;
|
||||
break;
|
||||
case HTT_DATA_TX_STATUS_DISCARD:
|
||||
case HTT_DATA_TX_STATUS_POSTPONE:
|
||||
@@ -1796,7 +1833,7 @@ static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
||||
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
ath10k_htt_rx_h_rx_offload_prot(status, msdu);
|
||||
ath10k_htt_rx_h_channel(ar, status);
|
||||
ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
|
||||
ath10k_process_rx(ar, status, msdu);
|
||||
}
|
||||
}
|
||||
@@ -1869,7 +1906,7 @@ static void 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.
|
||||
*/
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, status);
|
||||
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);
|
||||
ath10k_htt_rx_h_deliver(ar, &amsdu, status);
|
||||
@@ -1892,6 +1929,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
struct htt_resp *resp = (struct htt_resp *)skb->data;
|
||||
enum htt_t2h_msg_type type;
|
||||
|
||||
/* confirm alignment */
|
||||
if (!IS_ALIGNED((unsigned long)skb->data, 4))
|
||||
@@ -1899,7 +1937,16 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
|
||||
resp->hdr.msg_type);
|
||||
switch (resp->hdr.msg_type) {
|
||||
|
||||
if (resp->hdr.msg_type >= ar->htt.t2h_msg_types_max) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, unsupported msg_type: 0x%0X\n max: 0x%0X",
|
||||
resp->hdr.msg_type, ar->htt.t2h_msg_types_max);
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
type = ar->htt.t2h_msg_types[resp->hdr.msg_type];
|
||||
|
||||
switch (type) {
|
||||
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
|
||||
htt->target_version_major = resp->ver_resp.major;
|
||||
htt->target_version_minor = resp->ver_resp.minor;
|
||||
@@ -1937,6 +1984,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
||||
switch (status) {
|
||||
case HTT_MGMT_TX_STATUS_OK:
|
||||
tx_done.success = true;
|
||||
break;
|
||||
case HTT_MGMT_TX_STATUS_RETRY:
|
||||
tx_done.no_ack = true;
|
||||
@@ -1976,7 +2024,6 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TEST:
|
||||
/* FIX THIS */
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_STATS_CONF:
|
||||
trace_ath10k_htt_stats(ar, skb->data, skb->len);
|
||||
@@ -2018,11 +2065,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
return;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
|
||||
/* FIXME: This WMI-TLV event is overlapping with 10.2
|
||||
* CHAN_CHANGE - both being 0xF. Neither is being used in
|
||||
* practice so no immediate action is necessary. Nevertheless
|
||||
* HTT may need an abstraction layer like WMI has one day.
|
||||
*/
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_CHAN_CHANGE:
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "htt event (%d) not handled\n",
|
||||
|
||||
@@ -26,7 +26,7 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
htt->num_pending_tx--;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
||||
ieee80211_wake_queues(htt->ar->hw);
|
||||
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
@@ -49,7 +49,7 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||
|
||||
htt->num_pending_tx++;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx)
|
||||
ieee80211_stop_queues(htt->ar->hw);
|
||||
ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
@@ -420,9 +420,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
int res;
|
||||
u8 flags0 = 0;
|
||||
u16 msdu_id, flags1 = 0;
|
||||
dma_addr_t paddr;
|
||||
u32 frags_paddr;
|
||||
bool use_frags;
|
||||
dma_addr_t paddr = 0;
|
||||
u32 frags_paddr = 0;
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt);
|
||||
if (res)
|
||||
@@ -440,12 +439,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
prefetch_len = min(htt->prefetch_len, msdu->len);
|
||||
prefetch_len = roundup(prefetch_len, 4);
|
||||
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
|
||||
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
|
||||
* fragment list host driver specifies directly frame pointer. */
|
||||
use_frags = htt->target_version_major < 3 ||
|
||||
!ieee80211_is_mgmt(hdr->frame_control);
|
||||
|
||||
skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
|
||||
&paddr);
|
||||
if (!skb_cb->htt.txbuf) {
|
||||
@@ -466,7 +459,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
if (res)
|
||||
goto err_free_txbuf;
|
||||
|
||||
if (likely(use_frags)) {
|
||||
switch (skb_cb->txmode) {
|
||||
case ATH10K_HW_TXRX_RAW:
|
||||
case ATH10K_HW_TXRX_NATIVE_WIFI:
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
|
||||
/* pass through */
|
||||
case ATH10K_HW_TXRX_ETHERNET:
|
||||
frags = skb_cb->htt.txbuf->frags;
|
||||
|
||||
frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
|
||||
@@ -474,15 +472,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
frags[1].paddr = 0;
|
||||
frags[1].len = 0;
|
||||
|
||||
flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
|
||||
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
|
||||
frags_paddr = skb_cb->htt.txbuf_paddr;
|
||||
} else {
|
||||
break;
|
||||
case ATH10K_HW_TXRX_MGMT:
|
||||
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
|
||||
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
|
||||
|
||||
frags_paddr = skb_cb->paddr;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Normally all commands go through HTC which manages tx credits for
|
||||
@@ -508,11 +508,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
prefetch_len);
|
||||
skb_cb->htt.txbuf->htc_hdr.flags = 0;
|
||||
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
if (!skb_cb->is_protected)
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
|
||||
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
|
||||
|
||||
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
|
||||
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
|
||||
if (msdu->ip_summed == CHECKSUM_PARTIAL) {
|
||||
|
||||
@@ -78,6 +78,9 @@ enum qca6174_chip_id_rev {
|
||||
/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
|
||||
#define ATH10K_FW_API4_FILE "firmware-4.bin"
|
||||
|
||||
/* HTT id conflict fix for management frames over HTT */
|
||||
#define ATH10K_FW_API5_FILE "firmware-5.bin"
|
||||
|
||||
#define ATH10K_FW_UTF_FILE "utf.bin"
|
||||
|
||||
/* includes also the null byte */
|
||||
@@ -104,6 +107,11 @@ enum ath10k_fw_ie_type {
|
||||
* FW API 4 and above.
|
||||
*/
|
||||
ATH10K_FW_IE_WMI_OP_VERSION = 5,
|
||||
|
||||
/* HTT "operations" interface version, 32 bit value. Supported from
|
||||
* FW API 5 and above.
|
||||
*/
|
||||
ATH10K_FW_IE_HTT_OP_VERSION = 6,
|
||||
};
|
||||
|
||||
enum ath10k_fw_wmi_op_version {
|
||||
@@ -119,6 +127,20 @@ enum ath10k_fw_wmi_op_version {
|
||||
ATH10K_FW_WMI_OP_VERSION_MAX,
|
||||
};
|
||||
|
||||
enum ath10k_fw_htt_op_version {
|
||||
ATH10K_FW_HTT_OP_VERSION_UNSET = 0,
|
||||
|
||||
ATH10K_FW_HTT_OP_VERSION_MAIN = 1,
|
||||
|
||||
/* also used in 10.2 and 10.2.4 branches */
|
||||
ATH10K_FW_HTT_OP_VERSION_10_1 = 2,
|
||||
|
||||
ATH10K_FW_HTT_OP_VERSION_TLV = 3,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_HTT_OP_VERSION_MAX,
|
||||
};
|
||||
|
||||
enum ath10k_hw_rev {
|
||||
ATH10K_HW_QCA988X,
|
||||
ATH10K_HW_QCA6174,
|
||||
@@ -180,6 +202,27 @@ struct ath10k_pktlog_hdr {
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
enum ath10k_hw_rate_ofdm {
|
||||
ATH10K_HW_RATE_OFDM_48M = 0,
|
||||
ATH10K_HW_RATE_OFDM_24M,
|
||||
ATH10K_HW_RATE_OFDM_12M,
|
||||
ATH10K_HW_RATE_OFDM_6M,
|
||||
ATH10K_HW_RATE_OFDM_54M,
|
||||
ATH10K_HW_RATE_OFDM_36M,
|
||||
ATH10K_HW_RATE_OFDM_18M,
|
||||
ATH10K_HW_RATE_OFDM_9M,
|
||||
};
|
||||
|
||||
enum ath10k_hw_rate_cck {
|
||||
ATH10K_HW_RATE_CCK_LP_11M = 0,
|
||||
ATH10K_HW_RATE_CCK_LP_5_5M,
|
||||
ATH10K_HW_RATE_CCK_LP_2M,
|
||||
ATH10K_HW_RATE_CCK_LP_1M,
|
||||
ATH10K_HW_RATE_CCK_SP_11M,
|
||||
ATH10K_HW_RATE_CCK_SP_5_5M,
|
||||
ATH10K_HW_RATE_CCK_SP_2M,
|
||||
};
|
||||
|
||||
/* Target specific defines for MAIN firmware */
|
||||
#define TARGET_NUM_VDEVS 8
|
||||
#define TARGET_NUM_PEER_AST 2
|
||||
@@ -223,7 +266,7 @@ struct ath10k_pktlog_hdr {
|
||||
#define TARGET_10X_NUM_WDS_ENTRIES 32
|
||||
#define TARGET_10X_DMA_BURST_SIZE 0
|
||||
#define TARGET_10X_MAC_AGGR_DELIM 0
|
||||
#define TARGET_10X_AST_SKID_LIMIT 16
|
||||
#define TARGET_10X_AST_SKID_LIMIT 128
|
||||
#define TARGET_10X_NUM_STATIONS 128
|
||||
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
|
||||
(TARGET_10X_NUM_VDEVS))
|
||||
@@ -256,13 +299,13 @@ struct ath10k_pktlog_hdr {
|
||||
#define TARGET_10_2_DMA_BURST_SIZE 1
|
||||
|
||||
/* Target specific defines for WMI-TLV firmware */
|
||||
#define TARGET_TLV_NUM_VDEVS 3
|
||||
#define TARGET_TLV_NUM_VDEVS 4
|
||||
#define TARGET_TLV_NUM_STATIONS 32
|
||||
#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
|
||||
(TARGET_TLV_NUM_VDEVS) + \
|
||||
2)
|
||||
#define TARGET_TLV_NUM_PEERS 35
|
||||
#define TARGET_TLV_NUM_TDLS_VDEVS 1
|
||||
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
|
||||
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
|
||||
#define TARGET_TLV_NUM_WOW_PATTERNS 22
|
||||
|
||||
/* Number of Copy Engines supported */
|
||||
#define CE_COUNT 8
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,11 +23,22 @@
|
||||
|
||||
#define WEP_KEYID_SHIFT 6
|
||||
|
||||
enum wmi_tlv_tx_pause_id;
|
||||
enum wmi_tlv_tx_pause_action;
|
||||
|
||||
struct ath10k_generic_iter {
|
||||
struct ath10k *ar;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct rfc1042_hdr {
|
||||
u8 llc_dsap;
|
||||
u8 llc_ssap;
|
||||
u8 llc_ctrl;
|
||||
u8 snap_oui[3];
|
||||
__be16 snap_type;
|
||||
} __packed;
|
||||
|
||||
struct ath10k *ath10k_mac_create(size_t priv_size);
|
||||
void ath10k_mac_destroy(struct ath10k *ar);
|
||||
int ath10k_mac_register(struct ath10k *ar);
|
||||
@@ -45,6 +56,24 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
|
||||
void ath10k_drain_tx(struct ath10k *ar);
|
||||
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
|
||||
u8 keyidx);
|
||||
int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
|
||||
struct cfg80211_chan_def *def);
|
||||
|
||||
void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id);
|
||||
void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
|
||||
enum wmi_tlv_tx_pause_id pause_id,
|
||||
enum wmi_tlv_tx_pause_action action);
|
||||
|
||||
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
|
||||
u8 hw_rate);
|
||||
u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
|
||||
u32 bitrate);
|
||||
|
||||
void ath10k_mac_tx_lock(struct ath10k *ar, int reason);
|
||||
void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
|
||||
void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
|
||||
void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
|
||||
|
||||
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
|
||||
{
|
||||
|
||||
156
drivers/net/wireless/ath/ath10k/p2p.c
Normal file
156
drivers/net/wireless/ath/ath10k/p2p.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "wmi.h"
|
||||
#include "mac.h"
|
||||
#include "p2p.h"
|
||||
|
||||
static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ieee80211_p2p_noa_attr *noa_attr;
|
||||
u8 ctwindow_oppps = noa->ctwindow_oppps;
|
||||
u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
|
||||
bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
|
||||
__le16 *noa_attr_len;
|
||||
u16 attr_len;
|
||||
u8 noa_descriptors = noa->num_descriptors;
|
||||
int i;
|
||||
|
||||
/* P2P IE */
|
||||
data[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
data[1] = len - 2;
|
||||
data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
|
||||
data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
|
||||
data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
|
||||
data[5] = WLAN_OUI_TYPE_WFA_P2P;
|
||||
|
||||
/* NOA ATTR */
|
||||
data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
|
||||
noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
|
||||
noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
|
||||
|
||||
noa_attr->index = noa->index;
|
||||
noa_attr->oppps_ctwindow = ctwindow;
|
||||
if (oppps)
|
||||
noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
|
||||
|
||||
for (i = 0; i < noa_descriptors; i++) {
|
||||
noa_attr->desc[i].count =
|
||||
__le32_to_cpu(noa->descriptors[i].type_count);
|
||||
noa_attr->desc[i].duration = noa->descriptors[i].duration;
|
||||
noa_attr->desc[i].interval = noa->descriptors[i].interval;
|
||||
noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
|
||||
}
|
||||
|
||||
attr_len = 2; /* index + oppps_ctwindow */
|
||||
attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
|
||||
*noa_attr_len = __cpu_to_le16(attr_len);
|
||||
}
|
||||
|
||||
static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if (!noa->num_descriptors &&
|
||||
!(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))
|
||||
return 0;
|
||||
|
||||
len += 1 + 1 + 4; /* EID + len + OUI */
|
||||
len += 1 + 2; /* noa attr + attr len */
|
||||
len += 1 + 1; /* index + oppps_ctwindow */
|
||||
len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,
|
||||
size_t len)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
kfree(arvif->u.ap.noa_data);
|
||||
|
||||
arvif->u.ap.noa_data = ie;
|
||||
arvif->u.ap.noa_len = len;
|
||||
}
|
||||
|
||||
static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
void *ie;
|
||||
size_t len;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
ath10k_p2p_noa_ie_assign(arvif, NULL, 0);
|
||||
|
||||
len = ath10k_p2p_noa_ie_len_compute(noa);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
ie = kmalloc(len, GFP_ATOMIC);
|
||||
if (!ie)
|
||||
return;
|
||||
|
||||
ath10k_p2p_noa_ie_fill(ie, len, noa);
|
||||
ath10k_p2p_noa_ie_assign(arvif, ie, len);
|
||||
}
|
||||
|
||||
void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
__ath10k_p2p_noa_update(arvif, noa);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
struct ath10k_p2p_noa_arg {
|
||||
u32 vdev_id;
|
||||
const struct wmi_p2p_noa_info *noa;
|
||||
};
|
||||
|
||||
static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k_p2p_noa_arg *arg = data;
|
||||
|
||||
if (arvif->vdev_id != arg->vdev_id)
|
||||
return;
|
||||
|
||||
ath10k_p2p_noa_update(arvif, arg->noa);
|
||||
}
|
||||
|
||||
void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k_p2p_noa_arg arg = {
|
||||
.vdev_id = vdev_id,
|
||||
.noa = noa,
|
||||
};
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(ar->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_p2p_noa_update_vdev_iter,
|
||||
&arg);
|
||||
}
|
||||
28
drivers/net/wireless/ath/ath10k/p2p.h
Normal file
28
drivers/net/wireless/ath/ath10k/p2p.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _P2P_H
|
||||
#define _P2P_H
|
||||
|
||||
struct ath10k_vif;
|
||||
struct wmi_p2p_noa_info;
|
||||
|
||||
void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa);
|
||||
void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
|
||||
const struct wmi_p2p_noa_info *noa);
|
||||
|
||||
#endif
|
||||
@@ -113,7 +113,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 32,
|
||||
.dest_nentries = 128,
|
||||
},
|
||||
|
||||
/* CE3: host->target WMI */
|
||||
@@ -183,7 +183,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
{
|
||||
.pipenum = __cpu_to_le32(2),
|
||||
.pipedir = __cpu_to_le32(PIPEDIR_IN),
|
||||
.nentries = __cpu_to_le32(32),
|
||||
.nentries = __cpu_to_le32(64),
|
||||
.nbytes_max = __cpu_to_le32(2048),
|
||||
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
|
||||
.reserved = __cpu_to_le32(0),
|
||||
@@ -819,6 +819,21 @@ static int ath10k_pci_wake_wait(struct ath10k *ar)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* The rule is host is forbidden from accessing device registers while it's
|
||||
* asleep. Currently ath10k_pci_wake() and ath10k_pci_sleep() calls aren't
|
||||
* balanced and the device is kept awake all the time. This is intended for a
|
||||
* simpler solution for the following problems:
|
||||
*
|
||||
* * device can enter sleep during s2ram without the host knowing,
|
||||
*
|
||||
* * irq handlers access registers which is a problem if other device asserts
|
||||
* a shared irq line when ath10k is between hif_power_down() and
|
||||
* hif_power_up().
|
||||
*
|
||||
* FIXME: If power consumption is a concern (and there are *real* gains) then a
|
||||
* refcounted wake/sleep needs to be implemented.
|
||||
*/
|
||||
|
||||
static int ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
|
||||
@@ -1524,12 +1539,11 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
|
||||
switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
|
||||
case QCA6174_HW_1_0_CHIP_ID_REV:
|
||||
case QCA6174_HW_1_1_CHIP_ID_REV:
|
||||
case QCA6174_HW_2_1_CHIP_ID_REV:
|
||||
case QCA6174_HW_2_2_CHIP_ID_REV:
|
||||
return 3;
|
||||
case QCA6174_HW_1_3_CHIP_ID_REV:
|
||||
return 2;
|
||||
case QCA6174_HW_2_1_CHIP_ID_REV:
|
||||
case QCA6174_HW_2_2_CHIP_ID_REV:
|
||||
return 6;
|
||||
case QCA6174_HW_3_0_CHIP_ID_REV:
|
||||
case QCA6174_HW_3_1_CHIP_ID_REV:
|
||||
case QCA6174_HW_3_2_CHIP_ID_REV:
|
||||
@@ -2034,28 +2048,13 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
||||
/* Currently hif_power_up performs effectively a reset and hif_stop
|
||||
* resets the chip as well so there's no point in resetting here.
|
||||
*/
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#define ATH10K_PCI_PM_CONTROL 0x44
|
||||
|
||||
static int ath10k_pci_hif_suspend(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct pci_dev *pdev = ar_pci->pdev;
|
||||
u32 val;
|
||||
|
||||
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
|
||||
|
||||
if ((val & 0x000000ff) != 0x3) {
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
|
||||
(val & 0xffffff00) | 0x03);
|
||||
}
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2065,25 +2064,24 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct pci_dev *pdev = ar_pci->pdev;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
|
||||
|
||||
if ((val & 0x000000ff) != 0) {
|
||||
pci_restore_state(pdev);
|
||||
pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
|
||||
val & 0xffffff00);
|
||||
/*
|
||||
* Suspend/Resume resets the PCI configuration space,
|
||||
* so we have to re-disable the RETRY_TIMEOUT register (0x41)
|
||||
* to keep PCI Tx retries from interfering with C3 CPU state
|
||||
*/
|
||||
pci_read_config_dword(pdev, 0x40, &val);
|
||||
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to wake device up on resume: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Suspend/Resume resets the PCI configuration space, so we have to
|
||||
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
|
||||
* from interfering with C3 CPU state. pci_restore_state won't help
|
||||
* here since it only restores the first 64 bytes pci config header.
|
||||
*/
|
||||
pci_read_config_dword(pdev, 0x40, &val);
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2177,6 +2175,13 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
||||
{
|
||||
struct ath10k *ar = arg;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (ar_pci->num_msi_intrs == 0) {
|
||||
if (!ath10k_pci_irq_pending(ar))
|
||||
@@ -2621,6 +2626,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
ar_pci->dev = &pdev->dev;
|
||||
ar_pci->ar = ar;
|
||||
|
||||
if (pdev->subsystem_vendor || pdev->subsystem_device)
|
||||
scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id),
|
||||
"%04x:%04x:%04x:%04x",
|
||||
pdev->vendor, pdev->device,
|
||||
pdev->subsystem_vendor, pdev->subsystem_device);
|
||||
|
||||
spin_lock_init(&ar_pci->ce_lock);
|
||||
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
|
||||
(unsigned long)ar);
|
||||
@@ -2678,11 +2689,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
|
||||
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
|
||||
pdev->device, chip_id);
|
||||
goto err_sleep;
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
ret = ath10k_core_register(ar, chip_id);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to register driver core: %d\n", ret);
|
||||
@@ -2770,7 +2779,19 @@ module_exit(ath10k_pci_exit);
|
||||
MODULE_AUTHOR("Qualcomm Atheros");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
/* QCA988x 2.0 firmware files */
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
|
||||
|
||||
/* QCA6174 2.1 firmware files */
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
|
||||
|
||||
/* QCA6174 3.1 firmware files */
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
|
||||
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
|
||||
|
||||
@@ -661,6 +661,28 @@ struct rx_msdu_end {
|
||||
#define RX_PPDU_START_INFO5_SERVICE_MASK 0x0000ffff
|
||||
#define RX_PPDU_START_INFO5_SERVICE_LSB 0
|
||||
|
||||
/* No idea what this flag means. It seems to be always set in rate. */
|
||||
#define RX_PPDU_START_RATE_FLAG BIT(3)
|
||||
|
||||
enum rx_ppdu_start_rate {
|
||||
RX_PPDU_START_RATE_OFDM_48M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_48M,
|
||||
RX_PPDU_START_RATE_OFDM_24M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_24M,
|
||||
RX_PPDU_START_RATE_OFDM_12M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_12M,
|
||||
RX_PPDU_START_RATE_OFDM_6M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_6M,
|
||||
RX_PPDU_START_RATE_OFDM_54M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_54M,
|
||||
RX_PPDU_START_RATE_OFDM_36M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_36M,
|
||||
RX_PPDU_START_RATE_OFDM_18M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_18M,
|
||||
RX_PPDU_START_RATE_OFDM_9M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_9M,
|
||||
|
||||
RX_PPDU_START_RATE_CCK_LP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_11M,
|
||||
RX_PPDU_START_RATE_CCK_LP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_5_5M,
|
||||
RX_PPDU_START_RATE_CCK_LP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_2M,
|
||||
RX_PPDU_START_RATE_CCK_LP_1M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_1M,
|
||||
RX_PPDU_START_RATE_CCK_SP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_11M,
|
||||
RX_PPDU_START_RATE_CCK_SP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_5_5M,
|
||||
RX_PPDU_START_RATE_CCK_SP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_2M,
|
||||
};
|
||||
|
||||
struct rx_ppdu_start {
|
||||
struct {
|
||||
u8 pri20_mhz;
|
||||
|
||||
@@ -23,102 +23,50 @@
|
||||
#include "debug.h"
|
||||
#include "wmi-ops.h"
|
||||
|
||||
static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
|
||||
enum wmi_vdev_type type)
|
||||
static int
|
||||
ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int count = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
if (!arvif->is_started)
|
||||
continue;
|
||||
|
||||
if (!arvif->is_up)
|
||||
continue;
|
||||
|
||||
if (arvif->vdev_type != type)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
*state = ATH10K_QUIET_DUTY_CYCLE_MAX;
|
||||
*state = ATH10K_THERMAL_THROTTLE_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
static int
|
||||
ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct ath10k *ar = cdev->devdata;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
*state = ar->thermal.duty_cycle;
|
||||
*state = ar->thermal.throttle_state;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
|
||||
unsigned long duty_cycle)
|
||||
static int
|
||||
ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long throttle_state)
|
||||
{
|
||||
struct ath10k *ar = cdev->devdata;
|
||||
u32 period, duration, enabled;
|
||||
int num_bss, ret = 0;
|
||||
|
||||
if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
|
||||
ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
|
||||
throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) {
|
||||
ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n",
|
||||
duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* TODO: Right now, thermal mitigation is handled only for single/multi
|
||||
* vif AP mode. Since quiet param is not validated in STA mode, it needs
|
||||
* to be investigated further to handle multi STA and multi-vif (AP+STA)
|
||||
* mode properly.
|
||||
*/
|
||||
num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP);
|
||||
if (!num_bss) {
|
||||
ath10k_warn(ar, "no active AP interfaces\n");
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
period = max(ATH10K_QUIET_PERIOD_MIN,
|
||||
(ATH10K_QUIET_PERIOD_DEFAULT / num_bss));
|
||||
duration = (period * duty_cycle) / 100;
|
||||
enabled = duration ? 1 : 0;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
|
||||
ATH10K_QUIET_START_OFFSET,
|
||||
enabled);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
|
||||
period, duration, enabled, ret);
|
||||
goto out;
|
||||
}
|
||||
ar->thermal.duty_cycle = duty_cycle;
|
||||
out:
|
||||
ar->thermal.throttle_state = throttle_state;
|
||||
ath10k_thermal_set_throttling(ar);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops ath10k_thermal_ops = {
|
||||
.get_max_state = ath10k_thermal_get_max_dutycycle,
|
||||
.get_cur_state = ath10k_thermal_get_cur_dutycycle,
|
||||
.set_cur_state = ath10k_thermal_set_cur_dutycycle,
|
||||
.get_max_state = ath10k_thermal_get_max_throttle_state,
|
||||
.get_cur_state = ath10k_thermal_get_cur_throttle_state,
|
||||
.set_cur_state = ath10k_thermal_set_cur_throttle_state,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_thermal_show_temp(struct device *dev,
|
||||
@@ -127,6 +75,7 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
|
||||
{
|
||||
struct ath10k *ar = dev_get_drvdata(dev);
|
||||
int ret, temperature;
|
||||
unsigned long time_left;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
@@ -148,9 +97,9 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
|
||||
ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
|
||||
if (ret == 0) {
|
||||
time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
|
||||
ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
ath10k_warn(ar, "failed to synchronize thermal read\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
@@ -184,6 +133,32 @@ static struct attribute *ath10k_hwmon_attrs[] = {
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ath10k_hwmon);
|
||||
|
||||
void ath10k_thermal_set_throttling(struct ath10k *ar)
|
||||
{
|
||||
u32 period, duration, enabled;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
|
||||
return;
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON)
|
||||
return;
|
||||
|
||||
period = ar->thermal.quiet_period;
|
||||
duration = (period * ar->thermal.throttle_state) / 100;
|
||||
enabled = duration ? 1 : 0;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
|
||||
ATH10K_QUIET_START_OFFSET,
|
||||
enabled);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
|
||||
period, duration, enabled, ret);
|
||||
}
|
||||
}
|
||||
|
||||
int ath10k_thermal_register(struct ath10k *ar)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
@@ -202,11 +177,12 @@ int ath10k_thermal_register(struct ath10k *ar)
|
||||
ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
|
||||
"cooling_device");
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to create thermal symlink\n");
|
||||
ath10k_err(ar, "failed to create cooling device symlink\n");
|
||||
goto err_cooling_destroy;
|
||||
}
|
||||
|
||||
ar->thermal.cdev = cdev;
|
||||
ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
|
||||
|
||||
/* Do not register hwmon device when temperature reading is not
|
||||
* supported by firmware
|
||||
@@ -231,7 +207,7 @@ int ath10k_thermal_register(struct ath10k *ar)
|
||||
return 0;
|
||||
|
||||
err_remove_link:
|
||||
sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
|
||||
sysfs_remove_link(&ar->dev->kobj, "cooling_device");
|
||||
err_cooling_destroy:
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
return ret;
|
||||
|
||||
@@ -19,16 +19,17 @@
|
||||
#define ATH10K_QUIET_PERIOD_DEFAULT 100
|
||||
#define ATH10K_QUIET_PERIOD_MIN 25
|
||||
#define ATH10K_QUIET_START_OFFSET 10
|
||||
#define ATH10K_QUIET_DUTY_CYCLE_MAX 70
|
||||
#define ATH10K_HWMON_NAME_LEN 15
|
||||
#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
|
||||
#define ATH10K_THERMAL_THROTTLE_MAX 100
|
||||
|
||||
struct ath10k_thermal {
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct completion wmi_sync;
|
||||
|
||||
/* protected by conf_mutex */
|
||||
u32 duty_cycle;
|
||||
u32 throttle_state;
|
||||
u32 quiet_period;
|
||||
/* temperature value in Celcius degree
|
||||
* protected by data_lock
|
||||
*/
|
||||
@@ -39,6 +40,7 @@ struct ath10k_thermal {
|
||||
int ath10k_thermal_register(struct ath10k *ar);
|
||||
void ath10k_thermal_unregister(struct ath10k *ar);
|
||||
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
|
||||
void ath10k_thermal_set_throttling(struct ath10k *ar);
|
||||
#else
|
||||
static inline int ath10k_thermal_register(struct ath10k *ar)
|
||||
{
|
||||
@@ -54,5 +56,9 @@ static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_thermal_set_throttling(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* _THERMAL_ */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user