提交 efd7cef3 编写于 作者: K Kalle Valo

Merge ath-next from ath.git

ath.git patches for 4.7. Major changes:

ath10k

* implement set_tsf() for 10.2.4 branch
* remove rare MSI range support
* remove deprecated firmware API 1 support

ath9k

* add module parameter to invert LED polarity

wcn36xx

* fixes to get the driver properly working on Dragonboard 410c
...@@ -1050,11 +1050,11 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, ...@@ -1050,11 +1050,11 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
* *
* For the lack of a better place do the check here. * For the lack of a better place do the check here.
*/ */
BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC >
(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 > BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
ce_state->ar = ar; ce_state->ar = ar;
......
...@@ -408,7 +408,7 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) ...@@ -408,7 +408,7 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */ /* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \ #define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
(((int)(toidx)-(int)(fromidx)) & (nentries_mask)) (((int)(toidx) - (int)(fromidx)) & (nentries_mask))
#define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask)) #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
#define CE_RING_IDX_ADD(nentries_mask, idx, num) \ #define CE_RING_IDX_ADD(nentries_mask, idx, num) \
......
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
#define ATH10K_SCAN_ID 0 #define ATH10K_SCAN_ID 0
#define WMI_READY_TIMEOUT (5 * HZ) #define WMI_READY_TIMEOUT (5 * HZ)
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ) #define ATH10K_FLUSH_TIMEOUT_HZ (5 * HZ)
#define ATH10K_CONNECTION_LOSS_HZ (3*HZ) #define ATH10K_CONNECTION_LOSS_HZ (3 * HZ)
#define ATH10K_NUM_CHANS 39 #define ATH10K_NUM_CHANS 39
/* Antenna noise floor */ /* Antenna noise floor */
...@@ -139,7 +139,6 @@ struct ath10k_mem_chunk { ...@@ -139,7 +139,6 @@ 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;
...@@ -334,7 +333,7 @@ struct ath10k_sta { ...@@ -334,7 +333,7 @@ struct ath10k_sta {
#endif #endif
}; };
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
enum ath10k_beacon_state { enum ath10k_beacon_state {
ATH10K_BEACON_SCHEDULED = 0, ATH10K_BEACON_SCHEDULED = 0,
...@@ -627,6 +626,34 @@ enum ath10k_tx_pause_reason { ...@@ -627,6 +626,34 @@ enum ath10k_tx_pause_reason {
ATH10K_TX_PAUSE_MAX, ATH10K_TX_PAUSE_MAX,
}; };
struct ath10k_fw_file {
const struct firmware *firmware;
char fw_version[ETHTOOL_FWVERS_LEN];
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
enum ath10k_fw_wmi_op_version wmi_op_version;
enum ath10k_fw_htt_op_version htt_op_version;
const void *firmware_data;
size_t firmware_len;
const void *otp_data;
size_t otp_len;
const void *codeswap_data;
size_t codeswap_len;
};
struct ath10k_fw_components {
const struct firmware *board;
const void *board_data;
size_t board_len;
struct ath10k_fw_file fw_file;
};
struct ath10k { struct ath10k {
struct ath_common ath_common; struct ath_common ath_common;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
...@@ -652,8 +679,6 @@ struct ath10k { ...@@ -652,8 +679,6 @@ struct ath10k {
/* protected by conf_mutex */ /* protected by conf_mutex */
bool ani_enabled; bool ani_enabled;
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
bool p2p; bool p2p;
struct { struct {
...@@ -708,32 +733,24 @@ struct ath10k { ...@@ -708,32 +733,24 @@ struct ath10k {
struct ath10k_hw_params_fw { struct ath10k_hw_params_fw {
const char *dir; const char *dir;
const char *fw;
const char *otp;
const char *board; const char *board;
size_t board_size; size_t board_size;
size_t board_ext_size; size_t board_ext_size;
} fw; } fw;
} hw_params; } hw_params;
const struct firmware *board; /* contains the firmware images used with ATH10K_FIRMWARE_MODE_NORMAL */
const void *board_data; struct ath10k_fw_components normal_mode_fw;
size_t board_len;
const struct firmware *otp;
const void *otp_data;
size_t otp_len;
const struct firmware *firmware; /* READ-ONLY images of the running firmware, which can be either
const void *firmware_data; * normal or UTF. Do not modify, release etc!
size_t firmware_len; */
const struct ath10k_fw_components *running_fw;
const struct firmware *pre_cal_file; const struct firmware *pre_cal_file;
const struct firmware *cal_file; const struct firmware *cal_file;
struct { struct {
const void *firmware_codeswap_data;
size_t firmware_codeswap_len;
struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info;
} swap; } swap;
...@@ -879,13 +896,8 @@ struct ath10k { ...@@ -879,13 +896,8 @@ struct ath10k {
struct { struct {
/* protected by conf_mutex */ /* protected by conf_mutex */
const struct firmware *utf; struct ath10k_fw_components utf_mode_fw;
char utf_version[32];
const void *utf_firmware_data;
size_t utf_firmware_len;
DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
enum ath10k_fw_wmi_op_version orig_wmi_op_version;
enum ath10k_fw_wmi_op_version op_version;
/* protected by data_lock */ /* protected by data_lock */
bool utf_monitor; bool utf_monitor;
} testmode; } testmode;
...@@ -921,8 +933,11 @@ void ath10k_core_destroy(struct ath10k *ar); ...@@ -921,8 +933,11 @@ void ath10k_core_destroy(struct ath10k *ar);
void ath10k_core_get_fw_features_str(struct ath10k *ar, void ath10k_core_get_fw_features_str(struct ath10k *ar,
char *buf, char *buf,
size_t max_len); size_t max_len);
int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
struct ath10k_fw_file *fw_file);
int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
const struct ath10k_fw_components *fw_components);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar); void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar, u32 chip_id); int ath10k_core_register(struct ath10k *ar, u32 chip_id);
......
...@@ -126,6 +126,7 @@ EXPORT_SYMBOL(ath10k_info); ...@@ -126,6 +126,7 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_debug_print_hwfw_info(struct ath10k *ar) void ath10k_debug_print_hwfw_info(struct ath10k *ar)
{ {
const struct firmware *firmware;
char fw_features[128] = {}; char fw_features[128] = {};
u32 crc = 0; u32 crc = 0;
...@@ -144,8 +145,9 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar) ...@@ -144,8 +145,9 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar)
config_enabled(CONFIG_ATH10K_DFS_CERTIFIED), config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
config_enabled(CONFIG_NL80211_TESTMODE)); config_enabled(CONFIG_NL80211_TESTMODE));
if (ar->firmware) firmware = ar->normal_mode_fw.fw_file.firmware;
crc = crc32_le(0, ar->firmware->data, ar->firmware->size); if (firmware)
crc = crc32_le(0, firmware->data, firmware->size);
ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n", ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
ar->hw->wiphy->fw_version, ar->hw->wiphy->fw_version,
...@@ -167,7 +169,8 @@ void ath10k_debug_print_board_info(struct ath10k *ar) ...@@ -167,7 +169,8 @@ void ath10k_debug_print_board_info(struct ath10k *ar)
ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x", ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",
ar->bd_api, ar->bd_api,
boardinfo, boardinfo,
crc32_le(0, ar->board->data, ar->board->size)); crc32_le(0, ar->normal_mode_fw.board->data,
ar->normal_mode_fw.board->size));
} }
void ath10k_debug_print_boot_info(struct ath10k *ar) void ath10k_debug_print_boot_info(struct ath10k *ar)
...@@ -175,8 +178,8 @@ void ath10k_debug_print_boot_info(struct ath10k *ar) ...@@ -175,8 +178,8 @@ void ath10k_debug_print_boot_info(struct ath10k *ar)
ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n", ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",
ar->htt.target_version_major, ar->htt.target_version_major,
ar->htt.target_version_minor, ar->htt.target_version_minor,
ar->wmi.op_version, ar->normal_mode_fw.fw_file.wmi_op_version,
ar->htt.op_version, ar->normal_mode_fw.fw_file.htt_op_version,
ath10k_cal_mode_str(ar->cal_mode), ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations, ar->max_num_stations,
test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
...@@ -2122,7 +2125,7 @@ static ssize_t ath10k_write_btcoex(struct file *file, ...@@ -2122,7 +2125,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
struct ath10k *ar = file->private_data; struct ath10k *ar = file->private_data;
char buf[32]; char buf[32];
size_t buf_size; size_t buf_size;
int ret = 0; int ret;
bool val; bool val;
buf_size = min(count, (sizeof(buf) - 1)); buf_size = min(count, (sizeof(buf) - 1));
...@@ -2142,8 +2145,10 @@ static ssize_t ath10k_write_btcoex(struct file *file, ...@@ -2142,8 +2145,10 @@ static ssize_t ath10k_write_btcoex(struct file *file,
goto exit; goto exit;
} }
if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) {
ret = count;
goto exit; goto exit;
}
if (val) if (val)
set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
...@@ -2189,7 +2194,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file, ...@@ -2189,7 +2194,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
struct ath10k *ar = file->private_data; struct ath10k *ar = file->private_data;
char buf[32]; char buf[32];
size_t buf_size; size_t buf_size;
int ret = 0; int ret;
bool val; bool val;
buf_size = min(count, (sizeof(buf) - 1)); buf_size = min(count, (sizeof(buf) - 1));
...@@ -2209,8 +2214,10 @@ static ssize_t ath10k_write_peer_stats(struct file *file, ...@@ -2209,8 +2214,10 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
goto exit; goto exit;
} }
if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) {
ret = count;
goto exit; goto exit;
}
if (val) if (val)
set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags); set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
...@@ -2266,23 +2273,28 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file, ...@@ -2266,23 +2273,28 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"firmware-N.bin\t\t%08x\n", "firmware-N.bin\t\t%08x\n",
crc32_le(0, ar->firmware->data, ar->firmware->size)); crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data,
ar->normal_mode_fw.fw_file.firmware->size));
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"athwlan\t\t\t%08x\n", "athwlan\t\t\t%08x\n",
crc32_le(0, ar->firmware_data, ar->firmware_len)); crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data,
ar->normal_mode_fw.fw_file.firmware_len));
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"otp\t\t\t%08x\n", "otp\t\t\t%08x\n",
crc32_le(0, ar->otp_data, ar->otp_len)); crc32_le(0, ar->normal_mode_fw.fw_file.otp_data,
ar->normal_mode_fw.fw_file.otp_len));
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"codeswap\t\t%08x\n", "codeswap\t\t%08x\n",
crc32_le(0, ar->swap.firmware_codeswap_data, crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data,
ar->swap.firmware_codeswap_len)); ar->normal_mode_fw.fw_file.codeswap_len));
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"board-N.bin\t\t%08x\n", "board-N.bin\t\t%08x\n",
crc32_le(0, ar->board->data, ar->board->size)); crc32_le(0, ar->normal_mode_fw.board->data,
ar->normal_mode_fw.board->size));
len += scnprintf(buf + len, buf_len - len, len += scnprintf(buf + len, buf_len - len,
"board\t\t\t%08x\n", "board\t\t\t%08x\n",
crc32_le(0, ar->board_data, ar->board_len)); crc32_le(0, ar->normal_mode_fw.board_data,
ar->normal_mode_fw.board_len));
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
......
...@@ -57,7 +57,7 @@ enum ath10k_dbg_aggr_mode { ...@@ -57,7 +57,7 @@ enum ath10k_dbg_aggr_mode {
}; };
/* FIXME: How to calculate the buffer size sanely? */ /* FIXME: How to calculate the buffer size sanely? */
#define ATH10K_FW_STATS_BUF_SIZE (1024*1024) #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
extern unsigned int ath10k_debug_mask; extern unsigned int ath10k_debug_mask;
......
...@@ -297,10 +297,10 @@ struct ath10k_htc_svc_conn_resp { ...@@ -297,10 +297,10 @@ struct ath10k_htc_svc_conn_resp {
#define ATH10K_NUM_CONTROL_TX_BUFFERS 2 #define ATH10K_NUM_CONTROL_TX_BUFFERS 2
#define ATH10K_HTC_MAX_LEN 4096 #define ATH10K_HTC_MAX_LEN 4096
#define ATH10K_HTC_MAX_CTRL_MSG_LEN 256 #define ATH10K_HTC_MAX_CTRL_MSG_LEN 256
#define ATH10K_HTC_WAIT_TIMEOUT_HZ (1*HZ) #define ATH10K_HTC_WAIT_TIMEOUT_HZ (1 * HZ)
#define ATH10K_HTC_CONTROL_BUFFER_SIZE (ATH10K_HTC_MAX_CTRL_MSG_LEN + \ #define ATH10K_HTC_CONTROL_BUFFER_SIZE (ATH10K_HTC_MAX_CTRL_MSG_LEN + \
sizeof(struct ath10k_htc_hdr)) sizeof(struct ath10k_htc_hdr))
#define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1*HZ) #define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1 * HZ)
struct ath10k_htc_ep { struct ath10k_htc_ep {
struct ath10k_htc *htc; struct ath10k_htc *htc;
......
...@@ -183,7 +183,7 @@ int ath10k_htt_init(struct ath10k *ar) ...@@ -183,7 +183,7 @@ int ath10k_htt_init(struct ath10k *ar)
8 + /* llc snap */ 8 + /* llc snap */
2; /* ip4 dscp or ip6 priority */ 2; /* ip4 dscp or ip6 priority */
switch (ar->htt.op_version) { switch (ar->running_fw->fw_file.htt_op_version) {
case ATH10K_FW_HTT_OP_VERSION_10_4: case ATH10K_FW_HTT_OP_VERSION_10_4:
ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types; ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types;
ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS; ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS;
...@@ -208,7 +208,7 @@ int ath10k_htt_init(struct ath10k *ar) ...@@ -208,7 +208,7 @@ int ath10k_htt_init(struct ath10k *ar)
return 0; return 0;
} }
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) #define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)
static int ath10k_htt_verify_version(struct ath10k_htt *htt) static int ath10k_htt_verify_version(struct ath10k_htt *htt)
{ {
......
...@@ -1475,10 +1475,10 @@ union htt_rx_pn_t { ...@@ -1475,10 +1475,10 @@ union htt_rx_pn_t {
u32 pn24; u32 pn24;
/* TKIP or CCMP: 48-bit PN */ /* TKIP or CCMP: 48-bit PN */
u_int64_t pn48; u64 pn48;
/* WAPI: 128-bit PN */ /* WAPI: 128-bit PN */
u_int64_t pn128[2]; u64 pn128[2];
}; };
struct htt_cmd { struct htt_cmd {
...@@ -1562,7 +1562,6 @@ struct ath10k_htt { ...@@ -1562,7 +1562,6 @@ struct ath10k_htt {
u8 target_version_major; u8 target_version_major;
u8 target_version_minor; u8 target_version_minor;
struct completion target_version_received; struct completion target_version_received;
enum ath10k_fw_htt_op_version op_version;
u8 max_num_amsdu; u8 max_num_amsdu;
u8 max_num_ampdu; u8 max_num_ampdu;
......
...@@ -966,7 +966,7 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar, ...@@ -966,7 +966,7 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
int len = ieee80211_hdrlen(hdr->frame_control); int len = ieee80211_hdrlen(hdr->frame_control);
if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
ar->fw_features)) ar->running_fw->fw_file.fw_features))
len = round_up(len, 4); len = round_up(len, 4);
return len; return len;
......
...@@ -267,7 +267,8 @@ static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt) ...@@ -267,7 +267,8 @@ static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt)
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
size_t size; size_t size;
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
ar->running_fw->fw_file.fw_features))
return; return;
size = sizeof(*htt->tx_q_state.vaddr); size = sizeof(*htt->tx_q_state.vaddr);
...@@ -282,7 +283,8 @@ static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt) ...@@ -282,7 +283,8 @@ static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt)
size_t size; size_t size;
int ret; int ret;
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
ar->running_fw->fw_file.fw_features))
return 0; return 0;
htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS; htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS;
...@@ -513,7 +515,8 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) ...@@ -513,7 +515,8 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
info |= SM(htt->tx_q_state.type, info |= SM(htt->tx_q_state.type,
HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE); HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE);
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features)) if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
ar->running_fw->fw_file.fw_features))
info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID; info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID;
cfg = &cmd->frag_desc_bank_cfg; cfg = &cmd->frag_desc_bank_cfg;
......
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
#define QCA988X_HW_2_0_VERSION 0x4100016c #define QCA988X_HW_2_0_VERSION 0x4100016c
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2 #define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
...@@ -76,14 +74,10 @@ enum qca9377_chip_id_rev { ...@@ -76,14 +74,10 @@ enum qca9377_chip_id_rev {
}; };
#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" #define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1"
#define QCA6174_HW_2_1_FW_FILE "firmware.bin"
#define QCA6174_HW_2_1_OTP_FILE "otp.bin"
#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin"
#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 #define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234
#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0" #define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0"
#define QCA6174_HW_3_0_FW_FILE "firmware.bin"
#define QCA6174_HW_3_0_OTP_FILE "otp.bin"
#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin"
#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234
...@@ -94,23 +88,17 @@ enum qca9377_chip_id_rev { ...@@ -94,23 +88,17 @@ enum qca9377_chip_id_rev {
#define QCA99X0_HW_2_0_DEV_VERSION 0x01000000 #define QCA99X0_HW_2_0_DEV_VERSION 0x01000000
#define QCA99X0_HW_2_0_CHIP_ID_REV 0x1 #define QCA99X0_HW_2_0_CHIP_ID_REV 0x1
#define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0" #define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0"
#define QCA99X0_HW_2_0_FW_FILE "firmware.bin"
#define QCA99X0_HW_2_0_OTP_FILE "otp.bin"
#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9377 1.0 definitions */ /* QCA9377 1.0 definitions */
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0" #define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_FW_FILE "firmware.bin"
#define QCA9377_HW_1_0_OTP_FILE "otp.bin"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234 #define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA4019 1.0 definitions */ /* QCA4019 1.0 definitions */
#define QCA4019_HW_1_0_DEV_VERSION 0x01000000 #define QCA4019_HW_1_0_DEV_VERSION 0x01000000
#define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0" #define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0"
#define QCA4019_HW_1_0_FW_FILE "firmware.bin"
#define QCA4019_HW_1_0_OTP_FILE "otp.bin"
#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234 #define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
......
...@@ -157,6 +157,26 @@ ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) ...@@ -157,6 +157,26 @@ ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
return 1; return 1;
} }
int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val)
{
enum wmi_host_platform_type platform_type;
int ret;
if (test_bit(WMI_SERVICE_TX_MODE_DYNAMIC, ar->wmi.svc_map))
platform_type = WMI_HOST_PLATFORM_LOW_PERF;
else
platform_type = WMI_HOST_PLATFORM_HIGH_PERF;
ret = ath10k_wmi_ext_resource_config(ar, platform_type, val);
if (ret && ret != -EOPNOTSUPP) {
ath10k_warn(ar, "failed to configure ext resource: %d\n", ret);
return ret;
}
return 0;
}
/**********/ /**********/
/* Crypto */ /* Crypto */
/**********/ /**********/
...@@ -449,10 +469,10 @@ static int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif, ...@@ -449,10 +469,10 @@ static int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(peer, &ar->peers, list) { list_for_each_entry(peer, &ar->peers, list) {
if (!memcmp(peer->addr, arvif->vif->addr, ETH_ALEN)) if (ether_addr_equal(peer->addr, arvif->vif->addr))
continue; continue;
if (!memcmp(peer->addr, arvif->bssid, ETH_ALEN)) if (ether_addr_equal(peer->addr, arvif->bssid))
continue; continue;
if (peer->keys[key->keyidx] == key) if (peer->keys[key->keyidx] == key)
...@@ -1752,7 +1772,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ...@@ -1752,7 +1772,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 && if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 &&
!test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
ar->fw_features)) { ar->running_fw->fw_file.fw_features)) {
ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
arvif->vdev_id); arvif->vdev_id);
enable_ps = false; enable_ps = false;
...@@ -2040,7 +2060,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, ...@@ -2040,7 +2060,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
} }
if (sta->mfp && if (sta->mfp &&
test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, ar->fw_features)) { test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT,
ar->running_fw->fw_file.fw_features)) {
arg->peer_flags |= ar->wmi.peer_flags->pmf; arg->peer_flags |= ar->wmi.peer_flags->pmf;
} }
} }
...@@ -3187,7 +3208,8 @@ ath10k_mac_tx_h_get_txmode(struct ath10k *ar, ...@@ -3187,7 +3208,8 @@ ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
*/ */
if (ar->htt.target_version_major < 3 && if (ar->htt.target_version_major < 3 &&
(ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) && (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features)) !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
ar->running_fw->fw_file.fw_features))
return ATH10K_HW_TXRX_MGMT; return ATH10K_HW_TXRX_MGMT;
/* Workaround: /* Workaround:
...@@ -3337,7 +3359,7 @@ bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar) ...@@ -3337,7 +3359,7 @@ bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
*/ */
return (ar->htt.target_version_major >= 3 && return (ar->htt.target_version_major >= 3 &&
ar->htt.target_version_minor >= 4 && ar->htt.target_version_minor >= 4 &&
ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_TLV); ar->running_fw->fw_file.htt_op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
} }
static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb) static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
...@@ -3374,7 +3396,7 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar, ...@@ -3374,7 +3396,7 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
return ATH10K_MAC_TX_HTT; return ATH10K_MAC_TX_HTT;
case ATH10K_HW_TXRX_MGMT: case ATH10K_HW_TXRX_MGMT:
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
ar->fw_features)) ar->running_fw->fw_file.fw_features))
return ATH10K_MAC_TX_WMI_MGMT; return ATH10K_MAC_TX_WMI_MGMT;
else if (ar->htt.target_version_major >= 3) else if (ar->htt.target_version_major >= 3)
return ATH10K_MAC_TX_HTT; return ATH10K_MAC_TX_HTT;
...@@ -3846,7 +3868,7 @@ static int ath10k_scan_stop(struct ath10k *ar) ...@@ -3846,7 +3868,7 @@ static int ath10k_scan_stop(struct ath10k *ar)
goto out; goto out;
} }
ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ); ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ);
if (ret == 0) { if (ret == 0) {
ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n"); ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
...@@ -3926,7 +3948,7 @@ static int ath10k_start_scan(struct ath10k *ar, ...@@ -3926,7 +3948,7 @@ static int ath10k_start_scan(struct ath10k *ar,
if (ret) if (ret)
return ret; return ret;
ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ); ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ);
if (ret == 0) { if (ret == 0) {
ret = ath10k_scan_stop(ar); ret = ath10k_scan_stop(ar);
if (ret) if (ret)
...@@ -4356,7 +4378,8 @@ static int ath10k_start(struct ieee80211_hw *hw) ...@@ -4356,7 +4378,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_off; goto err_off;
} }
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL,
&ar->normal_mode_fw);
if (ret) { if (ret) {
ath10k_err(ar, "Could not init core: %d\n", ret); ath10k_err(ar, "Could not init core: %d\n", ret);
goto err_power_down; goto err_power_down;
...@@ -4414,7 +4437,7 @@ static int ath10k_start(struct ieee80211_hw *hw) ...@@ -4414,7 +4437,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
} }
if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA, if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
ar->fw_features)) { ar->running_fw->fw_file.fw_features)) {
ret = ath10k_wmi_pdev_enable_adaptive_cca(ar, 1, ret = ath10k_wmi_pdev_enable_adaptive_cca(ar, 1,
WMI_CCA_DETECT_LEVEL_AUTO, WMI_CCA_DETECT_LEVEL_AUTO,
WMI_CCA_DETECT_MARGIN_AUTO); WMI_CCA_DETECT_MARGIN_AUTO);
...@@ -6168,7 +6191,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, ...@@ -6168,7 +6191,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
return ret; return ret;
} }
#define ATH10K_ROC_TIMEOUT_HZ (2*HZ) #define ATH10K_ROC_TIMEOUT_HZ (2 * HZ)
static int ath10k_remain_on_channel(struct ieee80211_hw *hw, static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -6232,7 +6255,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ...@@ -6232,7 +6255,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
goto exit; goto exit;
} }
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
if (ret == 0) { if (ret == 0) {
ath10k_warn(ar, "failed to switch to channel for roc scan\n"); ath10k_warn(ar, "failed to switch to channel for roc scan\n");
...@@ -6796,6 +6819,32 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ...@@ -6796,6 +6819,32 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return 0; return 0;
} }
static void ath10k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u64 tsf)
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
u32 tsf_offset, vdev_param = ar->wmi.vdev_param->set_tsf;
int ret;
/* Workaround:
*
* Given tsf argument is entire TSF value, but firmware accepts
* only TSF offset to current TSF.
*
* get_tsf function is used to get offset value, however since
* ath10k_get_tsf is not implemented properly, it will return 0 always.
* Luckily all the caller functions to set_tsf, as of now, also rely on
* get_tsf function to get entire tsf value such get_tsf() + tsf_delta,
* final tsf offset value to firmware will be arithmetically correct.
*/
tsf_offset = tsf - ath10k_get_tsf(hw, vif);
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, tsf_offset);
if (ret && ret != -EOPNOTSUPP)
ath10k_warn(ar, "failed to set tsf offset: %d\n", ret);
}
static int ath10k_ampdu_action(struct ieee80211_hw *hw, static int ath10k_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params) struct ieee80211_ampdu_params *params)
...@@ -6867,7 +6916,13 @@ ath10k_mac_update_rx_channel(struct ath10k *ar, ...@@ -6867,7 +6916,13 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
def = &vifs[0].new_ctx->def; def = &vifs[0].new_ctx->def;
ar->rx_channel = def->chan; ar->rx_channel = def->chan;
} else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) { } else if ((ctx && ath10k_mac_num_chanctxs(ar) == 0) ||
(ctx && (ar->state == ATH10K_STATE_RESTARTED))) {
/* During driver restart due to firmware assert, since mac80211
* already has valid channel context for given radio, channel
* context iteration return num_chanctx > 0. So fix rx_channel
* when restart is in progress.
*/
ar->rx_channel = ctx->def.chan; ar->rx_channel = ctx->def.chan;
} else { } else {
ar->rx_channel = NULL; ar->rx_channel = NULL;
...@@ -7252,6 +7307,7 @@ static const struct ieee80211_ops ath10k_ops = { ...@@ -7252,6 +7307,7 @@ static const struct ieee80211_ops ath10k_ops = {
.set_bitrate_mask = ath10k_mac_op_set_bitrate_mask, .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update, .sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf, .get_tsf = ath10k_get_tsf,
.set_tsf = ath10k_set_tsf,
.ampdu_action = ath10k_ampdu_action, .ampdu_action = ath10k_ampdu_action,
.get_et_sset_count = ath10k_debug_get_et_sset_count, .get_et_sset_count = ath10k_debug_get_et_sset_count,
.get_et_stats = ath10k_debug_get_et_stats, .get_et_stats = ath10k_debug_get_et_stats,
...@@ -7640,7 +7696,7 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -7640,7 +7696,7 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->available_antennas_rx = ar->cfg_rx_chainmask; ar->hw->wiphy->available_antennas_rx = ar->cfg_rx_chainmask;
ar->hw->wiphy->available_antennas_tx = ar->cfg_tx_chainmask; ar->hw->wiphy->available_antennas_tx = ar->cfg_tx_chainmask;
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->normal_mode_fw.fw_file.fw_features))
ar->hw->wiphy->interface_modes |= ar->hw->wiphy->interface_modes |=
BIT(NL80211_IFTYPE_P2P_DEVICE) | BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
...@@ -7730,7 +7786,7 @@ int ath10k_mac_register(struct ath10k *ar) ...@@ -7730,7 +7786,7 @@ int ath10k_mac_register(struct ath10k *ar)
*/ */
ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1; ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1;
switch (ar->wmi.op_version) { switch (ar->running_fw->fw_file.wmi_op_version) {
case ATH10K_FW_WMI_OP_VERSION_MAIN: case ATH10K_FW_WMI_OP_VERSION_MAIN:
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 =
......
...@@ -81,6 +81,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, ...@@ -81,6 +81,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar, struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
u16 peer_id, u16 peer_id,
u8 tid); u8 tid);
int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{ {
......
...@@ -33,12 +33,6 @@ ...@@ -33,12 +33,6 @@
#include "ce.h" #include "ce.h"
#include "pci.h" #include "pci.h"
enum ath10k_pci_irq_mode {
ATH10K_PCI_IRQ_AUTO = 0,
ATH10K_PCI_IRQ_LEGACY = 1,
ATH10K_PCI_IRQ_MSI = 2,
};
enum ath10k_pci_reset_mode { enum ath10k_pci_reset_mode {
ATH10K_PCI_RESET_AUTO = 0, ATH10K_PCI_RESET_AUTO = 0,
ATH10K_PCI_RESET_WARM_ONLY = 1, ATH10K_PCI_RESET_WARM_ONLY = 1,
...@@ -745,10 +739,7 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) ...@@ -745,10 +739,7 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
if (ar_pci->num_msi_intrs > 1) if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_MSI)
return "msi-x";
if (ar_pci->num_msi_intrs == 1)
return "msi"; return "msi";
return "legacy"; return "legacy";
...@@ -1502,13 +1493,8 @@ void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, ...@@ -1502,13 +1493,8 @@ void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
void ath10k_pci_kill_tasklet(struct ath10k *ar) void ath10k_pci_kill_tasklet(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
tasklet_kill(&ar_pci->intr_tq); tasklet_kill(&ar_pci->intr_tq);
tasklet_kill(&ar_pci->msi_fw_err);
for (i = 0; i < CE_COUNT; i++)
tasklet_kill(&ar_pci->pipe_info[i].intr);
del_timer_sync(&ar_pci->rx_post_retry); del_timer_sync(&ar_pci->rx_post_retry);
} }
...@@ -1624,10 +1610,8 @@ static void ath10k_pci_irq_disable(struct ath10k *ar) ...@@ -1624,10 +1610,8 @@ static void ath10k_pci_irq_disable(struct ath10k *ar)
static void ath10k_pci_irq_sync(struct ath10k *ar) static void ath10k_pci_irq_sync(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) synchronize_irq(ar_pci->pdev->irq);
synchronize_irq(ar_pci->pdev->irq + i);
} }
static void ath10k_pci_irq_enable(struct ath10k *ar) static void ath10k_pci_irq_enable(struct ath10k *ar)
...@@ -2596,65 +2580,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { ...@@ -2596,65 +2580,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
#endif #endif
}; };
static void ath10k_pci_ce_tasklet(unsigned long ptr)
{
struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;
struct ath10k_pci *ar_pci = pipe->ar_pci;
ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num);
}
static void ath10k_msi_err_tasklet(unsigned long data)
{
struct ath10k *ar = (struct ath10k *)data;
if (!ath10k_pci_has_fw_crashed(ar)) {
ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
return;
}
ath10k_pci_irq_disable(ar);
ath10k_pci_fw_crashed_clear(ar);
ath10k_pci_fw_crashed_dump(ar);
}
/*
* Handler for a per-engine interrupt on a PARTICULAR CE.
* This is used in cases where each CE has a private MSI interrupt.
*/
static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
{
struct ath10k *ar = arg;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
ce_id);
return IRQ_HANDLED;
}
/*
* NOTE: We are able to derive ce_id from irq because we
* use a one-to-one mapping for CE's 0..5.
* CE's 6 & 7 do not use interrupts at all.
*
* This mapping must be kept in sync with the mapping
* used by firmware.
*/
tasklet_schedule(&ar_pci->pipe_info[ce_id].intr);
return IRQ_HANDLED;
}
static irqreturn_t ath10k_pci_msi_fw_handler(int irq, void *arg)
{
struct ath10k *ar = arg;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
tasklet_schedule(&ar_pci->msi_fw_err);
return IRQ_HANDLED;
}
/* /*
* Top-level interrupt handler for all PCI interrupts from a Target. * Top-level interrupt handler for all PCI interrupts from a Target.
* When a block of MSI interrupts is allocated, this top-level handler * When a block of MSI interrupts is allocated, this top-level handler
...@@ -2672,7 +2597,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) ...@@ -2672,7 +2597,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
return IRQ_NONE; return IRQ_NONE;
} }
if (ar_pci->num_msi_intrs == 0) { if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) {
if (!ath10k_pci_irq_pending(ar)) if (!ath10k_pci_irq_pending(ar))
return IRQ_NONE; return IRQ_NONE;
...@@ -2699,43 +2624,10 @@ static void ath10k_pci_tasklet(unsigned long data) ...@@ -2699,43 +2624,10 @@ static void ath10k_pci_tasklet(unsigned long data)
ath10k_ce_per_engine_service_any(ar); ath10k_ce_per_engine_service_any(ar);
/* Re-enable legacy irq that was disabled in the irq handler */ /* Re-enable legacy irq that was disabled in the irq handler */
if (ar_pci->num_msi_intrs == 0) if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
ath10k_pci_enable_legacy_irq(ar); ath10k_pci_enable_legacy_irq(ar);
} }
static int ath10k_pci_request_irq_msix(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret, i;
ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
ath10k_pci_msi_fw_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
return ret;
}
for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) {
ret = request_irq(ar_pci->pdev->irq + i,
ath10k_pci_per_engine_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
ar_pci->pdev->irq + i, ret);
for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
free_irq(ar_pci->pdev->irq + i, ar);
free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
return ret;
}
}
return 0;
}
static int ath10k_pci_request_irq_msi(struct ath10k *ar) static int ath10k_pci_request_irq_msi(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
...@@ -2774,41 +2666,28 @@ static int ath10k_pci_request_irq(struct ath10k *ar) ...@@ -2774,41 +2666,28 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
switch (ar_pci->num_msi_intrs) { switch (ar_pci->oper_irq_mode) {
case 0: case ATH10K_PCI_IRQ_LEGACY:
return ath10k_pci_request_irq_legacy(ar); return ath10k_pci_request_irq_legacy(ar);
case 1: case ATH10K_PCI_IRQ_MSI:
return ath10k_pci_request_irq_msi(ar); return ath10k_pci_request_irq_msi(ar);
default: default:
return ath10k_pci_request_irq_msix(ar); return -EINVAL;
} }
} }
static void ath10k_pci_free_irq(struct ath10k *ar) static void ath10k_pci_free_irq(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
/* There's at least one interrupt irregardless whether its legacy INTR free_irq(ar_pci->pdev->irq, ar);
* or MSI or MSI-X */
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
free_irq(ar_pci->pdev->irq + i, ar);
} }
void ath10k_pci_init_irq_tasklets(struct ath10k *ar) void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
(unsigned long)ar);
for (i = 0; i < CE_COUNT; i++) {
ar_pci->pipe_info[i].ar_pci = ar_pci;
tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
(unsigned long)&ar_pci->pipe_info[i]);
}
} }
static int ath10k_pci_init_irq(struct ath10k *ar) static int ath10k_pci_init_irq(struct ath10k *ar)
...@@ -2822,20 +2701,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ...@@ -2822,20 +2701,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
ath10k_info(ar, "limiting irq mode to: %d\n", ath10k_info(ar, "limiting irq mode to: %d\n",
ath10k_pci_irq_mode); ath10k_pci_irq_mode);
/* Try MSI-X */
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
ar_pci->num_msi_intrs = MSI_ASSIGN_CE_MAX + 1;
ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
ar_pci->num_msi_intrs);
if (ret > 0)
return 0;
/* fall-through */
}
/* Try MSI */ /* Try MSI */
if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) {
ar_pci->num_msi_intrs = 1; ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI;
ret = pci_enable_msi(ar_pci->pdev); ret = pci_enable_msi(ar_pci->pdev);
if (ret == 0) if (ret == 0)
return 0; return 0;
...@@ -2851,7 +2719,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ...@@ -2851,7 +2719,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
* This write might get lost if target has NOT written BAR. * This write might get lost if target has NOT written BAR.
* For now, fix the race by repeating the write in below * For now, fix the race by repeating the write in below
* synchronization checking. */ * synchronization checking. */
ar_pci->num_msi_intrs = 0; ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY;
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
...@@ -2869,8 +2737,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) ...@@ -2869,8 +2737,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
switch (ar_pci->num_msi_intrs) { switch (ar_pci->oper_irq_mode) {
case 0: case ATH10K_PCI_IRQ_LEGACY:
ath10k_pci_deinit_irq_legacy(ar); ath10k_pci_deinit_irq_legacy(ar);
break; break;
default: default:
...@@ -2908,7 +2776,7 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar) ...@@ -2908,7 +2776,7 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar)
if (val & FW_IND_INITIALIZED) if (val & FW_IND_INITIALIZED)
break; break;
if (ar_pci->num_msi_intrs == 0) if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
/* Fix potential race by repeating CORE_BASE writes */ /* Fix potential race by repeating CORE_BASE writes */
ath10k_pci_enable_legacy_irq(ar); ath10k_pci_enable_legacy_irq(ar);
...@@ -3186,8 +3054,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -3186,8 +3054,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_sleep; goto err_sleep;
} }
ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n", ath10k_info(ar, "pci irq %s oper_irq_mode %d irq_mode %d reset_mode %d\n",
ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs, ath10k_pci_get_irq_method(ar), ar_pci->oper_irq_mode,
ath10k_pci_irq_mode, ath10k_pci_reset_mode); ath10k_pci_irq_mode, ath10k_pci_reset_mode);
ret = ath10k_pci_request_irq(ar); ret = ath10k_pci_request_irq(ar);
...@@ -3305,7 +3173,6 @@ MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); ...@@ -3305,7 +3173,6 @@ MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
/* QCA988x 2.0 firmware files */ /* 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_API2_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_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_API4_FILE);
......
...@@ -148,9 +148,6 @@ struct ath10k_pci_pipe { ...@@ -148,9 +148,6 @@ struct ath10k_pci_pipe {
/* protects compl_free and num_send_allowed */ /* protects compl_free and num_send_allowed */
spinlock_t pipe_lock; spinlock_t pipe_lock;
struct ath10k_pci *ar_pci;
struct tasklet_struct intr;
}; };
struct ath10k_pci_supp_chip { struct ath10k_pci_supp_chip {
...@@ -164,6 +161,12 @@ struct ath10k_bus_ops { ...@@ -164,6 +161,12 @@ struct ath10k_bus_ops {
int (*get_num_banks)(struct ath10k *ar); int (*get_num_banks)(struct ath10k *ar);
}; };
enum ath10k_pci_irq_mode {
ATH10K_PCI_IRQ_AUTO = 0,
ATH10K_PCI_IRQ_LEGACY = 1,
ATH10K_PCI_IRQ_MSI = 2,
};
struct ath10k_pci { struct ath10k_pci {
struct pci_dev *pdev; struct pci_dev *pdev;
struct device *dev; struct device *dev;
...@@ -171,14 +174,10 @@ struct ath10k_pci { ...@@ -171,14 +174,10 @@ struct ath10k_pci {
void __iomem *mem; void __iomem *mem;
size_t mem_len; size_t mem_len;
/* /* Operating interrupt mode */
* Number of MSI interrupts granted, 0 --> using legacy PCI line enum ath10k_pci_irq_mode oper_irq_mode;
* interrupts.
*/
int num_msi_intrs;
struct tasklet_struct intr_tq; struct tasklet_struct intr_tq;
struct tasklet_struct msi_fw_err;
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
......
...@@ -134,27 +134,17 @@ ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) ...@@ -134,27 +134,17 @@ ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len)
return seg_info; return seg_info;
} }
int ath10k_swap_code_seg_configure(struct ath10k *ar, int ath10k_swap_code_seg_configure(struct ath10k *ar)
enum ath10k_swap_code_seg_bin_type type)
{ {
int ret; int ret;
struct ath10k_swap_code_seg_info *seg_info = NULL; struct ath10k_swap_code_seg_info *seg_info = NULL;
switch (type) { if (!ar->swap.firmware_swap_code_seg_info)
case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW:
if (!ar->swap.firmware_swap_code_seg_info)
return 0;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n");
seg_info = ar->swap.firmware_swap_code_seg_info;
break;
default:
case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP:
case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF:
ath10k_warn(ar, "ignoring unknown code swap binary type %d\n",
type);
return 0; return 0;
}
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n");
seg_info = ar->swap.firmware_swap_code_seg_info;
ret = ath10k_bmi_write_memory(ar, seg_info->target_addr, ret = ath10k_bmi_write_memory(ar, seg_info->target_addr,
&seg_info->seg_hw_info, &seg_info->seg_hw_info,
...@@ -171,8 +161,13 @@ int ath10k_swap_code_seg_configure(struct ath10k *ar, ...@@ -171,8 +161,13 @@ int ath10k_swap_code_seg_configure(struct ath10k *ar,
void ath10k_swap_code_seg_release(struct ath10k *ar) void ath10k_swap_code_seg_release(struct ath10k *ar)
{ {
ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info); ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info);
ar->swap.firmware_codeswap_data = NULL;
ar->swap.firmware_codeswap_len = 0; /* FIXME: these two assignments look to bein wrong place! Shouldn't
* they be in ath10k_core_free_firmware_files() like the rest?
*/
ar->normal_mode_fw.fw_file.codeswap_data = NULL;
ar->normal_mode_fw.fw_file.codeswap_len = 0;
ar->swap.firmware_swap_code_seg_info = NULL; ar->swap.firmware_swap_code_seg_info = NULL;
} }
...@@ -180,20 +175,23 @@ int ath10k_swap_code_seg_init(struct ath10k *ar) ...@@ -180,20 +175,23 @@ int ath10k_swap_code_seg_init(struct ath10k *ar)
{ {
int ret; int ret;
struct ath10k_swap_code_seg_info *seg_info; struct ath10k_swap_code_seg_info *seg_info;
const void *codeswap_data;
size_t codeswap_len;
codeswap_data = ar->normal_mode_fw.fw_file.codeswap_data;
codeswap_len = ar->normal_mode_fw.fw_file.codeswap_len;
if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data) if (!codeswap_len || !codeswap_data)
return 0; return 0;
seg_info = ath10k_swap_code_seg_alloc(ar, seg_info = ath10k_swap_code_seg_alloc(ar, codeswap_len);
ar->swap.firmware_codeswap_len);
if (!seg_info) { if (!seg_info) {
ath10k_err(ar, "failed to allocate fw code swap segment\n"); ath10k_err(ar, "failed to allocate fw code swap segment\n");
return -ENOMEM; return -ENOMEM;
} }
ret = ath10k_swap_code_seg_fill(ar, seg_info, ret = ath10k_swap_code_seg_fill(ar, seg_info,
ar->swap.firmware_codeswap_data, codeswap_data, codeswap_len);
ar->swap.firmware_codeswap_len);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n", ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n",
......
...@@ -39,12 +39,6 @@ union ath10k_swap_code_seg_item { ...@@ -39,12 +39,6 @@ union ath10k_swap_code_seg_item {
struct ath10k_swap_code_seg_tail tail; struct ath10k_swap_code_seg_tail tail;
} __packed; } __packed;
enum ath10k_swap_code_seg_bin_type {
ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP,
ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW,
ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF,
};
struct ath10k_swap_code_seg_hw_info { struct ath10k_swap_code_seg_hw_info {
/* Swap binary image size */ /* Swap binary image size */
__le32 swap_size; __le32 swap_size;
...@@ -64,8 +58,7 @@ struct ath10k_swap_code_seg_info { ...@@ -64,8 +58,7 @@ struct ath10k_swap_code_seg_info {
dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED];
}; };
int ath10k_swap_code_seg_configure(struct ath10k *ar, int ath10k_swap_code_seg_configure(struct ath10k *ar);
enum ath10k_swap_code_seg_bin_type type);
void ath10k_swap_code_seg_release(struct ath10k *ar); void ath10k_swap_code_seg_release(struct ath10k *ar);
int ath10k_swap_code_seg_init(struct ath10k *ar); int ath10k_swap_code_seg_init(struct ath10k *ar);
......
...@@ -438,7 +438,7 @@ Fw Mode/SubMode Mask ...@@ -438,7 +438,7 @@ Fw Mode/SubMode Mask
((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED)) ((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED))
#define HI_DEV_LPL_TYPE_GET(_devix) \ #define HI_DEV_LPL_TYPE_GET(_devix) \
(HOST_INTEREST->hi_pwr_save_flags & ((HI_PWR_SAVE_LPL_DEV_MASK) << \ (HOST_INTEREST->hi_pwr_save_flags & ((HI_PWR_SAVE_LPL_DEV_MASK) << \
(HI_PWR_SAVE_LPL_DEV0_LSB + (_devix)*2))) (HI_PWR_SAVE_LPL_DEV0_LSB + (_devix) * 2)))
#define HOST_INTEREST_SMPS_IS_ALLOWED() \ #define HOST_INTEREST_SMPS_IS_ALLOWED() \
((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK)) ((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK))
......
...@@ -139,127 +139,8 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) ...@@ -139,127 +139,8 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
return cfg80211_testmode_reply(skb); return cfg80211_testmode_reply(skb);
} }
static int ath10k_tm_fetch_utf_firmware_api_2(struct ath10k *ar) static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
{ struct ath10k_fw_file *fw_file)
size_t len, magic_len, ie_len;
struct ath10k_fw_ie *hdr;
char filename[100];
__le32 *version;
const u8 *data;
int ie_id, ret;
snprintf(filename, sizeof(filename), "%s/%s",
ar->hw_params.fw.dir, ATH10K_FW_UTF_API2_FILE);
/* load utf firmware image */
ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
if (ret) {
ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
filename, ret);
return ret;
}
data = ar->testmode.utf->data;
len = ar->testmode.utf->size;
/* FIXME: call release_firmware() in error cases */
/* magic also includes the null byte, check that as well */
magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
if (len < magic_len) {
ath10k_err(ar, "utf firmware file is too small to contain magic\n");
ret = -EINVAL;
goto err;
}
if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
ath10k_err(ar, "invalid firmware magic\n");
ret = -EINVAL;
goto err;
}
/* jump over the padding */
magic_len = ALIGN(magic_len, 4);
len -= magic_len;
data += magic_len;
/* loop elements */
while (len > sizeof(struct ath10k_fw_ie)) {
hdr = (struct ath10k_fw_ie *)data;
ie_id = le32_to_cpu(hdr->id);
ie_len = le32_to_cpu(hdr->len);
len -= sizeof(*hdr);
data += sizeof(*hdr);
if (len < ie_len) {
ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
ie_id, len, ie_len);
ret = -EINVAL;
goto err;
}
switch (ie_id) {
case ATH10K_FW_IE_FW_VERSION:
if (ie_len > sizeof(ar->testmode.utf_version) - 1)
break;
memcpy(ar->testmode.utf_version, data, ie_len);
ar->testmode.utf_version[ie_len] = '\0';
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
"testmode found fw utf version %s\n",
ar->testmode.utf_version);
break;
case ATH10K_FW_IE_TIMESTAMP:
/* ignore timestamp, but don't warn about it either */
break;
case ATH10K_FW_IE_FW_IMAGE:
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
"testmode found fw image ie (%zd B)\n",
ie_len);
ar->testmode.utf_firmware_data = data;
ar->testmode.utf_firmware_len = ie_len;
break;
case ATH10K_FW_IE_WMI_OP_VERSION:
if (ie_len != sizeof(u32))
break;
version = (__le32 *)data;
ar->testmode.op_version = le32_to_cpup(version);
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode found fw ie wmi op version %d\n",
ar->testmode.op_version);
break;
default:
ath10k_warn(ar, "Unknown testmode FW IE: %u\n",
le32_to_cpu(hdr->id));
break;
}
/* jump over the padding */
ie_len = ALIGN(ie_len, 4);
len -= ie_len;
data += ie_len;
}
if (!ar->testmode.utf_firmware_data || !ar->testmode.utf_firmware_len) {
ath10k_err(ar, "No ATH10K_FW_IE_FW_IMAGE found\n");
ret = -EINVAL;
goto err;
}
return 0;
err:
release_firmware(ar->testmode.utf);
return ret;
}
static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
{ {
char filename[100]; char filename[100];
int ret; int ret;
...@@ -268,7 +149,7 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar) ...@@ -268,7 +149,7 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
/* load utf firmware image */ /* load utf firmware image */
ret = request_firmware(&ar->testmode.utf, filename, ar->dev); ret = request_firmware(&fw_file->firmware, filename, ar->dev);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
filename, ret); filename, ret);
...@@ -281,24 +162,27 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar) ...@@ -281,24 +162,27 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
* correct WMI interface. * correct WMI interface.
*/ */
ar->testmode.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
ar->testmode.utf_firmware_data = ar->testmode.utf->data; fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
ar->testmode.utf_firmware_len = ar->testmode.utf->size; fw_file->firmware_data = fw_file->firmware->data;
fw_file->firmware_len = fw_file->firmware->size;
return 0; return 0;
} }
static int ath10k_tm_fetch_firmware(struct ath10k *ar) static int ath10k_tm_fetch_firmware(struct ath10k *ar)
{ {
struct ath10k_fw_components *utf_mode_fw;
int ret; int ret;
ret = ath10k_tm_fetch_utf_firmware_api_2(ar); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE,
&ar->testmode.utf_mode_fw.fw_file);
if (ret == 0) { if (ret == 0) {
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2"); ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
return 0; goto out;
} }
ret = ath10k_tm_fetch_utf_firmware_api_1(ar); ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
if (ret) { if (ret) {
ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret); ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
return ret; return ret;
...@@ -306,6 +190,21 @@ static int ath10k_tm_fetch_firmware(struct ath10k *ar) ...@@ -306,6 +190,21 @@ static int ath10k_tm_fetch_firmware(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1"); ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
out:
utf_mode_fw = &ar->testmode.utf_mode_fw;
/* Use the same board data file as the normal firmware uses (but
* it's still "owned" by normal_mode_fw so we shouldn't free it.
*/
utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
if (!utf_mode_fw->fw_file.otp_data) {
ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
}
return 0; return 0;
} }
...@@ -329,7 +228,7 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -329,7 +228,7 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
goto err; goto err;
} }
if (WARN_ON(ar->testmode.utf != NULL)) { if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
/* utf image is already downloaded, it shouldn't be */ /* utf image is already downloaded, it shouldn't be */
ret = -EEXIST; ret = -EEXIST;
goto err; goto err;
...@@ -344,27 +243,19 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -344,27 +243,19 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ar->testmode.utf_monitor = true; ar->testmode.utf_monitor = true;
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
BUILD_BUG_ON(sizeof(ar->fw_features) !=
sizeof(ar->testmode.orig_fw_features));
memcpy(ar->testmode.orig_fw_features, ar->fw_features,
sizeof(ar->fw_features));
ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
memset(ar->fw_features, 0, sizeof(ar->fw_features));
ar->wmi.op_version = ar->testmode.op_version;
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n", ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
ar->wmi.op_version); ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
ret = ath10k_hif_power_up(ar); ret = ath10k_hif_power_up(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret); ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
ar->state = ATH10K_STATE_OFF; ar->state = ATH10K_STATE_OFF;
goto err_fw_features; goto err_release_utf_mode_fw;
} }
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
&ar->testmode.utf_mode_fw);
if (ret) { if (ret) {
ath10k_err(ar, "failed to start core (testmode): %d\n", ret); ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
ar->state = ATH10K_STATE_OFF; ar->state = ATH10K_STATE_OFF;
...@@ -373,8 +264,8 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -373,8 +264,8 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
ar->state = ATH10K_STATE_UTF; ar->state = ATH10K_STATE_UTF;
if (strlen(ar->testmode.utf_version) > 0) if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
ver = ar->testmode.utf_version; ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
else else
ver = "API 1"; ver = "API 1";
...@@ -387,14 +278,9 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ...@@ -387,14 +278,9 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
err_power_down: err_power_down:
ath10k_hif_power_down(ar); ath10k_hif_power_down(ar);
err_fw_features: err_release_utf_mode_fw:
/* return the original firmware features */ release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
memcpy(ar->fw_features, ar->testmode.orig_fw_features, ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
sizeof(ar->fw_features));
ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL;
err: err:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
...@@ -415,13 +301,8 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) ...@@ -415,13 +301,8 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
/* return the original firmware features */ release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
memcpy(ar->fw_features, ar->testmode.orig_fw_features, ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
sizeof(ar->fw_features));
ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL;
ar->state = ATH10K_STATE_OFF; ar->state = ATH10K_STATE_OFF;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#define ATH10K_QUIET_PERIOD_MIN 25 #define ATH10K_QUIET_PERIOD_MIN 25
#define ATH10K_QUIET_START_OFFSET 10 #define ATH10K_QUIET_START_OFFSET 10
#define ATH10K_HWMON_NAME_LEN 15 #define ATH10K_HWMON_NAME_LEN 15
#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ) #define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
#define ATH10K_THERMAL_THROTTLE_MAX 100 #define ATH10K_THERMAL_THROTTLE_MAX 100
struct ath10k_thermal { struct ath10k_thermal {
......
...@@ -130,7 +130,7 @@ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, ...@@ -130,7 +130,7 @@ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
list_for_each_entry(peer, &ar->peers, list) { list_for_each_entry(peer, &ar->peers, list) {
if (peer->vdev_id != vdev_id) if (peer->vdev_id != vdev_id)
continue; continue;
if (memcmp(peer->addr, addr, ETH_ALEN)) if (!ether_addr_equal(peer->addr, addr))
continue; continue;
return peer; return peer;
...@@ -166,7 +166,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, ...@@ -166,7 +166,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
(mapped == expect_mapped || (mapped == expect_mapped ||
test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
}), 3*HZ); }), 3 * HZ);
if (time_left == 0) if (time_left == 0)
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -190,6 +190,13 @@ void ath10k_peer_map_event(struct ath10k_htt *htt, ...@@ -190,6 +190,13 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
struct ath10k_peer *peer; struct ath10k_peer *peer;
if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
ath10k_warn(ar,
"received htt peer map event with idx out of bounds: %hu\n",
ev->peer_id);
return;
}
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr); peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
if (!peer) { if (!peer) {
...@@ -218,6 +225,13 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt, ...@@ -218,6 +225,13 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
struct ath10k_peer *peer; struct ath10k_peer *peer;
if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
ath10k_warn(ar,
"received htt peer unmap event with idx out of bounds: %hu\n",
ev->peer_id);
return;
}
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, ev->peer_id); peer = ath10k_peer_find_by_id(ar, ev->peer_id);
if (!peer) { if (!peer) {
......
...@@ -3409,6 +3409,7 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { ...@@ -3409,6 +3409,7 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
.set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
}; };
static const struct wmi_ops wmi_tlv_ops = { static const struct wmi_ops wmi_tlv_ops = {
......
...@@ -968,8 +968,8 @@ enum wmi_tlv_service { ...@@ -968,8 +968,8 @@ enum wmi_tlv_service {
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
((svc_id) < (len) && \ ((svc_id) < (len) && \
__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \
BIT((svc_id)%(sizeof(u32)))) BIT((svc_id) % (sizeof(u32))))
#define SVCMAP(x, y, len) \ #define SVCMAP(x, y, len) \
do { \ do { \
......
...@@ -781,6 +781,7 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { ...@@ -781,6 +781,7 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = {
.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
.set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
}; };
/* 10.X WMI VDEV param map */ /* 10.X WMI VDEV param map */
...@@ -856,6 +857,7 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { ...@@ -856,6 +857,7 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = {
.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
.set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
}; };
static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
...@@ -930,6 +932,7 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { ...@@ -930,6 +932,7 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
.set_tsf = WMI_10X_VDEV_PARAM_TSF_INCREMENT,
}; };
static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = {
...@@ -1005,6 +1008,7 @@ static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { ...@@ -1005,6 +1008,7 @@ static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = {
.meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC,
.rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE,
.bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK,
.set_tsf = WMI_10_4_VDEV_PARAM_TSF_INCREMENT,
}; };
static struct wmi_pdev_param_map wmi_pdev_param_map = { static struct wmi_pdev_param_map wmi_pdev_param_map = {
...@@ -1804,7 +1808,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) ...@@ -1804,7 +1808,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
ret = -ESHUTDOWN; ret = -ESHUTDOWN;
(ret != -EAGAIN); (ret != -EAGAIN);
}), 3*HZ); }), 3 * HZ);
if (ret) if (ret)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -2145,7 +2149,8 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, ...@@ -2145,7 +2149,8 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
u32 msdu_len; u32 msdu_len;
u32 len; u32 len;
if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX,
ar->running_fw->fw_file.fw_features)) {
ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
ev_hdr = &ev_v2->hdr.v1; ev_hdr = &ev_v2->hdr.v1;
pull_len = sizeof(*ev_v2); pull_len = sizeof(*ev_v2);
...@@ -4600,10 +4605,6 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ...@@ -4600,10 +4605,6 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
arg.service_map, arg.service_map_len); arg.service_map, arg.service_map_len);
/* only manually set fw features when not using FW IE format */
if (ar->fw_api == 1 && ar->fw_version_build > 636)
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
if (ar->num_rf_chains > ar->max_spatial_stream) { if (ar->num_rf_chains > ar->max_spatial_stream) {
ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, ar->max_spatial_stream); ar->num_rf_chains, ar->max_spatial_stream);
...@@ -4634,7 +4635,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ...@@ -4634,7 +4635,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
ar->fw_features)) ar->running_fw->fw_file.fw_features))
ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS_PFC + ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS_PFC +
ar->max_num_vdevs; ar->max_num_vdevs;
else else
...@@ -5823,9 +5824,8 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, ...@@ -5823,9 +5824,8 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
bssids->num_bssid = __cpu_to_le32(arg->n_bssids); bssids->num_bssid = __cpu_to_le32(arg->n_bssids);
for (i = 0; i < arg->n_bssids; i++) for (i = 0; i < arg->n_bssids; i++)
memcpy(&bssids->bssid_list[i], ether_addr_copy(bssids->bssid_list[i].addr,
arg->bssids[i].bssid, arg->bssids[i].bssid);
ETH_ALEN);
ptr += sizeof(*bssids); ptr += sizeof(*bssids);
ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids; ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids;
...@@ -7865,7 +7865,7 @@ static const struct wmi_ops wmi_10_4_ops = { ...@@ -7865,7 +7865,7 @@ static const struct wmi_ops wmi_10_4_ops = {
int ath10k_wmi_attach(struct ath10k *ar) int ath10k_wmi_attach(struct ath10k *ar)
{ {
switch (ar->wmi.op_version) { switch (ar->running_fw->fw_file.wmi_op_version) {
case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_10_4:
ar->wmi.ops = &wmi_10_4_ops; ar->wmi.ops = &wmi_10_4_ops;
ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.cmd = &wmi_10_4_cmd_map;
...@@ -7907,7 +7907,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ...@@ -7907,7 +7907,7 @@ int ath10k_wmi_attach(struct ath10k *ar)
case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX: case ATH10K_FW_WMI_OP_VERSION_MAX:
ath10k_err(ar, "unsupported WMI op version: %d\n", ath10k_err(ar, "unsupported WMI op version: %d\n",
ar->wmi.op_version); ar->running_fw->fw_file.wmi_op_version);
return -EINVAL; return -EINVAL;
} }
......
...@@ -180,6 +180,9 @@ enum wmi_service { ...@@ -180,6 +180,9 @@ enum wmi_service {
WMI_SERVICE_MESH_NON_11S, WMI_SERVICE_MESH_NON_11S,
WMI_SERVICE_PEER_STATS, WMI_SERVICE_PEER_STATS,
WMI_SERVICE_RESTRT_CHNL_SUPPORT, WMI_SERVICE_RESTRT_CHNL_SUPPORT,
WMI_SERVICE_TX_MODE_PUSH_ONLY,
WMI_SERVICE_TX_MODE_PUSH_PULL,
WMI_SERVICE_TX_MODE_DYNAMIC,
/* keep last */ /* keep last */
WMI_SERVICE_MAX, WMI_SERVICE_MAX,
...@@ -302,6 +305,9 @@ enum wmi_10_4_service { ...@@ -302,6 +305,9 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT, WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
WMI_10_4_SERVICE_PEER_STATS, WMI_10_4_SERVICE_PEER_STATS,
WMI_10_4_SERVICE_MESH_11S, WMI_10_4_SERVICE_MESH_11S,
WMI_10_4_SERVICE_TX_MODE_PUSH_ONLY,
WMI_10_4_SERVICE_TX_MODE_PUSH_PULL,
WMI_10_4_SERVICE_TX_MODE_DYNAMIC,
}; };
static inline char *wmi_service_name(int service_id) static inline char *wmi_service_name(int service_id)
...@@ -396,6 +402,9 @@ static inline char *wmi_service_name(int service_id) ...@@ -396,6 +402,9 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_MESH_NON_11S); SVCSTR(WMI_SERVICE_MESH_NON_11S);
SVCSTR(WMI_SERVICE_PEER_STATS); SVCSTR(WMI_SERVICE_PEER_STATS);
SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT); SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT);
SVCSTR(WMI_SERVICE_TX_MODE_PUSH_ONLY);
SVCSTR(WMI_SERVICE_TX_MODE_PUSH_PULL);
SVCSTR(WMI_SERVICE_TX_MODE_DYNAMIC);
default: default:
return NULL; return NULL;
} }
...@@ -405,8 +414,8 @@ static inline char *wmi_service_name(int service_id) ...@@ -405,8 +414,8 @@ static inline char *wmi_service_name(int service_id)
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
((svc_id) < (len) && \ ((svc_id) < (len) && \
__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \
BIT((svc_id)%(sizeof(u32)))) BIT((svc_id) % (sizeof(u32))))
#define SVCMAP(x, y, len) \ #define SVCMAP(x, y, len) \
do { \ do { \
...@@ -643,6 +652,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, ...@@ -643,6 +652,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_PEER_STATS, len); WMI_SERVICE_PEER_STATS, len);
SVCMAP(WMI_10_4_SERVICE_MESH_11S, SVCMAP(WMI_10_4_SERVICE_MESH_11S,
WMI_SERVICE_MESH_11S, len); WMI_SERVICE_MESH_11S, len);
SVCMAP(WMI_10_4_SERVICE_TX_MODE_PUSH_ONLY,
WMI_SERVICE_TX_MODE_PUSH_ONLY, len);
SVCMAP(WMI_10_4_SERVICE_TX_MODE_PUSH_PULL,
WMI_SERVICE_TX_MODE_PUSH_PULL, len);
SVCMAP(WMI_10_4_SERVICE_TX_MODE_DYNAMIC,
WMI_SERVICE_TX_MODE_DYNAMIC, len);
} }
#undef SVCMAP #undef SVCMAP
...@@ -1309,7 +1324,7 @@ enum wmi_10x_event_id { ...@@ -1309,7 +1324,7 @@ enum wmi_10x_event_id {
WMI_10X_PDEV_TPC_CONFIG_EVENTID, WMI_10X_PDEV_TPC_CONFIG_EVENTID,
WMI_10X_GPIO_INPUT_EVENTID, WMI_10X_GPIO_INPUT_EVENTID,
WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1, WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID - 1,
}; };
enum wmi_10_2_cmd_id { enum wmi_10_2_cmd_id {
...@@ -2042,8 +2057,8 @@ struct wmi_10x_service_ready_event { ...@@ -2042,8 +2057,8 @@ struct wmi_10x_service_ready_event {
struct wlan_host_mem_req mem_reqs[0]; struct wlan_host_mem_req mem_reqs[0];
} __packed; } __packed;
#define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ) #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
#define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ) #define WMI_UNIFIED_READY_TIMEOUT_HZ (5 * HZ)
struct wmi_ready_event { struct wmi_ready_event {
__le32 sw_version; __le32 sw_version;
...@@ -2661,9 +2676,14 @@ struct wmi_resource_config_10_4 { ...@@ -2661,9 +2676,14 @@ struct wmi_resource_config_10_4 {
*/ */
__le32 iphdr_pad_config; __le32 iphdr_pad_config;
/* qwrap configuration /* qwrap configuration (bits 15-0)
* 1 - This is qwrap configuration * 1 - This is qwrap configuration
* 0 - This is not qwrap * 0 - This is not qwrap
*
* Bits 31-16 is alloc_frag_desc_for_data_pkt (1 enables, 0 disables)
* In order to get ack-RSSI reporting and to specify the tx-rate for
* individual frames, this option must be enabled. This uses an extra
* 4 bytes per tx-msdu descriptor, so don't enable it unless you need it.
*/ */
__le32 qwrap_config; __le32 qwrap_config;
} __packed; } __packed;
...@@ -4384,14 +4404,14 @@ enum wmi_vdev_subtype_10_4 { ...@@ -4384,14 +4404,14 @@ enum wmi_vdev_subtype_10_4 {
/* /*
* Indicates that AP VDEV uses hidden ssid. only valid for * Indicates that AP VDEV uses hidden ssid. only valid for
* AP/GO */ * AP/GO */
#define WMI_VDEV_START_HIDDEN_SSID (1<<0) #define WMI_VDEV_START_HIDDEN_SSID (1 << 0)
/* /*
* Indicates if robust management frame/management frame * Indicates if robust management frame/management frame
* protection is enabled. For GO/AP vdevs, it indicates that * protection is enabled. For GO/AP vdevs, it indicates that
* it may support station/client associations with RMF enabled. * it may support station/client associations with RMF enabled.
* For STA/client vdevs, it indicates that sta will * For STA/client vdevs, it indicates that sta will
* associate with AP with RMF enabled. */ * associate with AP with RMF enabled. */
#define WMI_VDEV_START_PMF_ENABLED (1<<1) #define WMI_VDEV_START_PMF_ENABLED (1 << 1)
struct wmi_p2p_noa_descriptor { struct wmi_p2p_noa_descriptor {
__le32 type_count; /* 255: continuous schedule, 0: reserved */ __le32 type_count; /* 255: continuous schedule, 0: reserved */
...@@ -4630,6 +4650,7 @@ struct wmi_vdev_param_map { ...@@ -4630,6 +4650,7 @@ struct wmi_vdev_param_map {
u32 meru_vc; u32 meru_vc;
u32 rx_decap_type; u32 rx_decap_type;
u32 bw_nss_ratemask; u32 bw_nss_ratemask;
u32 set_tsf;
}; };
#define WMI_VDEV_PARAM_UNSUPPORTED 0 #define WMI_VDEV_PARAM_UNSUPPORTED 0
...@@ -4886,6 +4907,7 @@ enum wmi_10x_vdev_param { ...@@ -4886,6 +4907,7 @@ enum wmi_10x_vdev_param {
WMI_10X_VDEV_PARAM_RTS_FIXED_RATE, WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
WMI_10X_VDEV_PARAM_VHT_SGIMASK, WMI_10X_VDEV_PARAM_VHT_SGIMASK,
WMI_10X_VDEV_PARAM_VHT80_RATEMASK, WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
WMI_10X_VDEV_PARAM_TSF_INCREMENT,
}; };
enum wmi_10_4_vdev_param { enum wmi_10_4_vdev_param {
...@@ -4955,6 +4977,12 @@ enum wmi_10_4_vdev_param { ...@@ -4955,6 +4977,12 @@ enum wmi_10_4_vdev_param {
WMI_10_4_VDEV_PARAM_MERU_VC, WMI_10_4_VDEV_PARAM_MERU_VC,
WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE,
WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK,
WMI_10_4_VDEV_PARAM_SENSOR_AP,
WMI_10_4_VDEV_PARAM_BEACON_RATE,
WMI_10_4_VDEV_PARAM_DTIM_ENABLE_CTS,
WMI_10_4_VDEV_PARAM_STA_KICKOUT,
WMI_10_4_VDEV_PARAM_CAPABILITIES,
WMI_10_4_VDEV_PARAM_TSF_INCREMENT,
}; };
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
...@@ -5329,7 +5357,7 @@ enum wmi_sta_ps_param_pspoll_count { ...@@ -5329,7 +5357,7 @@ enum wmi_sta_ps_param_pspoll_count {
#define WMI_UAPSD_AC_TYPE_TRIG 1 #define WMI_UAPSD_AC_TYPE_TRIG 1
#define WMI_UAPSD_AC_BIT_MASK(ac, type) \ #define WMI_UAPSD_AC_BIT_MASK(ac, type) \
((type == WMI_UAPSD_AC_TYPE_DELI) ? (1<<(ac<<1)) : (1<<((ac<<1)+1))) ((type == WMI_UAPSD_AC_TYPE_DELI) ? (1 << (ac << 1)) : (1 << ((ac << 1) + 1)))
enum wmi_sta_ps_param_uapsd { enum wmi_sta_ps_param_uapsd {
WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0),
...@@ -5744,7 +5772,7 @@ struct wmi_rate_set { ...@@ -5744,7 +5772,7 @@ struct wmi_rate_set {
* the rates are filled from least significant byte to most * the rates are filled from least significant byte to most
* significant byte. * significant byte.
*/ */
__le32 rates[(MAX_SUPPORTED_RATES/4)+1]; __le32 rates[(MAX_SUPPORTED_RATES / 4) + 1];
} __packed; } __packed;
struct wmi_rate_set_arg { struct wmi_rate_set_arg {
......
...@@ -233,7 +233,7 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw, ...@@ -233,7 +233,7 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
ar->fw_features))) { ar->running_fw->fw_file.fw_features))) {
ret = 1; ret = 1;
goto exit; goto exit;
} }
...@@ -285,7 +285,7 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) ...@@ -285,7 +285,7 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
ar->fw_features))) { ar->running_fw->fw_file.fw_features))) {
ret = 1; ret = 1;
goto exit; goto exit;
} }
...@@ -325,7 +325,8 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) ...@@ -325,7 +325,8 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)
int ath10k_wow_init(struct ath10k *ar) int ath10k_wow_init(struct ath10k *ar)
{ {
if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, ar->fw_features)) if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
ar->running_fw->fw_file.fw_features))
return 0; return 0;
if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map))) if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
......
...@@ -246,7 +246,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, ...@@ -246,7 +246,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ieee80211_conf *conf = &common->hw->conf; struct ieee80211_conf *conf = &common->hw->conf;
bool fastcc; bool fastcc;
struct ieee80211_channel *channel = hw->conf.chandef.chan; struct ieee80211_channel *channel = hw->conf.chandef.chan;
struct ath9k_hw_cal_data *caldata = NULL; struct ath9k_hw_cal_data *caldata;
enum htc_phymode mode; enum htc_phymode mode;
__be16 htc_mode; __be16 htc_mode;
u8 cmd_rsp; u8 cmd_rsp;
...@@ -274,10 +274,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, ...@@ -274,10 +274,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
priv->ah->curchan->channel, priv->ah->curchan->channel,
channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
fastcc); fastcc);
caldata = fastcc ? NULL : &priv->caldata;
if (!fastcc)
caldata = &priv->caldata;
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (ret) { if (ret) {
ath_err(common, ath_err(common,
......
...@@ -2914,8 +2914,7 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -2914,8 +2914,7 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
{ {
struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
int chan_pwr, new_pwr, max_gain; int chan_pwr, new_pwr;
int ant_gain, ant_reduction = 0;
if (!chan) if (!chan)
return; return;
...@@ -2923,15 +2922,10 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -2923,15 +2922,10 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
channel = chan->chan; channel = chan->chan;
chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
new_pwr = min_t(int, chan_pwr, reg->power_limit); new_pwr = min_t(int, chan_pwr, reg->power_limit);
max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
ant_gain = get_antenna_gain(ah, chan);
if (ant_gain > max_gain)
ant_reduction = ant_gain - max_gain;
ah->eep_ops->set_txpower(ah, chan, ah->eep_ops->set_txpower(ah, chan,
ath9k_regd_get_ctl(reg, chan), ath9k_regd_get_ctl(reg, chan),
ant_reduction, new_pwr, test); get_antenna_gain(ah, chan), new_pwr, test);
} }
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
......
...@@ -49,6 +49,10 @@ int ath9k_led_blink; ...@@ -49,6 +49,10 @@ int ath9k_led_blink;
module_param_named(blink, ath9k_led_blink, int, 0444); module_param_named(blink, ath9k_led_blink, int, 0444);
MODULE_PARM_DESC(blink, "Enable LED blink on activity"); MODULE_PARM_DESC(blink, "Enable LED blink on activity");
static int ath9k_led_active_high = -1;
module_param_named(led_active_high, ath9k_led_active_high, int, 0444);
MODULE_PARM_DESC(led_active_high, "Invert LED polarity");
static int ath9k_btcoex_enable; static int ath9k_btcoex_enable;
module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
...@@ -477,7 +481,7 @@ static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, ...@@ -477,7 +481,7 @@ static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
static int ath9k_eeprom_request(struct ath_softc *sc, const char *name) static int ath9k_eeprom_request(struct ath_softc *sc, const char *name)
{ {
struct ath9k_eeprom_ctx ec; struct ath9k_eeprom_ctx ec;
struct ath_hw *ah = ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
int err; int err;
/* try to load the EEPROM content asynchronously */ /* try to load the EEPROM content asynchronously */
...@@ -600,6 +604,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -600,6 +604,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret) if (ret)
return ret; return ret;
if (ath9k_led_active_high != -1)
ah->config.led_active_high = ath9k_led_active_high == 1;
/* /*
* Enable WLAN/BT RX Antenna diversity only when: * Enable WLAN/BT RX Antenna diversity only when:
* *
......
...@@ -28,6 +28,16 @@ static const struct pci_device_id ath_pci_id_table[] = { ...@@ -28,6 +28,16 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
#ifdef CONFIG_ATH9K_PCOEM
/* Mini PCI AR9220 MB92 cards: Compex WLM200NX, Wistron DNMA-92 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0029,
PCI_VENDOR_ID_ATHEROS,
0x2096),
.driver_data = ATH9K_PCI_LED_ACT_HI },
#endif
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
#ifdef CONFIG_ATH9K_PCOEM #ifdef CONFIG_ATH9K_PCOEM
......
...@@ -33,9 +33,7 @@ static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf, ...@@ -33,9 +33,7 @@ static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf,
char buf[3]; char buf[3];
list_for_each_entry(vif_priv, &wcn->vif_list, list) { list_for_each_entry(vif_priv, &wcn->vif_list, list) {
vif = container_of((void *)vif_priv, vif = wcn36xx_priv_to_vif(vif_priv);
struct ieee80211_vif,
drv_priv);
if (NL80211_IFTYPE_STATION == vif->type) { if (NL80211_IFTYPE_STATION == vif->type) {
if (vif_priv->pw_state == WCN36XX_BMPS) if (vif_priv->pw_state == WCN36XX_BMPS)
buf[0] = '1'; buf[0] = '1';
...@@ -70,9 +68,7 @@ static ssize_t write_file_bool_bmps(struct file *file, ...@@ -70,9 +68,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
case 'Y': case 'Y':
case '1': case '1':
list_for_each_entry(vif_priv, &wcn->vif_list, list) { list_for_each_entry(vif_priv, &wcn->vif_list, list) {
vif = container_of((void *)vif_priv, vif = wcn36xx_priv_to_vif(vif_priv);
struct ieee80211_vif,
drv_priv);
if (NL80211_IFTYPE_STATION == vif->type) { if (NL80211_IFTYPE_STATION == vif->type) {
wcn36xx_enable_keep_alive_null_packet(wcn, vif); wcn36xx_enable_keep_alive_null_packet(wcn, vif);
wcn36xx_pmc_enter_bmps_state(wcn, vif); wcn36xx_pmc_enter_bmps_state(wcn, vif);
...@@ -83,9 +79,7 @@ static ssize_t write_file_bool_bmps(struct file *file, ...@@ -83,9 +79,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
case 'N': case 'N':
case '0': case '0':
list_for_each_entry(vif_priv, &wcn->vif_list, list) { list_for_each_entry(vif_priv, &wcn->vif_list, list) {
vif = container_of((void *)vif_priv, vif = wcn36xx_priv_to_vif(vif_priv);
struct ieee80211_vif,
drv_priv);
if (NL80211_IFTYPE_STATION == vif->type) if (NL80211_IFTYPE_STATION == vif->type)
wcn36xx_pmc_exit_bmps_state(wcn, vif); wcn36xx_pmc_exit_bmps_state(wcn, vif);
} }
......
...@@ -48,12 +48,15 @@ ...@@ -48,12 +48,15 @@
#define WCN36XX_HAL_IPV4_ADDR_LEN 4 #define WCN36XX_HAL_IPV4_ADDR_LEN 4
#define WALN_HAL_STA_INVALID_IDX 0xFF #define WCN36XX_HAL_STA_INVALID_IDX 0xFF
#define WCN36XX_HAL_BSS_INVALID_IDX 0xFF #define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
/* Default Beacon template size */ /* Default Beacon template size */
#define BEACON_TEMPLATE_SIZE 0x180 #define BEACON_TEMPLATE_SIZE 0x180
/* Minimum PVM size that the FW expects. See comment in smd.c for details. */
#define TIM_MIN_PVM_SIZE 6
/* Param Change Bitmap sent to HAL */ /* Param Change Bitmap sent to HAL */
#define PARAM_BCN_INTERVAL_CHANGED (1 << 0) #define PARAM_BCN_INTERVAL_CHANGED (1 << 0)
#define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) #define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1)
...@@ -2884,11 +2887,14 @@ struct update_beacon_rsp_msg { ...@@ -2884,11 +2887,14 @@ struct update_beacon_rsp_msg {
struct wcn36xx_hal_send_beacon_req_msg { struct wcn36xx_hal_send_beacon_req_msg {
struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_msg_header header;
/* length of the template + 6. Only qcom knows why */
u32 beacon_length6;
/* length of the template. */ /* length of the template. */
u32 beacon_length; u32 beacon_length;
/* Beacon data. */ /* Beacon data. */
u8 beacon[BEACON_TEMPLATE_SIZE]; u8 beacon[BEACON_TEMPLATE_SIZE - sizeof(u32)];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
...@@ -4261,9 +4267,9 @@ struct wcn36xx_hal_rcv_flt_mc_addr_list_type { ...@@ -4261,9 +4267,9 @@ struct wcn36xx_hal_rcv_flt_mc_addr_list_type {
u8 data_offset; u8 data_offset;
u32 mc_addr_count; u32 mc_addr_count;
u8 mc_addr[ETH_ALEN][WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS]; u8 mc_addr[WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS][ETH_ALEN];
u8 bss_index; u8 bss_index;
}; } __packed;
struct wcn36xx_hal_set_pkt_filter_rsp_msg { struct wcn36xx_hal_set_pkt_filter_rsp_msg {
struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_msg_header header;
...@@ -4317,7 +4323,7 @@ struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg { ...@@ -4317,7 +4323,7 @@ struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg {
struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg { struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg {
struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_msg_header header;
struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list; struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list;
}; } __packed;
struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg { struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg {
struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_msg_header header;
...@@ -4383,6 +4389,45 @@ enum place_holder_in_cap_bitmap { ...@@ -4383,6 +4389,45 @@ enum place_holder_in_cap_bitmap {
RTT = 20, RTT = 20,
RATECTRL = 21, RATECTRL = 21,
WOW = 22, WOW = 22,
WLAN_ROAM_SCAN_OFFLOAD = 23,
SPECULATIVE_PS_POLL = 24,
SCAN_SCH = 25,
IBSS_HEARTBEAT_OFFLOAD = 26,
WLAN_SCAN_OFFLOAD = 27,
WLAN_PERIODIC_TX_PTRN = 28,
ADVANCE_TDLS = 29,
BATCH_SCAN = 30,
FW_IN_TX_PATH = 31,
EXTENDED_NSOFFLOAD_SLOT = 32,
CH_SWITCH_V1 = 33,
HT40_OBSS_SCAN = 34,
UPDATE_CHANNEL_LIST = 35,
WLAN_MCADDR_FLT = 36,
WLAN_CH144 = 37,
NAN = 38,
TDLS_SCAN_COEXISTENCE = 39,
LINK_LAYER_STATS_MEAS = 40,
MU_MIMO = 41,
EXTENDED_SCAN = 42,
DYNAMIC_WMM_PS = 43,
MAC_SPOOFED_SCAN = 44,
BMU_ERROR_GENERIC_RECOVERY = 45,
DISA = 46,
FW_STATS = 47,
WPS_PRBRSP_TMPL = 48,
BCN_IE_FLT_DELTA = 49,
TDLS_OFF_CHANNEL = 51,
RTT3 = 52,
MGMT_FRAME_LOGGING = 53,
ENHANCED_TXBD_COMPLETION = 54,
LOGGING_ENHANCEMENT = 55,
EXT_SCAN_ENHANCED = 56,
MEMORY_DUMP_SUPPORTED = 57,
PER_PKT_STATS_SUPPORTED = 58,
EXT_LL_STAT = 60,
WIFI_CONFIG = 61,
ANTENNA_DIVERSITY_SELECTION = 62,
MAX_FEATURE_SUPPORTED = 128, MAX_FEATURE_SUPPORTED = 128,
}; };
......
...@@ -201,7 +201,45 @@ static const char * const wcn36xx_caps_names[] = { ...@@ -201,7 +201,45 @@ static const char * const wcn36xx_caps_names[] = {
"BCN_FILTER", /* 19 */ "BCN_FILTER", /* 19 */
"RTT", /* 20 */ "RTT", /* 20 */
"RATECTRL", /* 21 */ "RATECTRL", /* 21 */
"WOW" /* 22 */ "WOW", /* 22 */
"WLAN_ROAM_SCAN_OFFLOAD", /* 23 */
"SPECULATIVE_PS_POLL", /* 24 */
"SCAN_SCH", /* 25 */
"IBSS_HEARTBEAT_OFFLOAD", /* 26 */
"WLAN_SCAN_OFFLOAD", /* 27 */
"WLAN_PERIODIC_TX_PTRN", /* 28 */
"ADVANCE_TDLS", /* 29 */
"BATCH_SCAN", /* 30 */
"FW_IN_TX_PATH", /* 31 */
"EXTENDED_NSOFFLOAD_SLOT", /* 32 */
"CH_SWITCH_V1", /* 33 */
"HT40_OBSS_SCAN", /* 34 */
"UPDATE_CHANNEL_LIST", /* 35 */
"WLAN_MCADDR_FLT", /* 36 */
"WLAN_CH144", /* 37 */
"NAN", /* 38 */
"TDLS_SCAN_COEXISTENCE", /* 39 */
"LINK_LAYER_STATS_MEAS", /* 40 */
"MU_MIMO", /* 41 */
"EXTENDED_SCAN", /* 42 */
"DYNAMIC_WMM_PS", /* 43 */
"MAC_SPOOFED_SCAN", /* 44 */
"BMU_ERROR_GENERIC_RECOVERY", /* 45 */
"DISA", /* 46 */
"FW_STATS", /* 47 */
"WPS_PRBRSP_TMPL", /* 48 */
"BCN_IE_FLT_DELTA", /* 49 */
"TDLS_OFF_CHANNEL", /* 51 */
"RTT3", /* 52 */
"MGMT_FRAME_LOGGING", /* 53 */
"ENHANCED_TXBD_COMPLETION", /* 54 */
"LOGGING_ENHANCEMENT", /* 55 */
"EXT_SCAN_ENHANCED", /* 56 */
"MEMORY_DUMP_SUPPORTED", /* 57 */
"PER_PKT_STATS_SUPPORTED", /* 58 */
"EXT_LL_STAT", /* 60 */
"WIFI_CONFIG", /* 61 */
"ANTENNA_DIVERSITY_SELECTION", /* 62 */
}; };
static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
...@@ -287,6 +325,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw) ...@@ -287,6 +325,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
} }
wcn36xx_detect_chip_version(wcn); wcn36xx_detect_chip_version(wcn);
wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
/* DMA channel initialization */ /* DMA channel initialization */
ret = wcn36xx_dxe_init(wcn); ret = wcn36xx_dxe_init(wcn);
...@@ -346,9 +385,7 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) ...@@ -346,9 +385,7 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
ch); ch);
list_for_each_entry(tmp, &wcn->vif_list, list) { list_for_each_entry(tmp, &wcn->vif_list, list) {
vif = container_of((void *)tmp, vif = wcn36xx_priv_to_vif(tmp);
struct ieee80211_vif,
drv_priv);
wcn36xx_smd_switch_channel(wcn, vif, ch); wcn36xx_smd_switch_channel(wcn, vif, ch);
} }
} }
...@@ -356,15 +393,57 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) ...@@ -356,15 +393,57 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
return 0; return 0;
} }
#define WCN36XX_SUPPORTED_FILTERS (0)
static void wcn36xx_configure_filter(struct ieee80211_hw *hw, static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
unsigned int changed, unsigned int changed,
unsigned int *total, u64 multicast) unsigned int *total, u64 multicast)
{ {
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *tmp;
struct ieee80211_vif *vif = NULL;
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n"); wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
*total &= WCN36XX_SUPPORTED_FILTERS; *total &= FIF_ALLMULTI;
fp = (void *)(unsigned long)multicast;
list_for_each_entry(tmp, &wcn->vif_list, list) {
vif = wcn36xx_priv_to_vif(tmp);
/* FW handles MC filtering only when connected as STA */
if (*total & FIF_ALLMULTI)
wcn36xx_smd_set_mc_list(wcn, vif, NULL);
else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)
wcn36xx_smd_set_mc_list(wcn, vif, fp);
}
kfree(fp);
}
static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list)
{
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
struct netdev_hw_addr *ha;
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");
fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
if (!fp) {
wcn36xx_err("Out of memory setting filters.\n");
return 0;
}
fp->mc_addr_count = 0;
/* update multicast filtering parameters */
if (netdev_hw_addr_list_count(mc_list) <=
WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {
netdev_hw_addr_list_for_each(ha, mc_list) {
memcpy(fp->mc_addr[fp->mc_addr_count],
ha->addr, ETH_ALEN);
fp->mc_addr_count++;
}
}
return (u64)(unsigned long)fp;
} }
static void wcn36xx_tx(struct ieee80211_hw *hw, static void wcn36xx_tx(struct ieee80211_hw *hw,
...@@ -375,7 +454,7 @@ static void wcn36xx_tx(struct ieee80211_hw *hw, ...@@ -375,7 +454,7 @@ static void wcn36xx_tx(struct ieee80211_hw *hw,
struct wcn36xx_sta *sta_priv = NULL; struct wcn36xx_sta *sta_priv = NULL;
if (control->sta) if (control->sta)
sta_priv = (struct wcn36xx_sta *)control->sta->drv_priv; sta_priv = wcn36xx_sta_to_priv(control->sta);
if (wcn36xx_start_tx(wcn, sta_priv, skb)) if (wcn36xx_start_tx(wcn, sta_priv, skb))
ieee80211_free_txskb(wcn->hw, skb); ieee80211_free_txskb(wcn->hw, skb);
...@@ -387,8 +466,8 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -387,8 +466,8 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key_conf) struct ieee80211_key_conf *key_conf)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
struct wcn36xx_sta *sta_priv = vif_priv->sta; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
int ret = 0; int ret = 0;
u8 key[WLAN_MAX_KEY_LEN]; u8 key[WLAN_MAX_KEY_LEN];
...@@ -473,6 +552,7 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -473,6 +552,7 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
break; break;
case DISABLE_KEY: case DISABLE_KEY:
if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) { if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
wcn36xx_smd_remove_bsskey(wcn, wcn36xx_smd_remove_bsskey(wcn,
vif_priv->encrypt_type, vif_priv->encrypt_type,
key_conf->keyidx); key_conf->keyidx);
...@@ -520,7 +600,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, ...@@ -520,7 +600,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
{ {
int i, size; int i, size;
u16 *rates_table; u16 *rates_table;
struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
u32 rates = sta->supp_rates[band]; u32 rates = sta->supp_rates[band];
memset(&sta_priv->supported_rates, 0, memset(&sta_priv->supported_rates, 0,
...@@ -590,7 +670,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -590,7 +670,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
u16 tim_off, tim_len; u16 tim_off, tim_len;
enum wcn36xx_hal_link_state link_state; enum wcn36xx_hal_link_state link_state;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
vif, changed); vif, changed);
...@@ -620,7 +700,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -620,7 +700,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
if (!is_zero_ether_addr(bss_conf->bssid)) { if (!is_zero_ether_addr(bss_conf->bssid)) {
vif_priv->is_joining = true; vif_priv->is_joining = true;
vif_priv->bss_index = 0xff; vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
wcn36xx_smd_join(wcn, bss_conf->bssid, wcn36xx_smd_join(wcn, bss_conf->bssid,
vif->addr, WCN36XX_HW_CHANNEL(wcn)); vif->addr, WCN36XX_HW_CHANNEL(wcn));
wcn36xx_smd_config_bss(wcn, vif, NULL, wcn36xx_smd_config_bss(wcn, vif, NULL,
...@@ -628,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -628,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
} else { } else {
vif_priv->is_joining = false; vif_priv->is_joining = false;
wcn36xx_smd_delete_bss(wcn, vif); wcn36xx_smd_delete_bss(wcn, vif);
vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
} }
} }
...@@ -655,6 +736,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -655,6 +736,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
vif->addr, vif->addr,
bss_conf->aid); bss_conf->aid);
vif_priv->sta_assoc = true;
rcu_read_lock(); rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid); sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (!sta) { if (!sta) {
...@@ -663,7 +745,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -663,7 +745,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
rcu_read_unlock(); rcu_read_unlock();
goto out; goto out;
} }
sta_priv = (struct wcn36xx_sta *)sta->drv_priv; sta_priv = wcn36xx_sta_to_priv(sta);
wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn)); wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
...@@ -686,6 +768,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -686,6 +768,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid, bss_conf->bssid,
vif->addr, vif->addr,
bss_conf->aid); bss_conf->aid);
vif_priv->sta_assoc = false;
wcn36xx_smd_set_link_st(wcn, wcn36xx_smd_set_link_st(wcn,
bss_conf->bssid, bss_conf->bssid,
vif->addr, vif->addr,
...@@ -713,7 +796,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -713,7 +796,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->enable_beacon) { if (bss_conf->enable_beacon) {
vif_priv->dtim_period = bss_conf->dtim_period; vif_priv->dtim_period = bss_conf->dtim_period;
vif_priv->bss_index = 0xff; vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
wcn36xx_smd_config_bss(wcn, vif, NULL, wcn36xx_smd_config_bss(wcn, vif, NULL,
vif->addr, false); vif->addr, false);
skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
...@@ -734,9 +817,9 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, ...@@ -734,9 +817,9 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
link_state); link_state);
} else { } else {
wcn36xx_smd_delete_bss(wcn, vif);
wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
WCN36XX_HAL_LINK_IDLE_STATE); WCN36XX_HAL_LINK_IDLE_STATE);
wcn36xx_smd_delete_bss(wcn, vif);
} }
} }
out: out:
...@@ -757,7 +840,7 @@ static void wcn36xx_remove_interface(struct ieee80211_hw *hw, ...@@ -757,7 +840,7 @@ static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif); wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
list_del(&vif_priv->list); list_del(&vif_priv->list);
...@@ -768,7 +851,7 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw, ...@@ -768,7 +851,7 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
vif, vif->type); vif, vif->type);
...@@ -792,13 +875,12 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -792,13 +875,12 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
vif, sta->addr); vif, sta->addr);
spin_lock_init(&sta_priv->ampdu_lock); spin_lock_init(&sta_priv->ampdu_lock);
vif_priv->sta = sta_priv;
sta_priv->vif = vif_priv; sta_priv->vif = vif_priv;
/* /*
* For STA mode HW will be configured on BSS_CHANGED_ASSOC because * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
...@@ -817,14 +899,12 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw, ...@@ -817,14 +899,12 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
vif, sta->addr, sta_priv->sta_index); vif, sta->addr, sta_priv->sta_index);
wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index); wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
vif_priv->sta = NULL;
sta_priv->vif = NULL; sta_priv->vif = NULL;
return 0; return 0;
} }
...@@ -860,7 +940,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, ...@@ -860,7 +940,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_ampdu_params *params) struct ieee80211_ampdu_params *params)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
struct wcn36xx_sta *sta_priv = NULL; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(params->sta);
struct ieee80211_sta *sta = params->sta; struct ieee80211_sta *sta = params->sta;
enum ieee80211_ampdu_mlme_action action = params->action; enum ieee80211_ampdu_mlme_action action = params->action;
u16 tid = params->tid; u16 tid = params->tid;
...@@ -869,8 +949,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, ...@@ -869,8 +949,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
action, tid); action, tid);
sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
sta_priv->tid = tid; sta_priv->tid = tid;
...@@ -923,6 +1001,7 @@ static const struct ieee80211_ops wcn36xx_ops = { ...@@ -923,6 +1001,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
.resume = wcn36xx_resume, .resume = wcn36xx_resume,
#endif #endif
.config = wcn36xx_config, .config = wcn36xx_config,
.prepare_multicast = wcn36xx_prepare_multicast,
.configure_filter = wcn36xx_configure_filter, .configure_filter = wcn36xx_configure_filter,
.tx = wcn36xx_tx, .tx = wcn36xx_tx,
.set_key = wcn36xx_set_key, .set_key = wcn36xx_set_key,
......
...@@ -22,7 +22,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, ...@@ -22,7 +22,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
int ret = 0; int ret = 0;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
/* TODO: Make sure the TX chain clean */ /* TODO: Make sure the TX chain clean */
ret = wcn36xx_smd_enter_bmps(wcn, vif); ret = wcn36xx_smd_enter_bmps(wcn, vif);
if (!ret) { if (!ret) {
...@@ -42,7 +42,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, ...@@ -42,7 +42,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn, int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
if (WCN36XX_BMPS != vif_priv->pw_state) { if (WCN36XX_BMPS != vif_priv->pw_state) {
wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n"); wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n");
......
...@@ -191,16 +191,16 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, ...@@ -191,16 +191,16 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct wcn36xx_hal_config_sta_params *sta_params) struct wcn36xx_hal_config_sta_params *sta_params)
{ {
struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
struct wcn36xx_sta *priv_sta = NULL; struct wcn36xx_sta *sta_priv = NULL;
if (vif->type == NL80211_IFTYPE_ADHOC || if (vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT) { vif->type == NL80211_IFTYPE_MESH_POINT) {
sta_params->type = 1; sta_params->type = 1;
sta_params->sta_index = 0xFF; sta_params->sta_index = WCN36XX_HAL_STA_INVALID_IDX;
} else { } else {
sta_params->type = 0; sta_params->type = 0;
sta_params->sta_index = 1; sta_params->sta_index = vif_priv->self_sta_index;
} }
sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);
...@@ -215,7 +215,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, ...@@ -215,7 +215,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
else else
memcpy(&sta_params->bssid, vif->addr, ETH_ALEN); memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);
sta_params->encrypt_type = priv_vif->encrypt_type; sta_params->encrypt_type = vif_priv->encrypt_type;
sta_params->short_preamble_supported = true; sta_params->short_preamble_supported = true;
sta_params->rifs_mode = 0; sta_params->rifs_mode = 0;
...@@ -224,21 +224,21 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, ...@@ -224,21 +224,21 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
sta_params->uapsd = 0; sta_params->uapsd = 0;
sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC; sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC;
sta_params->max_ampdu_duration = 0; sta_params->max_ampdu_duration = 0;
sta_params->bssid_index = priv_vif->bss_index; sta_params->bssid_index = vif_priv->bss_index;
sta_params->p2p = 0; sta_params->p2p = 0;
if (sta) { if (sta) {
priv_sta = (struct wcn36xx_sta *)sta->drv_priv; sta_priv = wcn36xx_sta_to_priv(sta);
if (NL80211_IFTYPE_STATION == vif->type) if (NL80211_IFTYPE_STATION == vif->type)
memcpy(&sta_params->bssid, sta->addr, ETH_ALEN); memcpy(&sta_params->bssid, sta->addr, ETH_ALEN);
else else
memcpy(&sta_params->mac, sta->addr, ETH_ALEN); memcpy(&sta_params->mac, sta->addr, ETH_ALEN);
sta_params->wmm_enabled = sta->wme; sta_params->wmm_enabled = sta->wme;
sta_params->max_sp_len = sta->max_sp; sta_params->max_sp_len = sta->max_sp;
sta_params->aid = priv_sta->aid; sta_params->aid = sta_priv->aid;
wcn36xx_smd_set_sta_ht_params(sta, sta_params); wcn36xx_smd_set_sta_ht_params(sta, sta_params);
memcpy(&sta_params->supported_rates, &priv_sta->supported_rates, memcpy(&sta_params->supported_rates, &sta_priv->supported_rates,
sizeof(priv_sta->supported_rates)); sizeof(sta_priv->supported_rates));
} else { } else {
wcn36xx_set_default_rates(&sta_params->supported_rates); wcn36xx_set_default_rates(&sta_params->supported_rates);
wcn36xx_smd_set_sta_default_ht_params(sta_params); wcn36xx_smd_set_sta_default_ht_params(sta_params);
...@@ -271,6 +271,16 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) ...@@ -271,6 +271,16 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
return ret; return ret;
} }
static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr,
enum wcn36xx_hal_host_msg_type msg_type,
size_t msg_size)
{
memset(hdr, 0, msg_size + sizeof(*hdr));
hdr->msg_type = msg_type;
hdr->msg_version = WCN36XX_HAL_MSG_VERSION0;
hdr->len = msg_size + sizeof(*hdr);
}
#define INIT_HAL_MSG(msg_body, type) \ #define INIT_HAL_MSG(msg_body, type) \
do { \ do { \
memset(&msg_body, 0, sizeof(msg_body)); \ memset(&msg_body, 0, sizeof(msg_body)); \
...@@ -302,22 +312,6 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) ...@@ -302,22 +312,6 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
return 0; return 0;
} }
static int wcn36xx_smd_rsp_status_check_v2(struct wcn36xx *wcn, void *buf,
size_t len)
{
struct wcn36xx_fw_msg_status_rsp_v2 *rsp;
if (len < sizeof(struct wcn36xx_hal_msg_header) + sizeof(*rsp))
return wcn36xx_smd_rsp_status_check(buf, len);
rsp = buf + sizeof(struct wcn36xx_hal_msg_header);
if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status)
return rsp->status;
return 0;
}
int wcn36xx_smd_load_nv(struct wcn36xx *wcn) int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
{ {
struct nv_data *nv_d; struct nv_data *nv_d;
...@@ -726,7 +720,7 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, ...@@ -726,7 +720,7 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,
size_t len) size_t len)
{ {
struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; struct wcn36xx_hal_add_sta_self_rsp_msg *rsp;
struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
if (len < sizeof(*rsp)) if (len < sizeof(*rsp))
return -EINVAL; return -EINVAL;
...@@ -743,8 +737,8 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, ...@@ -743,8 +737,8 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,
"hal add sta self status %d self_sta_index %d dpu_index %d\n", "hal add sta self status %d self_sta_index %d dpu_index %d\n",
rsp->status, rsp->self_sta_index, rsp->dpu_index); rsp->status, rsp->self_sta_index, rsp->dpu_index);
priv_vif->self_sta_index = rsp->self_sta_index; vif_priv->self_sta_index = rsp->self_sta_index;
priv_vif->self_dpu_desc_index = rsp->dpu_index; vif_priv->self_dpu_desc_index = rsp->dpu_index;
return 0; return 0;
} }
...@@ -949,17 +943,32 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn, ...@@ -949,17 +943,32 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
memcpy(&v1->mac, orig->mac, ETH_ALEN); memcpy(&v1->mac, orig->mac, ETH_ALEN);
v1->aid = orig->aid; v1->aid = orig->aid;
v1->type = orig->type; v1->type = orig->type;
v1->short_preamble_supported = orig->short_preamble_supported;
v1->listen_interval = orig->listen_interval; v1->listen_interval = orig->listen_interval;
v1->wmm_enabled = orig->wmm_enabled;
v1->ht_capable = orig->ht_capable; v1->ht_capable = orig->ht_capable;
v1->tx_channel_width_set = orig->tx_channel_width_set;
v1->rifs_mode = orig->rifs_mode;
v1->lsig_txop_protection = orig->lsig_txop_protection;
v1->max_ampdu_size = orig->max_ampdu_size; v1->max_ampdu_size = orig->max_ampdu_size;
v1->max_ampdu_density = orig->max_ampdu_density; v1->max_ampdu_density = orig->max_ampdu_density;
v1->sgi_40mhz = orig->sgi_40mhz; v1->sgi_40mhz = orig->sgi_40mhz;
v1->sgi_20Mhz = orig->sgi_20Mhz; v1->sgi_20Mhz = orig->sgi_20Mhz;
v1->rmf = orig->rmf;
v1->encrypt_type = orig->encrypt_type;
v1->action = orig->action;
v1->uapsd = orig->uapsd;
v1->max_sp_len = orig->max_sp_len;
v1->green_field_capable = orig->green_field_capable;
v1->mimo_ps = orig->mimo_ps;
v1->delayed_ba_support = orig->delayed_ba_support;
v1->max_ampdu_duration = orig->max_ampdu_duration;
v1->dsss_cck_mode_40mhz = orig->dsss_cck_mode_40mhz;
memcpy(&v1->supported_rates, &orig->supported_rates, memcpy(&v1->supported_rates, &orig->supported_rates,
sizeof(orig->supported_rates)); sizeof(orig->supported_rates));
v1->sta_index = orig->sta_index; v1->sta_index = orig->sta_index;
v1->bssid_index = orig->bssid_index;
v1->p2p = orig->p2p;
} }
static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
...@@ -969,7 +978,7 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, ...@@ -969,7 +978,7 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
{ {
struct wcn36xx_hal_config_sta_rsp_msg *rsp; struct wcn36xx_hal_config_sta_rsp_msg *rsp;
struct config_sta_rsp_params *params; struct config_sta_rsp_params *params;
struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
if (len < sizeof(*rsp)) if (len < sizeof(*rsp))
return -EINVAL; return -EINVAL;
...@@ -1170,12 +1179,13 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn, ...@@ -1170,12 +1179,13 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
void *buf, void *buf,
size_t len) size_t len)
{ {
struct wcn36xx_hal_config_bss_rsp_msg *rsp; struct wcn36xx_hal_config_bss_rsp_msg *rsp;
struct wcn36xx_hal_config_bss_rsp_params *params; struct wcn36xx_hal_config_bss_rsp_params *params;
struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
if (len < sizeof(*rsp)) if (len < sizeof(*rsp))
return -EINVAL; return -EINVAL;
...@@ -1198,14 +1208,15 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, ...@@ -1198,14 +1208,15 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
params->bss_bcast_sta_idx, params->mac, params->bss_bcast_sta_idx, params->mac,
params->tx_mgmt_power, params->ucast_dpu_signature); params->tx_mgmt_power, params->ucast_dpu_signature);
priv_vif->bss_index = params->bss_index; vif_priv->bss_index = params->bss_index;
if (priv_vif->sta) { if (sta) {
priv_vif->sta->bss_sta_index = params->bss_sta_index; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; sta_priv->bss_sta_index = params->bss_sta_index;
sta_priv->bss_dpu_desc_index = params->dpu_desc_index;
} }
priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; vif_priv->self_ucast_dpu_sign = params->ucast_dpu_signature;
return 0; return 0;
} }
...@@ -1217,7 +1228,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, ...@@ -1217,7 +1228,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
struct wcn36xx_hal_config_bss_req_msg msg; struct wcn36xx_hal_config_bss_req_msg msg;
struct wcn36xx_hal_config_bss_params *bss; struct wcn36xx_hal_config_bss_params *bss;
struct wcn36xx_hal_config_sta_params *sta_params; struct wcn36xx_hal_config_sta_params *sta_params;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret = 0; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
...@@ -1329,6 +1340,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, ...@@ -1329,6 +1340,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
} }
ret = wcn36xx_smd_config_bss_rsp(wcn, ret = wcn36xx_smd_config_bss_rsp(wcn,
vif, vif,
sta,
wcn->hal_buf, wcn->hal_buf,
wcn->hal_rsp_len); wcn->hal_rsp_len);
if (ret) { if (ret) {
...@@ -1343,13 +1355,13 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, ...@@ -1343,13 +1355,13 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif)
{ {
struct wcn36xx_hal_delete_bss_req_msg msg_body; struct wcn36xx_hal_delete_bss_req_msg msg_body;
struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret = 0; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ);
msg_body.bss_index = priv_vif->bss_index; msg_body.bss_index = vif_priv->bss_index;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body); PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
...@@ -1375,26 +1387,47 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, ...@@ -1375,26 +1387,47 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
u16 p2p_off) u16 p2p_off)
{ {
struct wcn36xx_hal_send_beacon_req_msg msg_body; struct wcn36xx_hal_send_beacon_req_msg msg_body;
int ret = 0; int ret = 0, pad, pvm_len;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
/* TODO need to find out why this is needed? */ pvm_len = skb_beacon->data[tim_off + 1] - 3;
msg_body.beacon_length = skb_beacon->len + 6; pad = TIM_MIN_PVM_SIZE - pvm_len;
if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) { /* Padding is irrelevant to mesh mode since tim_off is always 0. */
memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32)); if (vif->type == NL80211_IFTYPE_MESH_POINT)
memcpy(&(msg_body.beacon[4]), skb_beacon->data, pad = 0;
skb_beacon->len);
} else { msg_body.beacon_length = skb_beacon->len + pad;
/* TODO need to find out why + 6 is needed */
msg_body.beacon_length6 = msg_body.beacon_length + 6;
if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {
wcn36xx_err("Beacon is to big: beacon size=%d\n", wcn36xx_err("Beacon is to big: beacon size=%d\n",
msg_body.beacon_length); msg_body.beacon_length);
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);
memcpy(msg_body.bssid, vif->addr, ETH_ALEN); memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
if (pad > 0) {
/*
* The wcn36xx FW has a fixed size for the PVM in the TIM. If
* given the beacon template from mac80211 with a PVM shorter
* than the FW expectes it will overwrite the data after the
* TIM.
*/
wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n",
pad, pvm_len);
memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad],
&msg_body.beacon[tim_off + 5 + pvm_len],
skb_beacon->len - (tim_off + 5 + pvm_len));
memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad);
msg_body.beacon[tim_off + 1] += pad;
}
/* TODO need to find out why this is needed? */ /* TODO need to find out why this is needed? */
if (vif->type == NL80211_IFTYPE_MESH_POINT) if (vif->type == NL80211_IFTYPE_MESH_POINT)
/* mesh beacon don't need this, so push further down */ /* mesh beacon don't need this, so push further down */
...@@ -1598,8 +1631,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, ...@@ -1598,8 +1631,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
wcn36xx_err("Sending hal_remove_bsskey failed\n"); wcn36xx_err("Sending hal_remove_bsskey failed\n");
goto out; goto out;
} }
ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf, ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
wcn->hal_rsp_len);
if (ret) { if (ret) {
wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret); wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret);
goto out; goto out;
...@@ -1612,7 +1644,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, ...@@ -1612,7 +1644,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
{ {
struct wcn36xx_hal_enter_bmps_req_msg msg_body; struct wcn36xx_hal_enter_bmps_req_msg msg_body;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret = 0; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
...@@ -1641,8 +1673,8 @@ int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) ...@@ -1641,8 +1673,8 @@ int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
{ {
struct wcn36xx_hal_enter_bmps_req_msg msg_body; struct wcn36xx_hal_exit_bmps_req_msg msg_body;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret = 0; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
...@@ -1703,7 +1735,7 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, ...@@ -1703,7 +1735,7 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
int packet_type) int packet_type)
{ {
struct wcn36xx_hal_keep_alive_req_msg msg_body; struct wcn36xx_hal_keep_alive_req_msg msg_body;
struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret = 0; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
...@@ -1944,6 +1976,17 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index) ...@@ -1944,6 +1976,17 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index)
return ret; return ret;
} }
static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len)
{
struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;
if (len < sizeof(*rsp))
return -EINVAL;
rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf;
return rsp->status;
}
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
{ {
struct wcn36xx_hal_trigger_ba_req_msg msg_body; struct wcn36xx_hal_trigger_ba_req_msg msg_body;
...@@ -1968,8 +2011,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) ...@@ -1968,8 +2011,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
wcn36xx_err("Sending hal_trigger_ba failed\n"); wcn36xx_err("Sending hal_trigger_ba failed\n");
goto out; goto out;
} }
ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf, ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len);
wcn->hal_rsp_len);
if (ret) { if (ret) {
wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret); wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
goto out; goto out;
...@@ -2006,9 +2048,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, ...@@ -2006,9 +2048,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
list_for_each_entry(tmp, &wcn->vif_list, list) { list_for_each_entry(tmp, &wcn->vif_list, list) {
wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
tmp->bss_index); tmp->bss_index);
vif = container_of((void *)tmp, vif = wcn36xx_priv_to_vif(tmp);
struct ieee80211_vif,
drv_priv);
ieee80211_connection_loss(vif); ieee80211_connection_loss(vif);
} }
return 0; return 0;
...@@ -2023,9 +2063,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, ...@@ -2023,9 +2063,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
if (tmp->bss_index == rsp->bss_index) { if (tmp->bss_index == rsp->bss_index) {
wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
rsp->bss_index); rsp->bss_index);
vif = container_of((void *)tmp, vif = wcn36xx_priv_to_vif(tmp);
struct ieee80211_vif,
drv_priv);
ieee80211_connection_loss(vif); ieee80211_connection_loss(vif);
return 0; return 0;
} }
...@@ -2041,25 +2079,24 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn, ...@@ -2041,25 +2079,24 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
{ {
struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf; struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;
struct wcn36xx_vif *tmp; struct wcn36xx_vif *tmp;
struct ieee80211_sta *sta = NULL; struct ieee80211_sta *sta;
if (len != sizeof(*rsp)) { if (len != sizeof(*rsp)) {
wcn36xx_warn("Corrupted delete sta indication\n"); wcn36xx_warn("Corrupted delete sta indication\n");
return -EIO; return -EIO;
} }
wcn36xx_dbg(WCN36XX_DBG_HAL, "delete station indication %pM index %d\n",
rsp->addr2, rsp->sta_id);
list_for_each_entry(tmp, &wcn->vif_list, list) { list_for_each_entry(tmp, &wcn->vif_list, list) {
if (sta && (tmp->sta->sta_index == rsp->sta_id)) { rcu_read_lock();
sta = container_of((void *)tmp->sta, sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
struct ieee80211_sta, if (sta)
drv_priv);
wcn36xx_dbg(WCN36XX_DBG_HAL,
"delete station indication %pM index %d\n",
rsp->addr2,
rsp->sta_id);
ieee80211_report_low_ack(sta, 0); ieee80211_report_low_ack(sta, 0);
rcu_read_unlock();
if (sta)
return 0; return 0;
}
} }
wcn36xx_warn("STA with addr %pM and index %d not found\n", wcn36xx_warn("STA with addr %pM and index %d not found\n",
...@@ -2100,6 +2137,46 @@ int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value) ...@@ -2100,6 +2137,46 @@ int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value)
mutex_unlock(&wcn->hal_mutex); mutex_unlock(&wcn->hal_mutex);
return ret; return ret;
} }
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp)
{
struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *)
wcn->hal_buf;
init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ,
sizeof(msg_body->mc_addr_list));
/* An empty list means all mc traffic will be received */
if (fp)
memcpy(&msg_body->mc_addr_list, fp,
sizeof(msg_body->mc_addr_list));
else
msg_body->mc_addr_list.mc_addr_count = 0;
msg_body->mc_addr_list.bss_index = vif_priv->bss_index;
ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
if (ret) {
wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n");
goto out;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n", ret);
goto out;
}
out:
mutex_unlock(&wcn->hal_mutex);
return ret;
}
static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
{ {
struct wcn36xx_hal_msg_header *msg_header = buf; struct wcn36xx_hal_msg_header *msg_header = buf;
...@@ -2141,6 +2218,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) ...@@ -2141,6 +2218,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP:
case WCN36XX_HAL_CH_SWITCH_RSP: case WCN36XX_HAL_CH_SWITCH_RSP:
case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
memcpy(wcn->hal_buf, buf, len); memcpy(wcn->hal_buf, buf, len);
wcn->hal_rsp_len = len; wcn->hal_rsp_len = len;
complete(&wcn->hal_rsp_compl); complete(&wcn->hal_rsp_compl);
......
...@@ -44,15 +44,6 @@ struct wcn36xx_fw_msg_status_rsp { ...@@ -44,15 +44,6 @@ struct wcn36xx_fw_msg_status_rsp {
u32 status; u32 status;
} __packed; } __packed;
/* wcn3620 returns this for tigger_ba */
struct wcn36xx_fw_msg_status_rsp_v2 {
u8 bss_id[6];
u32 status __packed;
u16 count_following_candidates __packed;
/* candidate list follows */
};
struct wcn36xx_hal_ind_msg { struct wcn36xx_hal_ind_msg {
struct list_head list; struct list_head list;
u8 *msg; u8 *msg;
...@@ -136,4 +127,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index); ...@@ -136,4 +127,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index); int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
#endif /* _SMD_H_ */ #endif /* _SMD_H_ */
...@@ -102,9 +102,7 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, ...@@ -102,9 +102,7 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
struct wcn36xx_vif *vif_priv = NULL; struct wcn36xx_vif *vif_priv = NULL;
struct ieee80211_vif *vif = NULL; struct ieee80211_vif *vif = NULL;
list_for_each_entry(vif_priv, &wcn->vif_list, list) { list_for_each_entry(vif_priv, &wcn->vif_list, list) {
vif = container_of((void *)vif_priv, vif = wcn36xx_priv_to_vif(vif_priv);
struct ieee80211_vif,
drv_priv);
if (memcmp(vif->addr, addr, ETH_ALEN) == 0) if (memcmp(vif->addr, addr, ETH_ALEN) == 0)
return vif_priv; return vif_priv;
} }
...@@ -167,9 +165,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, ...@@ -167,9 +165,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
*/ */
if (sta_priv) { if (sta_priv) {
__vif_priv = sta_priv->vif; __vif_priv = sta_priv->vif;
vif = container_of((void *)__vif_priv, vif = wcn36xx_priv_to_vif(__vif_priv);
struct ieee80211_vif,
drv_priv);
bd->dpu_sign = sta_priv->ucast_dpu_sign; bd->dpu_sign = sta_priv->ucast_dpu_sign;
if (vif->type == NL80211_IFTYPE_STATION) { if (vif->type == NL80211_IFTYPE_STATION) {
......
...@@ -125,10 +125,10 @@ struct wcn36xx_platform_ctrl_ops { ...@@ -125,10 +125,10 @@ struct wcn36xx_platform_ctrl_ops {
*/ */
struct wcn36xx_vif { struct wcn36xx_vif {
struct list_head list; struct list_head list;
struct wcn36xx_sta *sta;
u8 dtim_period; u8 dtim_period;
enum ani_ed_type encrypt_type; enum ani_ed_type encrypt_type;
bool is_joining; bool is_joining;
bool sta_assoc;
struct wcn36xx_hal_mac_ssid ssid; struct wcn36xx_hal_mac_ssid ssid;
/* Power management */ /* Power management */
...@@ -263,4 +263,22 @@ struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv) ...@@ -263,4 +263,22 @@ struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv); return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv);
} }
static inline
struct wcn36xx_vif *wcn36xx_vif_to_priv(struct ieee80211_vif *vif)
{
return (struct wcn36xx_vif *) vif->drv_priv;
}
static inline
struct ieee80211_vif *wcn36xx_priv_to_vif(struct wcn36xx_vif *vif_priv)
{
return container_of((void *) vif_priv, struct ieee80211_vif, drv_priv);
}
static inline
struct wcn36xx_sta *wcn36xx_sta_to_priv(struct ieee80211_sta *sta)
{
return (struct wcn36xx_sta *)sta->drv_priv;
}
#endif /* _WCN36XX_H_ */ #endif /* _WCN36XX_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部