Commit 350b193e authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from ath.git

Major changes in ath10k:

* Device tree support

* Major restructuring how to handle different WMI interface versions

* Add WMI TLV interface in preparation for new firmware interface support

* Support new firmware branch 10.2.4

* Add thermal cooling interface

* Add hwmon interface to read temparture from the device

And of course lots of small fixes and cleanups.
parents ed0fb7eb 96bba983
* Qualcomm Atheros ath10k wireless devices
For ath10k devices the calibration data can be provided through Device
Tree. The node is a child node of the PCI controller.
Required properties:
-compatible : Should be "qcom,ath10k"
Optional properties:
- qcom,ath10k-calibration-data : calibration data as an array, the
length can vary between hw versions
Example:
pci {
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ath10k@0,0 {
reg = <0 0 0 0 0>;
device_type = "pci";
qcom,ath10k-calibration-data = [ 01 02 03 ... ];
};
};
};
...@@ -8,11 +8,13 @@ ath10k_core-y += mac.o \ ...@@ -8,11 +8,13 @@ ath10k_core-y += mac.o \
htt_tx.o \ htt_tx.o \
txrx.o \ txrx.o \
wmi.o \ wmi.o \
wmi-tlv.o \
bmi.o bmi.o
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
ath10k_core-$(CONFIG_THERMAL) += thermal.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \ ath10k_pci-y += pci.o \
......
...@@ -1093,6 +1093,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ...@@ -1093,6 +1093,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
ce_state->ar = ar; ce_state->ar = ar;
ce_state->id = ce_id; ce_state->id = ce_id;
......
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "../regd.h" #include "../regd.h"
#include "../dfs_pattern_detector.h" #include "../dfs_pattern_detector.h"
#include "spectral.h" #include "spectral.h"
#include "thermal.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
...@@ -120,6 +121,7 @@ struct ath10k_mem_chunk { ...@@ -120,6 +121,7 @@ struct ath10k_mem_chunk {
}; };
struct ath10k_wmi { struct ath10k_wmi {
enum ath10k_fw_wmi_op_version op_version;
enum ath10k_htc_ep_id eid; enum ath10k_htc_ep_id eid;
struct completion service_ready; struct completion service_ready;
struct completion unified_ready; struct completion unified_ready;
...@@ -128,6 +130,7 @@ struct ath10k_wmi { ...@@ -128,6 +130,7 @@ struct ath10k_wmi {
struct wmi_cmd_map *cmd; struct wmi_cmd_map *cmd;
struct wmi_vdev_param_map *vdev_param; struct wmi_vdev_param_map *vdev_param;
struct wmi_pdev_param_map *pdev_param; struct wmi_pdev_param_map *pdev_param;
const struct wmi_ops *ops;
u32 num_mem_chunks; u32 num_mem_chunks;
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
...@@ -325,6 +328,7 @@ struct ath10k_debug { ...@@ -325,6 +328,7 @@ struct ath10k_debug {
u32 fw_dbglog_mask; u32 fw_dbglog_mask;
u32 pktlog_filter; u32 pktlog_filter;
u32 reg_addr; u32 reg_addr;
u32 nf_cal_period;
u8 htt_max_amsdu; u8 htt_max_amsdu;
u8 htt_max_ampdu; u8 htt_max_ampdu;
...@@ -369,7 +373,7 @@ enum ath10k_fw_features { ...@@ -369,7 +373,7 @@ enum ath10k_fw_features {
/* wmi_mgmt_rx_hdr contains extra RSSI information */ /* wmi_mgmt_rx_hdr contains extra RSSI information */
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
/* firmware from 10X branch */ /* Firmware from 10X branch. Deprecated, don't use in new code. */
ATH10K_FW_FEATURE_WMI_10X = 1, ATH10K_FW_FEATURE_WMI_10X = 1,
/* firmware support tx frame management over WMI, otherwise it's HTT */ /* firmware support tx frame management over WMI, otherwise it's HTT */
...@@ -378,8 +382,9 @@ enum ath10k_fw_features { ...@@ -378,8 +382,9 @@ enum ath10k_fw_features {
/* Firmware does not support P2P */ /* Firmware does not support P2P */
ATH10K_FW_FEATURE_NO_P2P = 3, ATH10K_FW_FEATURE_NO_P2P = 3,
/* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature
* is required to be set as well. * bit is required to be set as well. Deprecated, don't use in new
* code.
*/ */
ATH10K_FW_FEATURE_WMI_10_2 = 4, ATH10K_FW_FEATURE_WMI_10_2 = 4,
...@@ -401,6 +406,7 @@ enum ath10k_dev_flags { ...@@ -401,6 +406,7 @@ enum ath10k_dev_flags {
enum ath10k_cal_mode { enum ath10k_cal_mode {
ATH10K_CAL_MODE_FILE, ATH10K_CAL_MODE_FILE,
ATH10K_CAL_MODE_OTP, ATH10K_CAL_MODE_OTP,
ATH10K_CAL_MODE_DT,
}; };
static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
...@@ -410,6 +416,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) ...@@ -410,6 +416,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
return "file"; return "file";
case ATH10K_CAL_MODE_OTP: case ATH10K_CAL_MODE_OTP:
return "otp"; return "otp";
case ATH10K_CAL_MODE_DT:
return "dt";
} }
return "unknown"; return "unknown";
...@@ -480,12 +488,15 @@ struct ath10k { ...@@ -480,12 +488,15 @@ struct ath10k {
u32 id; u32 id;
const char *name; const char *name;
u32 patch_load_addr; u32 patch_load_addr;
int uart_pin;
struct ath10k_hw_params_fw { struct ath10k_hw_params_fw {
const char *dir; const char *dir;
const char *fw; const char *fw;
const char *otp; const char *otp;
const char *board; const char *board;
size_t board_size;
size_t board_ext_size;
} fw; } fw;
} hw_params; } hw_params;
...@@ -571,6 +582,7 @@ struct ath10k { ...@@ -571,6 +582,7 @@ struct ath10k {
int max_num_peers; int max_num_peers;
int max_num_stations; int max_num_stations;
int max_num_vdevs;
struct work_struct offchan_tx_work; struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue; struct sk_buff_head offchan_tx_queue;
...@@ -610,6 +622,7 @@ struct ath10k { ...@@ -610,6 +622,7 @@ struct ath10k {
/* protected by conf_mutex */ /* protected by conf_mutex */
const struct firmware *utf; const struct firmware *utf;
DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT); DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
enum ath10k_fw_wmi_op_version orig_wmi_op_version;
/* protected by data_lock */ /* protected by data_lock */
bool utf_monitor; bool utf_monitor;
...@@ -622,6 +635,8 @@ struct ath10k { ...@@ -622,6 +635,8 @@ struct ath10k {
u32 fw_cold_reset_counter; u32 fw_cold_reset_counter;
} stats; } stats;
struct ath10k_thermal thermal;
/* must be last */ /* must be last */
u8 drv_priv[0] __aligned(sizeof(void *)); u8 drv_priv[0] __aligned(sizeof(void *));
}; };
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "core.h" #include "core.h"
#include "debug.h" #include "debug.h"
#include "hif.h" #include "hif.h"
#include "wmi-ops.h"
/* ms */ /* ms */
#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
...@@ -123,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info); ...@@ -123,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar) 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.%d.%d.%d cal %s max_sta %d\n", ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
ar->hw_params.name, ar->hw_params.name,
ar->target_version, ar->target_version,
ar->chip_id, ar->chip_id,
...@@ -131,10 +132,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ...@@ -131,10 +132,7 @@ void ath10k_print_driver_info(struct ath10k *ar)
ar->fw_api, ar->fw_api,
ar->htt.target_version_major, ar->htt.target_version_major,
ar->htt.target_version_minor, ar->htt.target_version_minor,
ar->fw_version_major, ar->wmi.op_version,
ar->fw_version_minor,
ar->fw_version_release,
ar->fw_version_build,
ath10k_cal_mode_str(ar->cal_mode), ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations); ar->max_num_stations);
ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
...@@ -1607,6 +1605,73 @@ static const struct file_operations fops_cal_data = { ...@@ -1607,6 +1605,73 @@ static const struct file_operations fops_cal_data = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t ath10k_read_nf_cal_period(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
unsigned int len;
char buf[32];
len = scnprintf(buf, sizeof(buf), "%d\n",
ar->debug.nf_cal_period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath10k_write_nf_cal_period(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
unsigned long period;
int ret;
ret = kstrtoul_from_user(user_buf, count, 0, &period);
if (ret)
return ret;
if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)
return -EINVAL;
/* there's no way to switch back to the firmware default */
if (period == 0)
return -EINVAL;
mutex_lock(&ar->conf_mutex);
ar->debug.nf_cal_period = period;
if (ar->state != ATH10K_STATE_ON) {
/* firmware is not running, nothing else to do */
ret = count;
goto exit;
}
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,
ar->debug.nf_cal_period);
if (ret) {
ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",
ret);
goto exit;
}
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_nf_cal_period = {
.read = ath10k_read_nf_cal_period,
.write = ath10k_write_nf_cal_period,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_start(struct ath10k *ar) int ath10k_debug_start(struct ath10k *ar)
{ {
int ret; int ret;
...@@ -1642,6 +1707,16 @@ int ath10k_debug_start(struct ath10k *ar) ...@@ -1642,6 +1707,16 @@ int ath10k_debug_start(struct ath10k *ar)
ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
} }
if (ar->debug.nf_cal_period) {
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->cal_period,
ar->debug.nf_cal_period);
if (ret)
/* not serious */
ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",
ret);
}
return ret; return ret;
} }
...@@ -1880,6 +1955,9 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -1880,6 +1955,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data); ar, &fops_cal_data);
debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
debugfs_create_file("dfs_simulate_radar", S_IWUSR, debugfs_create_file("dfs_simulate_radar", S_IWUSR,
ar->debug.debugfs_phy, ar, ar->debug.debugfs_phy, ar,
......
...@@ -93,11 +93,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) ...@@ -93,11 +93,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
spin_lock_init(&htt->tx_lock); spin_lock_init(&htt->tx_lock);
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features))
htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
else
htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
htt->max_num_pending_tx); htt->max_num_pending_tx);
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API2_FILE "firmware-2.bin"
#define ATH10K_FW_API3_FILE "firmware-3.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin"
/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
#define ATH10K_FW_API4_FILE "firmware-4.bin"
#define ATH10K_FW_UTF_FILE "utf.bin" #define ATH10K_FW_UTF_FILE "utf.bin"
/* includes also the null byte */ /* includes also the null byte */
...@@ -58,6 +61,24 @@ enum ath10k_fw_ie_type { ...@@ -58,6 +61,24 @@ enum ath10k_fw_ie_type {
ATH10K_FW_IE_FEATURES = 2, ATH10K_FW_IE_FEATURES = 2,
ATH10K_FW_IE_FW_IMAGE = 3, ATH10K_FW_IE_FW_IMAGE = 3,
ATH10K_FW_IE_OTP_IMAGE = 4, ATH10K_FW_IE_OTP_IMAGE = 4,
/* WMI "operations" interface version, 32 bit value. Supported from
* FW API 4 and above.
*/
ATH10K_FW_IE_WMI_OP_VERSION = 5,
};
enum ath10k_fw_wmi_op_version {
ATH10K_FW_WMI_OP_VERSION_UNSET = 0,
ATH10K_FW_WMI_OP_VERSION_MAIN = 1,
ATH10K_FW_WMI_OP_VERSION_10_1 = 2,
ATH10K_FW_WMI_OP_VERSION_10_2 = 3,
ATH10K_FW_WMI_OP_VERSION_TLV = 4,
ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5,
/* keep last */
ATH10K_FW_WMI_OP_VERSION_MAX,
}; };
/* Known pecularities: /* Known pecularities:
...@@ -162,6 +183,15 @@ struct ath10k_pktlog_hdr { ...@@ -162,6 +183,15 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_NUM_MSDU_DESC (1024 + 400) #define TARGET_10X_NUM_MSDU_DESC (1024 + 400)
#define TARGET_10X_MAX_FRAG_ENTRIES 0 #define TARGET_10X_MAX_FRAG_ENTRIES 0
/* Target specific defines for WMI-TLV firmware */
#define TARGET_TLV_NUM_VDEVS 3
#define TARGET_TLV_NUM_STATIONS 32
#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
(TARGET_TLV_NUM_VDEVS) + \
2)
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
/* Number of Copy Engines supported */ /* Number of Copy Engines supported */
#define CE_COUNT 8 #define CE_COUNT 8
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "htt.h" #include "htt.h"
#include "txrx.h" #include "txrx.h"
#include "testmode.h" #include "testmode.h"
#include "wmi.h"
#include "wmi-ops.h"
/**********/ /**********/
/* Crypto */ /* Crypto */
...@@ -267,7 +269,10 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) ...@@ -267,7 +269,10 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef)
case IEEE80211_BAND_2GHZ: case IEEE80211_BAND_2GHZ:
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
phymode = MODE_11G; if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM)
phymode = MODE_11B;
else
phymode = MODE_11G;
break; break;
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
phymode = MODE_11NG_HT20; phymode = MODE_11NG_HT20;
...@@ -1046,28 +1051,85 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ...@@ -1046,28 +1051,85 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
arvif->vdev_id, ret); arvif->vdev_id, ret);
} }
/* static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif)
* Review this when mac80211 gains per-interface powersave support. {
*/ struct ath10k *ar = arvif->ar;
u32 param;
u32 value;
int ret;
lockdep_assert_held(&arvif->ar->conf_mutex);
if (arvif->u.sta.uapsd)
value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
else
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value);
if (ret) {
ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n",
value, arvif->vdev_id, ret);
return ret;
}
return 0;
}
static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
u32 param;
u32 value;
int ret;
lockdep_assert_held(&arvif->ar->conf_mutex);
if (arvif->u.sta.uapsd)
value = WMI_STA_PS_PSPOLL_COUNT_UAPSD;
else
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n",
value, arvif->vdev_id, ret);
return ret;
}
return 0;
}
static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_conf *conf = &ar->hw->conf; struct ieee80211_conf *conf = &ar->hw->conf;
enum wmi_sta_powersave_param param; enum wmi_sta_powersave_param param;
enum wmi_sta_ps_mode psmode; enum wmi_sta_ps_mode psmode;
int ret; int ret;
int ps_timeout;
lockdep_assert_held(&arvif->ar->conf_mutex); lockdep_assert_held(&arvif->ar->conf_mutex);
if (arvif->vif->type != NL80211_IFTYPE_STATION) if (arvif->vif->type != NL80211_IFTYPE_STATION)
return 0; return 0;
if (conf->flags & IEEE80211_CONF_PS) { if (vif->bss_conf.ps) {
psmode = WMI_STA_PS_MODE_ENABLED; psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME; param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
ps_timeout = conf->dynamic_ps_timeout;
if (ps_timeout == 0) {
/* Firmware doesn't like 0 */
ps_timeout = ieee80211_tu_to_usec(
vif->bss_conf.beacon_int) / 1000;
}
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
conf->dynamic_ps_timeout); ps_timeout);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
...@@ -1409,9 +1471,22 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, ...@@ -1409,9 +1471,22 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
if (vif->bss_conf.qos) if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS; arg->peer_flags |= WMI_PEER_QOS;
break; break;
case WMI_VDEV_TYPE_IBSS:
if (sta->wme)
arg->peer_flags |= WMI_PEER_QOS;
break;
default: default:
break; break;
} }
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
}
static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta)
{
/* First 4 rates in ath10k_rates are CCK (11b) rates. */
return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4;
} }
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
...@@ -1428,8 +1503,10 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, ...@@ -1428,8 +1503,10 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
phymode = MODE_11NG_HT40; phymode = MODE_11NG_HT40;
else else
phymode = MODE_11NG_HT20; phymode = MODE_11NG_HT20;
} else { } else if (ath10k_mac_sta_has_11g_rates(sta)) {
phymode = MODE_11G; phymode = MODE_11G;
} else {
phymode = MODE_11B;
} }
break; break;
...@@ -2894,10 +2971,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ...@@ -2894,10 +2971,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vdev_id = bit; arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
if (ar->p2p)
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
arvif->vdev_type = WMI_VDEV_TYPE_STA;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
break;
case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
arvif->vdev_type = WMI_VDEV_TYPE_STA; arvif->vdev_type = WMI_VDEV_TYPE_STA;
...@@ -3026,22 +3104,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ...@@ -3026,22 +3104,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_peer_delete; goto err_peer_delete;
} }
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n", ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
goto err_peer_delete; goto err_peer_delete;
} }
param = WMI_STA_PS_PARAM_PSPOLL_COUNT; ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n", ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
goto err_peer_delete; goto err_peer_delete;
} }
...@@ -3314,6 +3386,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -3314,6 +3386,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
} }
if (changed & BSS_CHANGED_PS) {
ret = ath10k_mac_vif_setup_ps(arvif);
if (ret)
ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
arvif->vdev_id, ret);
}
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
...@@ -3583,8 +3662,9 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) ...@@ -3583,8 +3662,9 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
sta->addr, smps, err); sta->addr, smps, err);
} }
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", changed & IEEE80211_RC_NSS_CHANGED) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
sta->addr); sta->addr);
err = ath10k_station_assoc(ar, arvif->vif, sta, true); err = ath10k_station_assoc(ar, arvif->vif, sta, true);
...@@ -3808,6 +3888,20 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, ...@@ -3808,6 +3888,20 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
if (ret) if (ret)
ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
if (ret) {
ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
if (ret) {
ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
exit: exit:
return ret; return ret;
} }
...@@ -3989,29 +4083,6 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ...@@ -3989,29 +4083,6 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret; return ret;
} }
static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif;
int ret = 0;
mutex_lock(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
arvif->vdev_id, value);
ret = ath10k_mac_set_frag(arvif, value);
if (ret) {
ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
break;
}
}
mutex_unlock(&ar->conf_mutex);
return ret;
}
static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop) u32 queues, bool drop)
{ {
...@@ -4655,7 +4726,6 @@ static const struct ieee80211_ops ath10k_ops = { ...@@ -4655,7 +4726,6 @@ static const struct ieee80211_ops ath10k_ops = {
.remain_on_channel = ath10k_remain_on_channel, .remain_on_channel = ath10k_remain_on_channel,
.cancel_remain_on_channel = ath10k_cancel_remain_on_channel, .cancel_remain_on_channel = ath10k_cancel_remain_on_channel,
.set_rts_threshold = ath10k_set_rts_threshold, .set_rts_threshold = ath10k_set_rts_threshold,
.set_frag_threshold = ath10k_set_frag_threshold,
.flush = ath10k_flush, .flush = ath10k_flush,
.tx_last_beacon = ath10k_tx_last_beacon, .tx_last_beacon = ath10k_tx_last_beacon,
.set_antenna = ath10k_set_antenna, .set_antenna = ath10k_set_antenna,
...@@ -4746,6 +4816,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = { ...@@ -4746,6 +4816,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(165, 5825, 0), CHAN5G(165, 5825, 0),
}; };
/* Note: Be careful if you re-order these. There is code which depends on this
* ordering.
*/
static struct ieee80211_rate ath10k_rates[] = { static struct ieee80211_rate ath10k_rates[] = {
/* CCK */ /* CCK */
RATETAB_ENT(10, 0x82, 0), RATETAB_ENT(10, 0x82, 0),
...@@ -4799,6 +4872,10 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { ...@@ -4799,6 +4872,10 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
.types = BIT(NL80211_IFTYPE_P2P_GO) .types = BIT(NL80211_IFTYPE_P2P_GO)
}, },
{ {
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
},
{
.max = 7, .max = 7,
.types = BIT(NL80211_IFTYPE_AP) .types = BIT(NL80211_IFTYPE_AP)
}, },
...@@ -5018,6 +5095,7 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -5018,6 +5095,7 @@ int ath10k_mac_register(struct ath10k *ar)
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
ar->hw->wiphy->interface_modes |= ar->hw->wiphy->interface_modes |=
BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO); BIT(NL80211_IFTYPE_P2P_GO);
...@@ -5062,16 +5140,26 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -5062,16 +5140,26 @@ int ath10k_mac_register(struct ath10k *ar)
*/ */
ar->hw->queues = 4; ar->hw->queues = 4;
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { switch (ar->wmi.op_version) {
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; case ATH10K_FW_WMI_OP_VERSION_MAIN:
ar->hw->wiphy->n_iface_combinations = case ATH10K_FW_WMI_OP_VERSION_TLV:
ARRAY_SIZE(ath10k_10x_if_comb);
} else {
ar->hw->wiphy->iface_combinations = ath10k_if_comb; ar->hw->wiphy->iface_combinations = ath10k_if_comb;
ar->hw->wiphy->n_iface_combinations = ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_if_comb); ARRAY_SIZE(ath10k_if_comb);
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
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->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_10x_if_comb);
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
WARN_ON(1);
ret = -EINVAL;
goto err_free;
} }
ar->hw->netdev_features = NETIF_F_HW_CSUM; ar->hw->netdev_features = NETIF_F_HW_CSUM;
......
...@@ -64,6 +64,14 @@ static const struct pci_device_id ath10k_pci_id_table[] = { ...@@ -64,6 +64,14 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
{0} {0}
}; };
static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
/* QCA988X pre 2.0 chips are not supported because they need some nasty
* hacks. ath10k doesn't have them and these devices crash horribly
* because of that.
*/
{ QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
};
static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
static int ath10k_pci_cold_reset(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar);
static int ath10k_pci_warm_reset(struct ath10k *ar); static int ath10k_pci_warm_reset(struct ath10k *ar);
...@@ -2476,6 +2484,23 @@ static void ath10k_pci_release(struct ath10k *ar) ...@@ -2476,6 +2484,23 @@ static void ath10k_pci_release(struct ath10k *ar)
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
{
const struct ath10k_pci_supp_chip *supp_chip;
int i;
u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV);
for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) {
supp_chip = &ath10k_pci_supp_chips[i];
if (supp_chip->dev_id == dev_id &&
supp_chip->rev_id == rev_id)
return true;
}
return false;
}
static int ath10k_pci_probe(struct pci_dev *pdev, static int ath10k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev) const struct pci_device_id *pci_dev)
{ {
...@@ -2521,6 +2546,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -2521,6 +2546,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_sleep; goto err_sleep;
} }
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;
}
ret = ath10k_pci_alloc_pipes(ar); ret = ath10k_pci_alloc_pipes(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
......
...@@ -152,6 +152,11 @@ struct ath10k_pci_pipe { ...@@ -152,6 +152,11 @@ struct ath10k_pci_pipe {
struct tasklet_struct intr; struct tasklet_struct intr;
}; };
struct ath10k_pci_supp_chip {
u32 dev_id;
u32 rev_id;
};
struct ath10k_pci { struct ath10k_pci {
struct pci_dev *pdev; struct pci_dev *pdev;
struct device *dev; struct device *dev;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/relay.h> #include <linux/relay.h>
#include "core.h" #include "core.h"
#include "debug.h" #include "debug.h"
#include "wmi-ops.h"
static void send_fft_sample(struct ath10k *ar, static void send_fft_sample(struct ath10k *ar,
const struct fft_sample_tlv *fft_sample_tlv) const struct fft_sample_tlv *fft_sample_tlv)
......
...@@ -187,13 +187,14 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -187,13 +187,14 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
memcpy(ar->testmode.orig_fw_features, ar->fw_features, memcpy(ar->testmode.orig_fw_features, ar->fw_features,
sizeof(ar->fw_features)); sizeof(ar->fw_features));
ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
/* utf.bin firmware image does not advertise firmware features. Do /* utf.bin firmware image does not advertise firmware features. Do
* an ugly hack where we force the firmware features so that wmi.c * an ugly hack where we force the firmware features so that wmi.c
* will use the correct WMI interface. * will use the correct WMI interface.
*/ */
memset(ar->fw_features, 0, sizeof(ar->fw_features)); memset(ar->fw_features, 0, sizeof(ar->fw_features));
__set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features); ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
ret = ath10k_hif_power_up(ar); ret = ath10k_hif_power_up(ar);
if (ret) { if (ret) {
...@@ -224,6 +225,7 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -224,6 +225,7 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
/* return the original firmware features */ /* return the original firmware features */
memcpy(ar->fw_features, ar->testmode.orig_fw_features, memcpy(ar->fw_features, ar->testmode.orig_fw_features,
sizeof(ar->fw_features)); sizeof(ar->fw_features));
ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf); release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL; ar->testmode.utf = NULL;
...@@ -250,6 +252,7 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) ...@@ -250,6 +252,7 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
/* return the original firmware features */ /* return the original firmware features */
memcpy(ar->fw_features, ar->testmode.orig_fw_features, memcpy(ar->fw_features, ar->testmode.orig_fw_features,
sizeof(ar->fw_features)); sizeof(ar->fw_features));
ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf); release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL; ar->testmode.utf = NULL;
......
/*
* Copyright (c) 2014 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 <linux/device.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include "core.h"
#include "debug.h"
#include "wmi-ops.h"
static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
enum wmi_vdev_type type)
{
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;
return 0;
}
static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct ath10k *ar = cdev->devdata;
mutex_lock(&ar->conf_mutex);
*state = ar->thermal.duty_cycle;
mutex_unlock(&ar->conf_mutex);
return 0;
}
static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
unsigned long duty_cycle)
{
struct ath10k *ar = cdev->devdata;
u32 period, duration, enabled;
int num_bss, ret = 0;
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:
mutex_unlock(&ar->conf_mutex);
return ret;
}
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,
};
static ssize_t ath10k_thermal_show_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ath10k *ar = dev_get_drvdata(dev);
int ret, temperature;
mutex_lock(&ar->conf_mutex);
/* Can't get temperature when the card is off */
if (ar->state != ATH10K_STATE_ON) {
ret = -ENETDOWN;
goto out;
}
reinit_completion(&ar->thermal.wmi_sync);
ret = ath10k_wmi_pdev_get_temperature(ar);
if (ret) {
ath10k_warn(ar, "failed to read temperature %d\n", ret);
goto out;
}
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
ret = -ESHUTDOWN;
goto out;
}
ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
if (ret == 0) {
ath10k_warn(ar, "failed to synchronize thermal read\n");
ret = -ETIMEDOUT;
goto out;
}
spin_lock_bh(&ar->data_lock);
temperature = ar->thermal.temperature;
spin_unlock_bh(&ar->data_lock);
ret = snprintf(buf, PAGE_SIZE, "%d", temperature);
out:
mutex_unlock(&ar->conf_mutex);
return ret;
}
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
{
spin_lock_bh(&ar->data_lock);
ar->thermal.temperature = temperature;
spin_unlock_bh(&ar->data_lock);
complete(&ar->thermal.wmi_sync);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp,
NULL, 0);
static struct attribute *ath10k_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(ath10k_hwmon);
int ath10k_thermal_register(struct ath10k *ar)
{
struct thermal_cooling_device *cdev;
struct device *hwmon_dev;
int ret;
cdev = thermal_cooling_device_register("ath10k_thermal", ar,
&ath10k_thermal_ops);
if (IS_ERR(cdev)) {
ath10k_err(ar, "failed to setup thermal device result: %ld\n",
PTR_ERR(cdev));
return -EINVAL;
}
ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
"cooling_device");
if (ret) {
ath10k_err(ar, "failed to create thermal symlink\n");
goto err_cooling_destroy;
}
ar->thermal.cdev = cdev;
/* Do not register hwmon device when temperature reading is not
* supported by firmware
*/
if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
return 0;
/* Avoid linking error on devm_hwmon_device_register_with_groups, I
* guess linux/hwmon.h is missing proper stubs. */
if (!config_enabled(HWMON))
return 0;
hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
"ath10k_hwmon", ar,
ath10k_hwmon_groups);
if (IS_ERR(hwmon_dev)) {
ath10k_err(ar, "failed to register hwmon device: %ld\n",
PTR_ERR(hwmon_dev));
ret = -EINVAL;
goto err_remove_link;
}
return 0;
err_remove_link:
sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
err_cooling_destroy:
thermal_cooling_device_unregister(cdev);
return ret;
}
void ath10k_thermal_unregister(struct ath10k *ar)
{
thermal_cooling_device_unregister(ar->thermal.cdev);
sysfs_remove_link(&ar->dev->kobj, "cooling_device");
}
/*
* Copyright (c) 2014 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 _THERMAL_
#define _THERMAL_
#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)
struct ath10k_thermal {
struct thermal_cooling_device *cdev;
struct completion wmi_sync;
/* protected by conf_mutex */
u32 duty_cycle;
/* temperature value in Celcius degree
* protected by data_lock
*/
int temperature;
};
#ifdef CONFIG_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);
#else
static inline int ath10k_thermal_register(struct ath10k *ar)
{
return 0;
}
static inline void ath10k_thermal_unregister(struct ath10k *ar)
{
}
static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
int temperature)
{
}
#endif
#endif /* _THERMAL_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment