mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 00:24:58 +08:00
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.8. Major changes: ath10k * enable support for QCA9888
This commit is contained in:
commit
cf8c581a00
@ -206,6 +206,28 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = QCA9888_HW_2_0_DEV_VERSION,
|
||||
.dev_id = QCA9888_2_0_DEVICE_ID,
|
||||
.name = "qca9888 hw2.0",
|
||||
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
|
||||
.uart_pin = 7,
|
||||
.otp_exe_param = 0x00000700,
|
||||
.continuous_frag_desc = true,
|
||||
.channel_counters_freq_hz = 150000,
|
||||
.max_probe_resp_desc_thres = 24,
|
||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
||||
.tx_chain_mask = 3,
|
||||
.rx_chain_mask = 3,
|
||||
.max_spatial_stream = 2,
|
||||
.cal_data_len = 12064,
|
||||
.fw = {
|
||||
.dir = QCA9888_HW_2_0_FW_DIR,
|
||||
.board = QCA9888_HW_2_0_BOARD_DATA_FILE,
|
||||
.board_size = QCA99X0_BOARD_DATA_SZ,
|
||||
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = QCA9377_HW_1_0_DEV_VERSION,
|
||||
.dev_id = QCA9377_1_0_DEVICE_ID,
|
||||
@ -1675,7 +1697,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||
case ATH10K_FW_WMI_OP_VERSION_10_4:
|
||||
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
||||
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
||||
WARN_ON(1);
|
||||
ath10k_err(ar, "htt op version not found from fw meta data");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@ -2171,6 +2193,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||
ar->regs = &qca99x0_regs;
|
||||
ar->hw_values = &qca99x0_values;
|
||||
break;
|
||||
case ATH10K_HW_QCA9888:
|
||||
ar->regs = &qca99x0_regs;
|
||||
ar->hw_values = &qca9888_values;
|
||||
break;
|
||||
case ATH10K_HW_QCA4019:
|
||||
ar->regs = &qca4019_regs;
|
||||
ar->hw_values = &qca4019_values;
|
||||
|
@ -165,6 +165,13 @@ struct ath10k_fw_stats_peer {
|
||||
u32 rx_duration;
|
||||
};
|
||||
|
||||
struct ath10k_fw_extd_stats_peer {
|
||||
struct list_head list;
|
||||
|
||||
u8 peer_macaddr[ETH_ALEN];
|
||||
u32 rx_duration;
|
||||
};
|
||||
|
||||
struct ath10k_fw_stats_vdev {
|
||||
struct list_head list;
|
||||
|
||||
@ -256,9 +263,11 @@ struct ath10k_fw_stats_pdev {
|
||||
};
|
||||
|
||||
struct ath10k_fw_stats {
|
||||
bool extended;
|
||||
struct list_head pdevs;
|
||||
struct list_head vdevs;
|
||||
struct list_head peers;
|
||||
struct list_head peers_extd;
|
||||
};
|
||||
|
||||
#define ATH10K_TPC_TABLE_TYPE_FLAG 1
|
||||
|
@ -313,13 +313,25 @@ static void ath10k_fw_stats_peers_free(struct list_head *head)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_fw_extd_stats_peers_free(struct list_head *head)
|
||||
{
|
||||
struct ath10k_fw_extd_stats_peer *i, *tmp;
|
||||
|
||||
list_for_each_entry_safe(i, tmp, head, list) {
|
||||
list_del(&i->list);
|
||||
kfree(i);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->debug.fw_stats_done = false;
|
||||
ar->debug.fw_stats.extended = false;
|
||||
ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
|
||||
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
|
||||
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
|
||||
ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
@ -334,6 +346,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
INIT_LIST_HEAD(&stats.pdevs);
|
||||
INIT_LIST_HEAD(&stats.vdevs);
|
||||
INIT_LIST_HEAD(&stats.peers);
|
||||
INIT_LIST_HEAD(&stats.peers_extd);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
|
||||
@ -354,7 +367,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
* delivered which is treated as end-of-data and is itself discarded
|
||||
*/
|
||||
if (ath10k_peer_stats_enabled(ar))
|
||||
ath10k_sta_update_rx_duration(ar, &stats.peers);
|
||||
ath10k_sta_update_rx_duration(ar, &stats);
|
||||
|
||||
if (ar->debug.fw_stats_done) {
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
@ -396,6 +409,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
||||
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
|
||||
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
|
||||
list_splice_tail_init(&stats.peers_extd,
|
||||
&ar->debug.fw_stats.peers_extd);
|
||||
}
|
||||
|
||||
complete(&ar->debug.fw_stats_complete);
|
||||
@ -407,6 +422,7 @@ free:
|
||||
ath10k_fw_stats_pdevs_free(&stats.pdevs);
|
||||
ath10k_fw_stats_vdevs_free(&stats.vdevs);
|
||||
ath10k_fw_stats_peers_free(&stats.peers);
|
||||
ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
@ -2330,6 +2346,7 @@ int ath10k_debug_create(struct ath10k *ar)
|
||||
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
|
||||
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
|
||||
INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
|
||||
INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -154,10 +154,15 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir);
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer);
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats);
|
||||
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo);
|
||||
#else
|
||||
static inline void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct list_head *peer)
|
||||
static inline
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MAC80211_DEBUGFS */
|
||||
|
@ -18,13 +18,15 @@
|
||||
#include "wmi-ops.h"
|
||||
#include "debug.h"
|
||||
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
|
||||
{ struct ieee80211_sta *sta;
|
||||
struct ath10k_fw_stats_peer *peer;
|
||||
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
struct ath10k_fw_extd_stats_peer *peer;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(peer, head, list) {
|
||||
list_for_each_entry(peer, &stats->peers_extd, list) {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
|
||||
NULL);
|
||||
if (!sta)
|
||||
@ -35,6 +37,48 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
struct ath10k_fw_stats_peer *peer;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(peer, &stats->peers, list) {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
|
||||
NULL);
|
||||
if (!sta)
|
||||
continue;
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
arsta->rx_duration += (u64)peer->rx_duration;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
if (stats->extended)
|
||||
ath10k_sta_update_extd_stats_rx_duration(ar, stats);
|
||||
else
|
||||
ath10k_sta_update_stats_rx_duration(ar, stats);
|
||||
}
|
||||
|
||||
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
|
||||
if (!ath10k_peer_stats_enabled(ar))
|
||||
return;
|
||||
|
||||
sinfo->rx_duration = arsta->rx_duration;
|
||||
sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -249,28 +293,6 @@ static const struct file_operations fops_delba = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_rx_duration(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
char buf[100];
|
||||
int len = 0;
|
||||
|
||||
len = scnprintf(buf, sizeof(buf),
|
||||
"%llu usecs\n", arsta->rx_duration);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_rx_duration = {
|
||||
.read = ath10k_dbg_sta_read_rx_duration,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir)
|
||||
{
|
||||
@ -279,6 +301,4 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
|
||||
debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
|
||||
debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
|
||||
debugfs_create_file("rx_duration", S_IRUGO, dir, sta,
|
||||
&fops_rx_duration);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
struct ath10k;
|
||||
|
@ -748,7 +748,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
|
||||
if (WARN_ON_ONCE(!arvif))
|
||||
return NULL;
|
||||
|
||||
if (WARN_ON_ONCE(ath10k_mac_vif_chan(arvif->vif, &def)))
|
||||
if (ath10k_mac_vif_chan(arvif->vif, &def))
|
||||
return NULL;
|
||||
|
||||
return def.chan;
|
||||
@ -2307,12 +2307,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_htt_rx_delba(ar, resp);
|
||||
break;
|
||||
case HTT_T2H_MSG_TYPE_PKTLOG: {
|
||||
struct ath10k_pktlog_hdr *hdr =
|
||||
(struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
|
||||
|
||||
trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
|
||||
sizeof(*hdr) +
|
||||
__le16_to_cpu(hdr->size));
|
||||
skb->len -
|
||||
offsetof(struct htt_resp,
|
||||
pktlog_msg.payload));
|
||||
break;
|
||||
}
|
||||
case HTT_T2H_MSG_TYPE_RX_FLUSH: {
|
||||
|
@ -49,7 +49,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_sta *arsta = (void *)txq->sta->drv_priv;
|
||||
struct ath10k_sta *arsta;
|
||||
struct ath10k_vif *arvif = (void *)txq->vif->drv_priv;
|
||||
unsigned long frame_cnt;
|
||||
unsigned long byte_cnt;
|
||||
@ -67,10 +67,12 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
|
||||
if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL)
|
||||
return;
|
||||
|
||||
if (txq->sta)
|
||||
if (txq->sta) {
|
||||
arsta = (void *)txq->sta->drv_priv;
|
||||
peer_id = arsta->peer_id;
|
||||
else
|
||||
} else {
|
||||
peer_id = arvif->peer_id;
|
||||
}
|
||||
|
||||
tid = txq->tid;
|
||||
bit = BIT(peer_id % 32);
|
||||
@ -388,6 +390,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
int size;
|
||||
|
||||
tasklet_kill(&htt->txrx_compl_task);
|
||||
|
||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
||||
idr_destroy(&htt->pending_tx);
|
||||
|
||||
@ -733,16 +737,18 @@ static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
||||
return ar->scan.vdev_id;
|
||||
else if (cb->vif)
|
||||
} else if (cb->vif) {
|
||||
arvif = (void *)cb->vif->drv_priv;
|
||||
return arvif->vdev_id;
|
||||
else if (ar->monitor_started)
|
||||
} else if (ar->monitor_started) {
|
||||
return ar->monitor_vdev_id;
|
||||
else
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth)
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "hw.h"
|
||||
|
||||
const struct ath10k_hw_regs qca988x_regs = {
|
||||
.rtc_state_cold_reset_mask = 0x00000400,
|
||||
.rtc_soc_base_address = 0x00004000,
|
||||
.rtc_wmac_base_address = 0x00005000,
|
||||
.soc_core_base_address = 0x00009000,
|
||||
@ -46,7 +45,6 @@ const struct ath10k_hw_regs qca988x_regs = {
|
||||
};
|
||||
|
||||
const struct ath10k_hw_regs qca6174_regs = {
|
||||
.rtc_state_cold_reset_mask = 0x00002000,
|
||||
.rtc_soc_base_address = 0x00000800,
|
||||
.rtc_wmac_base_address = 0x00001000,
|
||||
.soc_core_base_address = 0x0003a000,
|
||||
@ -73,7 +71,6 @@ const struct ath10k_hw_regs qca6174_regs = {
|
||||
};
|
||||
|
||||
const struct ath10k_hw_regs qca99x0_regs = {
|
||||
.rtc_state_cold_reset_mask = 0x00000400,
|
||||
.rtc_soc_base_address = 0x00080000,
|
||||
.rtc_wmac_base_address = 0x00000000,
|
||||
.soc_core_base_address = 0x00082000,
|
||||
@ -168,6 +165,15 @@ const struct ath10k_hw_values qca99x0_values = {
|
||||
.ce_desc_meta_data_lsb = 4,
|
||||
};
|
||||
|
||||
const struct ath10k_hw_values qca9888_values = {
|
||||
.rtc_state_val_on = 3,
|
||||
.ce_count = 12,
|
||||
.msi_assign_ce_max = 12,
|
||||
.num_target_ce_config_wlan = 10,
|
||||
.ce_desc_meta_data_mask = 0xFFF0,
|
||||
.ce_desc_meta_data_lsb = 4,
|
||||
};
|
||||
|
||||
const struct ath10k_hw_values qca4019_values = {
|
||||
.ce_count = 12,
|
||||
.num_target_ce_config_wlan = 10,
|
||||
@ -198,7 +204,8 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||
case ATH10K_HW_CC_WRAP_SHIFTED_EACH:
|
||||
if (cc < cc_prev)
|
||||
cc_fix = 0x7fffffff;
|
||||
else
|
||||
|
||||
if (rcc < rcc_prev)
|
||||
rcc_fix = 0x7fffffff;
|
||||
break;
|
||||
case ATH10K_HW_CC_WRAP_DISABLED:
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define QCA6164_2_1_DEVICE_ID (0x0041)
|
||||
#define QCA6174_2_1_DEVICE_ID (0x003e)
|
||||
#define QCA99X0_2_0_DEVICE_ID (0x0040)
|
||||
#define QCA9888_2_0_DEVICE_ID (0x0056)
|
||||
#define QCA9984_1_0_DEVICE_ID (0x0046)
|
||||
#define QCA9377_1_0_DEVICE_ID (0x0042)
|
||||
#define QCA9887_1_0_DEVICE_ID (0x0050)
|
||||
@ -108,6 +109,14 @@ enum qca9377_chip_id_rev {
|
||||
#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
/* QCA9888 2.0 defines */
|
||||
#define QCA9888_HW_2_0_DEV_VERSION 0x1000000
|
||||
#define QCA9888_HW_DEV_TYPE 0xc
|
||||
#define QCA9888_HW_2_0_CHIP_ID_REV 0x0
|
||||
#define QCA9888_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA9888/hw2.0"
|
||||
#define QCA9888_HW_2_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA9888_HW_2_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
/* QCA9377 1.0 definitions */
|
||||
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
|
||||
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||
@ -210,6 +219,7 @@ enum ath10k_hw_rev {
|
||||
ATH10K_HW_QCA988X,
|
||||
ATH10K_HW_QCA6174,
|
||||
ATH10K_HW_QCA99X0,
|
||||
ATH10K_HW_QCA9888,
|
||||
ATH10K_HW_QCA9984,
|
||||
ATH10K_HW_QCA9377,
|
||||
ATH10K_HW_QCA4019,
|
||||
@ -217,7 +227,6 @@ enum ath10k_hw_rev {
|
||||
};
|
||||
|
||||
struct ath10k_hw_regs {
|
||||
u32 rtc_state_cold_reset_mask;
|
||||
u32 rtc_soc_base_address;
|
||||
u32 rtc_wmac_base_address;
|
||||
u32 soc_core_base_address;
|
||||
@ -260,6 +269,7 @@ struct ath10k_hw_values {
|
||||
extern const struct ath10k_hw_values qca988x_values;
|
||||
extern const struct ath10k_hw_values qca6174_values;
|
||||
extern const struct ath10k_hw_values qca99x0_values;
|
||||
extern const struct ath10k_hw_values qca9888_values;
|
||||
extern const struct ath10k_hw_values qca4019_values;
|
||||
|
||||
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||
@ -269,6 +279,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||
#define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887)
|
||||
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
|
||||
#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
|
||||
#define QCA_REV_9888(ar) ((ar)->hw_rev == ATH10K_HW_QCA9888)
|
||||
#define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984)
|
||||
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
|
||||
#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
|
||||
@ -296,25 +307,6 @@ enum ath10k_mcast2ucast_mode {
|
||||
ATH10K_MCAST2UCAST_ENABLED = 1,
|
||||
};
|
||||
|
||||
struct ath10k_pktlog_hdr {
|
||||
__le16 flags;
|
||||
__le16 missed_cnt;
|
||||
__le16 log_type;
|
||||
__le16 size;
|
||||
__le32 timestamp;
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_pktlog_10_4_hdr {
|
||||
__le16 flags;
|
||||
__le16 missed_cnt;
|
||||
__le16 log_type;
|
||||
__le16 size;
|
||||
__le32 timestamp;
|
||||
__le32 type_specific_data;
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
enum ath10k_hw_rate_ofdm {
|
||||
ATH10K_HW_RATE_OFDM_48M = 0,
|
||||
ATH10K_HW_RATE_OFDM_24M,
|
||||
@ -535,7 +527,6 @@ enum ath10k_hw_cc_wraparound_type {
|
||||
/* as of IP3.7.1 */
|
||||
#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on
|
||||
|
||||
#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask
|
||||
#define RTC_STATE_V_LSB 0
|
||||
#define RTC_STATE_V_MASK 0x00000007
|
||||
#define RTC_STATE_ADDRESS 0x0000
|
||||
|
@ -802,6 +802,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
{
|
||||
struct ath10k_peer *peer, *tmp;
|
||||
int peer_id;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
@ -818,6 +819,17 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
ar->peer_map[peer_id] = NULL;
|
||||
}
|
||||
|
||||
/* Double check that peer is properly un-referenced from
|
||||
* the peer_map
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
|
||||
if (ar->peer_map[i] == peer) {
|
||||
ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %p idx %d)\n",
|
||||
peer->addr, peer, i);
|
||||
ar->peer_map[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
@ -828,6 +840,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
static void ath10k_peer_cleanup_all(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_peer *peer, *tmp;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
@ -836,6 +849,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++)
|
||||
ar->peer_map[i] = NULL;
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ar->num_peers = 0;
|
||||
@ -2939,7 +2956,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
|
||||
if (channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
ch->allow_ht = true;
|
||||
ch->allow_ht = true;
|
||||
|
||||
/* FIXME: when should we really allow VHT? */
|
||||
ch->allow_vht = true;
|
||||
@ -3675,17 +3692,18 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
||||
|
||||
static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
struct ath10k_txq *artxq;
|
||||
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
artxq = (void *)txq->drv_priv;
|
||||
INIT_LIST_HEAD(&artxq->list);
|
||||
}
|
||||
|
||||
static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ath10k_txq *artxq = (void *)txq->drv_priv;
|
||||
struct ath10k_txq *artxq;
|
||||
struct ath10k_skb_cb *cb;
|
||||
struct sk_buff *msdu;
|
||||
int msdu_id;
|
||||
@ -3693,6 +3711,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
artxq = (void *)txq->drv_priv;
|
||||
spin_lock_bh(&ar->txqs_lock);
|
||||
if (!list_empty(&artxq->list))
|
||||
list_del_init(&artxq->list);
|
||||
@ -4228,6 +4247,9 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
||||
mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
|
||||
}
|
||||
|
||||
if (ar->cfg_tx_chainmask <= 1)
|
||||
vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC;
|
||||
|
||||
vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
|
||||
vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
|
||||
|
||||
@ -4265,7 +4287,7 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
|
||||
ht_cap.cap |= smps;
|
||||
}
|
||||
|
||||
if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC)
|
||||
if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC && (ar->cfg_tx_chainmask > 1))
|
||||
ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
|
||||
|
||||
if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) {
|
||||
@ -5979,9 +6001,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
continue;
|
||||
|
||||
if (peer->sta == sta) {
|
||||
ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
ath10k_warn(ar, "found sta peer %pM (ptr %p id %d) entry on vdev %i after it was supposedly removed\n",
|
||||
sta->addr, peer, i, arvif->vdev_id);
|
||||
peer->sta = NULL;
|
||||
|
||||
/* Clean up the peer object as well since we
|
||||
* must have failed to do this above.
|
||||
*/
|
||||
list_del(&peer->list);
|
||||
ar->peer_map[i] = NULL;
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
@ -7406,6 +7436,7 @@ static const struct ieee80211_ops ath10k_ops = {
|
||||
#endif
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
.sta_add_debugfs = ath10k_sta_add_debugfs,
|
||||
.sta_statistics = ath10k_sta_statistics,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -56,6 +56,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
|
||||
{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA9888_2_0_DEVICE_ID) }, /* PCI-E QCA9888 V2 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */
|
||||
@ -85,6 +86,8 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
|
||||
|
||||
{ QCA9984_1_0_DEVICE_ID, QCA9984_HW_1_0_CHIP_ID_REV },
|
||||
|
||||
{ QCA9888_2_0_DEVICE_ID, QCA9888_HW_2_0_CHIP_ID_REV },
|
||||
|
||||
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
|
||||
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV },
|
||||
|
||||
@ -850,6 +853,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
|
||||
CORE_CTRL_ADDRESS) &
|
||||
0x7ff) << 21;
|
||||
break;
|
||||
case ATH10K_HW_QCA9888:
|
||||
case ATH10K_HW_QCA99X0:
|
||||
case ATH10K_HW_QCA9984:
|
||||
case ATH10K_HW_QCA4019:
|
||||
@ -1583,6 +1587,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
|
||||
break;
|
||||
case ATH10K_HW_QCA99X0:
|
||||
case ATH10K_HW_QCA9984:
|
||||
case ATH10K_HW_QCA9888:
|
||||
case ATH10K_HW_QCA4019:
|
||||
/* TODO: Find appropriate register configuration for QCA99X0
|
||||
* to mask irq/MSI.
|
||||
@ -1608,6 +1613,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
|
||||
break;
|
||||
case ATH10K_HW_QCA99X0:
|
||||
case ATH10K_HW_QCA9984:
|
||||
case ATH10K_HW_QCA9888:
|
||||
case ATH10K_HW_QCA4019:
|
||||
/* TODO: Find appropriate register configuration for QCA99X0
|
||||
* to unmask irq/MSI.
|
||||
@ -1948,6 +1954,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
|
||||
switch (ar_pci->pdev->device) {
|
||||
case QCA988X_2_0_DEVICE_ID:
|
||||
case QCA99X0_2_0_DEVICE_ID:
|
||||
case QCA9888_2_0_DEVICE_ID:
|
||||
case QCA9984_1_0_DEVICE_ID:
|
||||
case QCA9887_1_0_DEVICE_ID:
|
||||
return 1;
|
||||
@ -2216,6 +2223,14 @@ static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
|
||||
}
|
||||
|
||||
static bool ath10k_pci_has_device_gone(struct ath10k *ar)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
|
||||
return (val == 0xffffffff);
|
||||
}
|
||||
|
||||
/* this function effectively clears target memory controller assert line */
|
||||
static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
|
||||
{
|
||||
@ -2748,6 +2763,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
if (ath10k_pci_has_device_gone(ar))
|
||||
return IRQ_NONE;
|
||||
|
||||
ret = ath10k_pci_force_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
|
||||
@ -3169,6 +3187,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
|
||||
pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
|
||||
break;
|
||||
case QCA9888_2_0_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA9888;
|
||||
pci_ps = false;
|
||||
pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
|
||||
pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
|
||||
break;
|
||||
case QCA9377_1_0_DEVICE_ID:
|
||||
hw_rev = ATH10K_HW_QCA9377;
|
||||
pci_ps = true;
|
||||
|
@ -101,9 +101,9 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
|
||||
break;
|
||||
case 80:
|
||||
/* TODO: As experiments with an analogue sender and various
|
||||
* configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
|
||||
* configurations (fft-sizes of 64/128/256 and 20/40/80 Mhz)
|
||||
* show, the particular configuration of 80 MHz/64 bins does
|
||||
* not match with the other smaples at all. Until the reason
|
||||
* not match with the other samples at all. Until the reason
|
||||
* for that is found, don't report these samples.
|
||||
*/
|
||||
if (bin_len == 64)
|
||||
|
@ -81,10 +81,11 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
|
||||
skb_cb = ATH10K_SKB_CB(msdu);
|
||||
txq = skb_cb->txq;
|
||||
artxq = (void *)txq->drv_priv;
|
||||
|
||||
if (txq)
|
||||
if (txq) {
|
||||
artxq = (void *)txq->drv_priv;
|
||||
artxq->num_fw_queued--;
|
||||
}
|
||||
|
||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
@ -216,6 +217,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
|
||||
ev->vdev_id, ev->addr, ev->peer_id);
|
||||
|
||||
WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer));
|
||||
ar->peer_map[ev->peer_id] = peer;
|
||||
set_bit(ev->peer_id, peer->peer_ids);
|
||||
exit:
|
||||
|
@ -1826,7 +1826,7 @@ static struct sk_buff *
|
||||
ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
||||
{
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
|
||||
struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
|
||||
struct ath10k_vif *arvif;
|
||||
struct wmi_mgmt_tx_cmd *cmd;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
@ -1838,10 +1838,12 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
||||
hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
if (cb->vif)
|
||||
if (cb->vif) {
|
||||
arvif = (void *)cb->vif->drv_priv;
|
||||
vdev_id = arvif->vdev_id;
|
||||
else
|
||||
} else {
|
||||
vdev_id = 0;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -2924,6 +2926,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
u32 num_pdev_ext_stats;
|
||||
u32 num_vdev_stats;
|
||||
u32 num_peer_stats;
|
||||
u32 num_bcnflt_stats;
|
||||
u32 stats_id;
|
||||
int i;
|
||||
|
||||
@ -2934,6 +2937,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
|
||||
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
|
||||
num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats);
|
||||
stats_id = __le32_to_cpu(ev->stats_id);
|
||||
|
||||
for (i = 0; i < num_pdev_stats; i++) {
|
||||
@ -2974,32 +2978,57 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
|
||||
/* fw doesn't implement vdev stats */
|
||||
|
||||
for (i = 0; i < num_peer_stats; i++) {
|
||||
const struct wmi_10_4_peer_extd_stats *src;
|
||||
const struct wmi_10_4_peer_stats *src;
|
||||
struct ath10k_fw_stats_peer *dst;
|
||||
int stats_len;
|
||||
bool extd_peer_stats = !!(stats_id & WMI_10_4_STAT_PEER_EXTD);
|
||||
|
||||
if (extd_peer_stats)
|
||||
stats_len = sizeof(struct wmi_10_4_peer_extd_stats);
|
||||
else
|
||||
stats_len = sizeof(struct wmi_10_4_peer_stats);
|
||||
|
||||
src = (void *)skb->data;
|
||||
if (!skb_pull(skb, stats_len))
|
||||
if (!skb_pull(skb, sizeof(*src)))
|
||||
return -EPROTO;
|
||||
|
||||
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
|
||||
if (!dst)
|
||||
continue;
|
||||
|
||||
ath10k_wmi_10_4_pull_peer_stats(&src->common, dst);
|
||||
/* FIXME: expose 10.4 specific values */
|
||||
if (extd_peer_stats)
|
||||
dst->rx_duration = __le32_to_cpu(src->rx_duration);
|
||||
|
||||
ath10k_wmi_10_4_pull_peer_stats(src, dst);
|
||||
list_add_tail(&dst->list, &stats->peers);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_bcnflt_stats; i++) {
|
||||
const struct wmi_10_4_bss_bcn_filter_stats *src;
|
||||
|
||||
src = (void *)skb->data;
|
||||
if (!skb_pull(skb, sizeof(*src)))
|
||||
return -EPROTO;
|
||||
|
||||
/* FIXME: expose values to userspace
|
||||
*
|
||||
* Note: Even though this loop seems to do nothing it is
|
||||
* required to parse following sub-structures properly.
|
||||
*/
|
||||
}
|
||||
|
||||
if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0)
|
||||
return 0;
|
||||
|
||||
stats->extended = true;
|
||||
|
||||
for (i = 0; i < num_peer_stats; i++) {
|
||||
const struct wmi_10_4_peer_extd_stats *src;
|
||||
struct ath10k_fw_extd_stats_peer *dst;
|
||||
|
||||
src = (void *)skb->data;
|
||||
if (!skb_pull(skb, sizeof(*src)))
|
||||
return -EPROTO;
|
||||
|
||||
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
|
||||
if (!dst)
|
||||
continue;
|
||||
|
||||
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
|
||||
dst->rx_duration = __le32_to_cpu(src->rx_duration);
|
||||
list_add_tail(&dst->list, &stats->peers_extd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5257,6 +5286,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
case WMI_10_4_PEER_STA_KICKOUT_EVENTID:
|
||||
ath10k_wmi_event_peer_sta_kickout(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_ROAM_EVENTID:
|
||||
ath10k_wmi_event_roam(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_HOST_SWBA_EVENTID:
|
||||
ath10k_wmi_event_host_swba(ar, skb);
|
||||
break;
|
||||
@ -7903,6 +7935,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
||||
.pull_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev,
|
||||
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
|
||||
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
|
||||
.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
|
||||
.get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme,
|
||||
|
||||
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
|
||||
|
@ -4340,7 +4340,6 @@ struct wmi_10_4_peer_stats {
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_peer_extd_stats {
|
||||
struct wmi_10_4_peer_stats common;
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
__le32 inactive_time;
|
||||
__le32 peer_chain_rssi;
|
||||
@ -4348,6 +4347,19 @@ struct wmi_10_4_peer_extd_stats {
|
||||
__le32 reserved[10];
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_bss_bcn_stats {
|
||||
__le32 vdev_id;
|
||||
__le32 bss_bcns_dropped;
|
||||
__le32 bss_bcn_delivered;
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_4_bss_bcn_filter_stats {
|
||||
__le32 bcns_dropped;
|
||||
__le32 bcns_delivered;
|
||||
__le32 active_filters;
|
||||
struct wmi_10_4_bss_bcn_stats bss_stats;
|
||||
} __packed;
|
||||
|
||||
struct wmi_10_2_pdev_ext_stats {
|
||||
__le32 rx_rssi_comb;
|
||||
__le32 rx_rssi[4];
|
||||
|
@ -4175,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
|
||||
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
|
||||
ar9003_hw_internal_regulator_apply(ah);
|
||||
ar9003_hw_apply_tuning_caps(ah);
|
||||
ar9003_hw_apply_minccapwr_thresh(ah, chan);
|
||||
ar9003_hw_apply_minccapwr_thresh(ah, is2ghz);
|
||||
ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
|
||||
ar9003_hw_thermometer_apply(ah);
|
||||
ar9003_hw_thermo_cal_apply(ah);
|
||||
|
@ -637,6 +637,8 @@ struct ath9k_vif_iter_data {
|
||||
int nwds; /* number of WDS vifs */
|
||||
int nadhocs; /* number of adhoc vifs */
|
||||
int nocbs; /* number of OCB vifs */
|
||||
int nbcnvifs; /* number of beaconing vifs */
|
||||
struct ieee80211_vif *primary_beacon_vif;
|
||||
struct ieee80211_vif *primary_sta;
|
||||
};
|
||||
|
||||
@ -685,10 +687,11 @@ struct ath_beacon {
|
||||
};
|
||||
|
||||
void ath9k_beacon_tasklet(unsigned long data);
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
u32 changed);
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
|
||||
bool beacons);
|
||||
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc);
|
||||
void ath9k_set_beacon(struct ath_softc *sc);
|
||||
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath9k_csa_update(struct ath_softc *sc);
|
||||
|
@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
|
||||
txq = sc->tx.txq_map[IEEE80211_AC_BE];
|
||||
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
|
||||
qi.tqi_aifs = qi_be.tqi_aifs;
|
||||
if (ah->slottime == ATH9K_SLOT_TIME_20)
|
||||
if (ah->slottime == 20)
|
||||
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
|
||||
else
|
||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
||||
@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
}
|
||||
|
||||
sc->beacon.bslot[avp->av_bslot] = vif;
|
||||
sc->nbcnvifs++;
|
||||
|
||||
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
|
||||
avp->av_bslot);
|
||||
@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_buf *bf = avp->av_bcbuf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
||||
|
||||
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
|
||||
avp->av_bslot);
|
||||
|
||||
tasklet_disable(&sc->bcon_tasklet);
|
||||
|
||||
cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
||||
|
||||
if (bf && bf->bf_mpdu) {
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
||||
@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
|
||||
avp->av_bcbuf = NULL;
|
||||
sc->beacon.bslot[avp->av_bslot] = NULL;
|
||||
sc->nbcnvifs--;
|
||||
list_add_tail(&bf->list, &sc->beacon.bbuf);
|
||||
|
||||
tasklet_enable(&sc->bcon_tasklet);
|
||||
}
|
||||
|
||||
void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_vif *avp;
|
||||
s64 tsfadjust;
|
||||
u32 offset;
|
||||
int first_slot = ATH_BCBUF;
|
||||
int slot;
|
||||
|
||||
tasklet_disable(&sc->bcon_tasklet);
|
||||
|
||||
/* Find first taken slot. */
|
||||
for (slot = 0; slot < ATH_BCBUF; slot++) {
|
||||
if (sc->beacon.bslot[slot]) {
|
||||
first_slot = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_slot == 0)
|
||||
goto out;
|
||||
|
||||
/* Re-enumarate all slots, moving them forward. */
|
||||
for (slot = 0; slot < ATH_BCBUF; slot++) {
|
||||
if (slot + first_slot < ATH_BCBUF) {
|
||||
vif = sc->beacon.bslot[slot + first_slot];
|
||||
sc->beacon.bslot[slot] = vif;
|
||||
|
||||
if (vif) {
|
||||
avp = (void *)vif->drv_priv;
|
||||
avp->av_bslot = slot;
|
||||
}
|
||||
} else {
|
||||
sc->beacon.bslot[slot] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vif = sc->beacon.bslot[0];
|
||||
if (WARN_ON(!vif))
|
||||
goto out;
|
||||
|
||||
/* Get the tsf_adjust value for the new first slot. */
|
||||
avp = (void *)vif->drv_priv;
|
||||
tsfadjust = le64_to_cpu(avp->tsf_adjust);
|
||||
|
||||
ath_dbg(common, CONFIG,
|
||||
"Adjusting global TSF after beacon slot reassignment: %lld\n",
|
||||
(signed long long)tsfadjust);
|
||||
|
||||
/* Modify TSF as required and update the HW. */
|
||||
avp->chanctx->tsf_val += tsfadjust;
|
||||
if (sc->cur_chan == avp->chanctx) {
|
||||
offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
|
||||
ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset);
|
||||
}
|
||||
|
||||
/* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
|
||||
|
||||
out:
|
||||
tasklet_enable(&sc->bcon_tasklet);
|
||||
}
|
||||
|
||||
static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
@ -274,22 +331,33 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
||||
return slot;
|
||||
}
|
||||
|
||||
static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
static void ath9k_set_tsfadjust(struct ath_softc *sc,
|
||||
struct ath_beacon_config *cur_conf)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
|
||||
u32 tsfadjust;
|
||||
s64 tsfadjust;
|
||||
int slot;
|
||||
|
||||
if (avp->av_bslot == 0)
|
||||
return;
|
||||
for (slot = 0; slot < ATH_BCBUF; slot++) {
|
||||
struct ath_vif *avp;
|
||||
|
||||
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
|
||||
tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
||||
avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
||||
if (!sc->beacon.bslot[slot])
|
||||
continue;
|
||||
|
||||
ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
|
||||
(unsigned long long)tsfadjust, avp->av_bslot);
|
||||
avp = (void *)sc->beacon.bslot[slot]->drv_priv;
|
||||
|
||||
/* tsf_adjust is added to the TSF value. We send out the
|
||||
* beacon late, so need to adjust the TSF starting point to be
|
||||
* later in time (i.e. the theoretical first beacon has a TSF
|
||||
* of 0 after correction).
|
||||
*/
|
||||
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
|
||||
tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
||||
avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
||||
|
||||
ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
|
||||
(signed long long)tsfadjust, avp->av_bslot);
|
||||
}
|
||||
}
|
||||
|
||||
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
@ -443,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
* Both nexttbtt and intval have to be in usecs.
|
||||
*/
|
||||
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
|
||||
u32 intval, bool reset_tsf)
|
||||
u32 intval)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
if (reset_tsf)
|
||||
ath9k_hw_reset_tsf(ah);
|
||||
ath9k_beaconq_config(sc);
|
||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
static void ath9k_beacon_stop(struct ath_softc *sc)
|
||||
{
|
||||
ath9k_hw_disable_interrupts(sc->sc_ah);
|
||||
sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah);
|
||||
ath9k_hw_enable_interrupts(sc->sc_ah);
|
||||
}
|
||||
|
||||
/*
|
||||
* For multi-bss ap support beacons are either staggered evenly over N slots or
|
||||
* burst together. For the former arrange for the SWBA to be delivered for each
|
||||
@ -468,7 +544,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
|
||||
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);
|
||||
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
|
||||
}
|
||||
|
||||
static void ath9k_beacon_config_sta(struct ath_hw *ah,
|
||||
@ -497,7 +573,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
|
||||
|
||||
ath9k_cmn_beacon_config_adhoc(ah, conf);
|
||||
|
||||
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);
|
||||
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
|
||||
|
||||
/*
|
||||
* Set the global 'beacon has been configured' flag for the
|
||||
@ -507,44 +583,6 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
|
||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
}
|
||||
|
||||
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
if (ath9k_is_chanctx_enabled()) {
|
||||
/*
|
||||
* If the VIF is not present in the current channel context,
|
||||
* then we can't do the usual opmode checks. Allow the
|
||||
* beacon config for the VIF to be updated in this case and
|
||||
* return immediately.
|
||||
*/
|
||||
if (sc->cur_chan != avp->chanctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if (vif->type != NL80211_IFTYPE_AP) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"An AP interface is already present !\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
if ((vif->type == NL80211_IFTYPE_STATION) &&
|
||||
test_bit(ATH_OP_BEACONS, &common->op_flags) &&
|
||||
vif != sc->cur_chan->primary_sta) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
||||
struct ath_chanctx *ctx,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
@ -580,87 +618,79 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
||||
if (cur_conf->dtim_period == 0)
|
||||
cur_conf->dtim_period = 1;
|
||||
|
||||
ath9k_set_tsfadjust(sc, cur_conf);
|
||||
}
|
||||
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
u32 changed)
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
|
||||
bool beacons)
|
||||
{
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp;
|
||||
struct ath_chanctx *ctx;
|
||||
struct ath_beacon_config *cur_conf;
|
||||
unsigned long flags;
|
||||
bool enabled;
|
||||
bool skip_beacon = false;
|
||||
|
||||
if (!ctx)
|
||||
if (!beacons) {
|
||||
clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
ath9k_beacon_stop(sc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WARN_ON(!main_vif))
|
||||
return;
|
||||
|
||||
cur_conf = &avp->chanctx->beacon;
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
ath9k_set_tsfadjust(sc, vif);
|
||||
avp = (void *)main_vif->drv_priv;
|
||||
ctx = avp->chanctx;
|
||||
cur_conf = &ctx->beacon;
|
||||
enabled = cur_conf->enable_beacon;
|
||||
cur_conf->enable_beacon = beacons;
|
||||
|
||||
if (!ath9k_allow_beacon_config(sc, vif))
|
||||
return;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
if (ctx != sc->cur_chan)
|
||||
return;
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
|
||||
|
||||
ath9k_set_beacon(sc);
|
||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take care of multiple interfaces when
|
||||
* enabling/disabling SWBA.
|
||||
*/
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
bool enabled = cur_conf->enable_beacon;
|
||||
|
||||
if (!bss_conf->enable_beacon) {
|
||||
cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
||||
} else {
|
||||
cur_conf->enable_beacon |= BIT(avp->av_bslot);
|
||||
if (!enabled)
|
||||
ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx != sc->cur_chan)
|
||||
return;
|
||||
/* Update the beacon configuration. */
|
||||
ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
|
||||
|
||||
/*
|
||||
* Configure the HW beacon registers only when we have a valid
|
||||
* beacon interval.
|
||||
*/
|
||||
if (cur_conf->beacon_interval) {
|
||||
/*
|
||||
* If we are joining an existing IBSS network, start beaconing
|
||||
* only after a TSF-sync has taken place. Ensure that this
|
||||
* happens by setting the appropriate flags.
|
||||
/* Special case to sync the TSF when joining an existing IBSS.
|
||||
* This is only done if no AP interface is active.
|
||||
* Note that mac80211 always resets the TSF when creating a new
|
||||
* IBSS interface.
|
||||
*/
|
||||
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
|
||||
bss_conf->enable_beacon) {
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
|
||||
!enabled && beacons && !main_vif->bss_conf.ibss_creator) {
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
skip_beacon = true;
|
||||
} else {
|
||||
ath9k_set_beacon(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
|
||||
* here, it is done in ath9k_beacon_config_adhoc().
|
||||
*/
|
||||
if (cur_conf->enable_beacon && !skip_beacon)
|
||||
if (beacons && !skip_beacon) {
|
||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
else
|
||||
ath9k_set_beacon(sc);
|
||||
} else {
|
||||
clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
ath9k_beacon_stop(sc);
|
||||
}
|
||||
} else {
|
||||
clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
ath9k_beacon_stop(sc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@
|
||||
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
|
||||
|
||||
struct ath_beacon_config {
|
||||
struct ieee80211_vif *main_vif;
|
||||
int beacon_interval;
|
||||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
|
@ -280,7 +280,7 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
|
||||
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
|
||||
{
|
||||
/* ackto = slottime + sifs + air delay */
|
||||
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
|
||||
u32 ackto = 9 + 16 + 64;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
|
||||
an->ackto = ackto;
|
||||
@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
|
||||
void ath_dynack_reset(struct ath_hw *ah)
|
||||
{
|
||||
/* ackto = slottime + sifs + air delay */
|
||||
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
|
||||
u32 ackto = 9 + 16 + 64;
|
||||
struct ath_dynack *da = &ah->dynack;
|
||||
|
||||
da->lto = jiffies;
|
||||
|
@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
|
||||
* Long slot time : 2x cwmin
|
||||
* Short slot time : 4x cwmin
|
||||
*/
|
||||
if (ah->slottime == ATH9K_SLOT_TIME_20)
|
||||
if (ah->slottime == 20)
|
||||
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
|
||||
else
|
||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
||||
|
@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
||||
|
||||
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
|
||||
priv->beacon.bslot[i] = NULL;
|
||||
priv->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
priv->beacon.slottime = 9;
|
||||
|
||||
ath9k_cmn_init_channels_rates(common);
|
||||
ath9k_cmn_init_crypto(ah);
|
||||
|
@ -454,7 +454,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
||||
if (AR_SREV_9100(ah))
|
||||
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
|
||||
|
||||
ah->slottime = ATH9K_SLOT_TIME_9;
|
||||
ah->slottime = 9;
|
||||
ah->globaltxtimeout = (u32) -1;
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
ah->htc_reset_init = true;
|
||||
@ -471,33 +471,34 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
||||
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
|
||||
}
|
||||
|
||||
static int ath9k_hw_init_macaddr(struct ath_hw *ah)
|
||||
static void ath9k_hw_init_macaddr(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 sum;
|
||||
int i;
|
||||
u16 eeval;
|
||||
static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
|
||||
|
||||
sum = 0;
|
||||
/* MAC address may already be loaded via ath9k_platform_data */
|
||||
if (is_valid_ether_addr(common->macaddr))
|
||||
return;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]);
|
||||
sum += eeval;
|
||||
common->macaddr[2 * i] = eeval >> 8;
|
||||
common->macaddr[2 * i + 1] = eeval & 0xff;
|
||||
}
|
||||
if (!is_valid_ether_addr(common->macaddr)) {
|
||||
ath_err(common,
|
||||
"eeprom contains invalid mac address: %pM\n",
|
||||
common->macaddr);
|
||||
|
||||
random_ether_addr(common->macaddr);
|
||||
ath_err(common,
|
||||
"random mac address will be used: %pM\n",
|
||||
common->macaddr);
|
||||
}
|
||||
if (is_valid_ether_addr(common->macaddr))
|
||||
return;
|
||||
|
||||
return 0;
|
||||
ath_err(common, "eeprom contains invalid mac address: %pM\n",
|
||||
common->macaddr);
|
||||
|
||||
random_ether_addr(common->macaddr);
|
||||
ath_err(common, "random mac address will be used: %pM\n",
|
||||
common->macaddr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ath9k_hw_post_init(struct ath_hw *ah)
|
||||
@ -636,12 +637,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = ath9k_hw_init_macaddr(ah);
|
||||
if (r) {
|
||||
ath_err(common, "Failed to initialize MAC address\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
ath9k_hw_init_macaddr(ah);
|
||||
ath9k_hw_init_hang_checks(ah);
|
||||
|
||||
common->state = ATH_HW_INITIALIZED;
|
||||
@ -1832,8 +1828,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
u32 saveLedState;
|
||||
u32 saveDefAntenna;
|
||||
u32 macStaId1;
|
||||
struct timespec tsf_ts;
|
||||
u32 tsf_offset;
|
||||
u64 tsf = 0;
|
||||
s64 usec = 0;
|
||||
int r;
|
||||
bool start_mci_reset = false;
|
||||
bool save_fullsleep = ah->chip_fullsleep;
|
||||
@ -1877,8 +1874,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
|
||||
|
||||
/* Save TSF before chip reset, a cold reset clears it */
|
||||
getrawmonotonic(&tsf_ts);
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
usec = ktime_to_us(ktime_get_raw());
|
||||
|
||||
saveLedState = REG_READ(ah, AR_CFG_LED) &
|
||||
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
|
||||
@ -1911,8 +1908,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
}
|
||||
|
||||
/* Restore TSF */
|
||||
usec = ktime_to_us(ktime_get_raw()) - usec;
|
||||
ath9k_hw_settsf64(ah, tsf + usec);
|
||||
tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
|
||||
ath9k_hw_settsf64(ah, tsf + tsf_offset);
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah))
|
||||
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
|
||||
@ -1932,12 +1929,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
/*
|
||||
* Some AR91xx SoC devices frequently fail to accept TSF writes
|
||||
* right after the chip reset. When that happens, write a new
|
||||
* value after the initvals have been applied, with an offset
|
||||
* based on measured time difference
|
||||
* value after the initvals have been applied.
|
||||
*/
|
||||
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
|
||||
tsf += 1500;
|
||||
ath9k_hw_settsf64(ah, tsf);
|
||||
tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
|
||||
ath9k_hw_settsf64(ah, tsf + tsf_offset);
|
||||
}
|
||||
|
||||
ath9k_hw_init_mfp(ah);
|
||||
|
@ -372,7 +372,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
||||
|
||||
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
||||
sc->beacon.slottime = 9;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
|
||||
sc->beacon.bslot[i] = NULL;
|
||||
@ -512,31 +512,52 @@ static void ath9k_eeprom_release(struct ath_softc *sc)
|
||||
release_firmware(sc->sc_ah->eeprom_blob);
|
||||
}
|
||||
|
||||
static int ath9k_init_soc_platform(struct ath_softc *sc)
|
||||
static int ath9k_init_platform(struct ath_softc *sc)
|
||||
{
|
||||
struct ath9k_platform_data *pdata = sc->dev->platform_data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
int ret = 0;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int ret;
|
||||
|
||||
if (!pdata)
|
||||
return 0;
|
||||
|
||||
if (!pdata->use_eeprom) {
|
||||
ah->ah_flags &= ~AH_USE_EEPROM;
|
||||
ah->gpio_mask = pdata->gpio_mask;
|
||||
ah->gpio_val = pdata->gpio_val;
|
||||
ah->led_pin = pdata->led_pin;
|
||||
ah->is_clk_25mhz = pdata->is_clk_25mhz;
|
||||
ah->get_mac_revision = pdata->get_mac_revision;
|
||||
ah->external_reset = pdata->external_reset;
|
||||
ah->disable_2ghz = pdata->disable_2ghz;
|
||||
ah->disable_5ghz = pdata->disable_5ghz;
|
||||
|
||||
if (!pdata->endian_check)
|
||||
ah->ah_flags |= AH_NO_EEP_SWAP;
|
||||
}
|
||||
|
||||
if (pdata->eeprom_name) {
|
||||
ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata->led_active_high)
|
||||
ah->config.led_active_high = true;
|
||||
|
||||
if (pdata->tx_gain_buffalo)
|
||||
ah->config.tx_gain_buffalo = true;
|
||||
|
||||
return ret;
|
||||
if (pdata->macaddr)
|
||||
ether_addr_copy(common->macaddr, pdata->macaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ath9k_platform_data *pdata = sc->dev->platform_data;
|
||||
struct ath_hw *ah = NULL;
|
||||
struct ath9k_hw_capabilities *pCap;
|
||||
struct ath_common *common;
|
||||
@ -550,6 +571,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
ah->dev = sc->dev;
|
||||
ah->hw = sc->hw;
|
||||
ah->hw_version.devid = devid;
|
||||
ah->ah_flags |= AH_USE_EEPROM;
|
||||
ah->led_pin = -1;
|
||||
ah->reg_ops.read = ath9k_ioread32;
|
||||
ah->reg_ops.multi_read = ath9k_multi_ioread32;
|
||||
ah->reg_ops.write = ath9k_iowrite32;
|
||||
@ -569,22 +592,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
if (!ath9k_is_chanctx_enabled())
|
||||
sc->cur_chan->hw_queue_base = 0;
|
||||
|
||||
if (!pdata || pdata->use_eeprom) {
|
||||
ah->ah_flags |= AH_USE_EEPROM;
|
||||
sc->sc_ah->led_pin = -1;
|
||||
} else {
|
||||
sc->sc_ah->gpio_mask = pdata->gpio_mask;
|
||||
sc->sc_ah->gpio_val = pdata->gpio_val;
|
||||
sc->sc_ah->led_pin = pdata->led_pin;
|
||||
ah->is_clk_25mhz = pdata->is_clk_25mhz;
|
||||
ah->get_mac_revision = pdata->get_mac_revision;
|
||||
ah->external_reset = pdata->external_reset;
|
||||
ah->disable_2ghz = pdata->disable_2ghz;
|
||||
ah->disable_5ghz = pdata->disable_5ghz;
|
||||
if (!pdata->endian_check)
|
||||
ah->ah_flags |= AH_NO_EEP_SWAP;
|
||||
}
|
||||
|
||||
common->ops = &ah->reg_ops;
|
||||
common->bus_ops = bus_ops;
|
||||
common->ps_ops = &ath9k_ps_ops;
|
||||
@ -600,7 +607,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
*/
|
||||
ath9k_init_pcoem_platform(sc);
|
||||
|
||||
ret = ath9k_init_soc_platform(sc);
|
||||
ret = ath9k_init_platform(sc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -646,9 +653,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
if (ret)
|
||||
goto err_hw;
|
||||
|
||||
if (pdata && pdata->macaddr)
|
||||
memcpy(common->macaddr, pdata->macaddr, ETH_ALEN);
|
||||
|
||||
ret = ath9k_init_queues(sc);
|
||||
if (ret)
|
||||
goto err_queues;
|
||||
|
@ -65,10 +65,6 @@
|
||||
#define INIT_SSH_RETRY 32
|
||||
#define INIT_SLG_RETRY 32
|
||||
|
||||
#define ATH9K_SLOT_TIME_6 6
|
||||
#define ATH9K_SLOT_TIME_9 9
|
||||
#define ATH9K_SLOT_TIME_20 20
|
||||
|
||||
#define ATH9K_TXERR_XRETRY 0x01
|
||||
#define ATH9K_TXERR_FILT 0x02
|
||||
#define ATH9K_TXERR_FIFO 0x04
|
||||
|
@ -910,6 +910,22 @@ static bool ath9k_uses_beacons(int type)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
/* Use the first (configured) interface, but prefering AP interfaces. */
|
||||
if (!iter_data->primary_beacon_vif) {
|
||||
iter_data->primary_beacon_vif = vif;
|
||||
} else {
|
||||
if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP &&
|
||||
vif->type == NL80211_IFTYPE_AP)
|
||||
iter_data->primary_beacon_vif = vif;
|
||||
}
|
||||
|
||||
iter_data->beacons = true;
|
||||
iter_data->nbcnvifs += 1;
|
||||
}
|
||||
|
||||
static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
|
||||
u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
@ -926,11 +942,13 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
|
||||
}
|
||||
|
||||
if (!vif->bss_conf.use_short_slot)
|
||||
iter_data->slottime = ATH9K_SLOT_TIME_20;
|
||||
iter_data->slottime = 20;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
iter_data->naps++;
|
||||
if (vif->bss_conf.enable_beacon)
|
||||
ath9k_vif_iter_set_beacon(iter_data, vif);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
iter_data->nstations++;
|
||||
@ -943,12 +961,12 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
iter_data->nadhocs++;
|
||||
if (vif->bss_conf.enable_beacon)
|
||||
iter_data->beacons = true;
|
||||
ath9k_vif_iter_set_beacon(iter_data, vif);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
iter_data->nmeshes++;
|
||||
if (vif->bss_conf.enable_beacon)
|
||||
iter_data->beacons = true;
|
||||
ath9k_vif_iter_set_beacon(iter_data, vif);
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
iter_data->nwds++;
|
||||
@ -999,7 +1017,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
|
||||
*/
|
||||
memset(iter_data, 0, sizeof(*iter_data));
|
||||
eth_broadcast_addr(iter_data->mask);
|
||||
iter_data->slottime = ATH9K_SLOT_TIME_9;
|
||||
iter_data->slottime = 9;
|
||||
|
||||
list_for_each_entry(avp, &ctx->vifs, list)
|
||||
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
|
||||
@ -1061,7 +1079,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc)
|
||||
ah->opmode = vif->type;
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
ah->imask &= ~ATH9K_INT_TSFOOR;
|
||||
ah->slottime = ATH9K_SLOT_TIME_9;
|
||||
ah->slottime = 9;
|
||||
|
||||
ath_hw_setbssidmask(common);
|
||||
ath9k_hw_setopmode(ah);
|
||||
@ -1081,7 +1099,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
struct ath_beacon_config *cur_conf;
|
||||
|
||||
ath_chanctx_check_active(sc, ctx);
|
||||
|
||||
@ -1103,13 +1120,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
|
||||
ath_hw_setbssidmask(common);
|
||||
|
||||
if (iter_data.naps > 0) {
|
||||
cur_conf = &ctx->beacon;
|
||||
ath9k_hw_set_tsfadjust(ah, true);
|
||||
ah->opmode = NL80211_IFTYPE_AP;
|
||||
if (cur_conf->enable_beacon)
|
||||
iter_data.beacons = true;
|
||||
} else {
|
||||
ath9k_hw_set_tsfadjust(ah, false);
|
||||
if (iter_data.beacons)
|
||||
ath9k_beacon_ensure_primary_slot(sc);
|
||||
|
||||
if (iter_data.nmeshes)
|
||||
ah->opmode = NL80211_IFTYPE_MESH_POINT;
|
||||
@ -1134,7 +1150,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
|
||||
ctx->switch_after_beacon = true;
|
||||
}
|
||||
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
if (ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
bool changed = (iter_data.primary_sta != ctx->primary_sta);
|
||||
|
||||
@ -1151,16 +1166,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
|
||||
if (ath9k_hw_mci_is_enabled(sc->sc_ah))
|
||||
ath9k_mci_update_wlan_channels(sc, true);
|
||||
}
|
||||
} else if (iter_data.beacons) {
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
}
|
||||
sc->nbcnvifs = iter_data.nbcnvifs;
|
||||
ath9k_beacon_config(sc, iter_data.primary_beacon_vif,
|
||||
iter_data.beacons);
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
|
||||
if (iter_data.beacons)
|
||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
else
|
||||
clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
||||
|
||||
if (ah->slottime != iter_data.slottime) {
|
||||
ah->slottime = iter_data.slottime;
|
||||
ath9k_hw_init_global_settings(ah);
|
||||
@ -1777,9 +1788,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
|
||||
(changed & BSS_CHANGED_BEACON_INT) ||
|
||||
(changed & BSS_CHANGED_BEACON_INFO)) {
|
||||
ath9k_beacon_config(sc, vif, changed);
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED)
|
||||
ath9k_calculate_summary_state(sc, avp->chanctx);
|
||||
ath9k_calculate_summary_state(sc, avp->chanctx);
|
||||
}
|
||||
|
||||
if ((avp->chanctx == sc->cur_chan) &&
|
||||
@ -1788,6 +1797,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
slottime = 9;
|
||||
else
|
||||
slottime = 20;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
* Defer update, so that connected stations can adjust
|
||||
@ -1823,11 +1833,19 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
u64 tsf;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
ath9k_ps_wakeup(sc);
|
||||
tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
||||
/* Get current TSF either from HW or kernel time. */
|
||||
if (sc->cur_chan == avp->chanctx) {
|
||||
tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
||||
} else {
|
||||
tsf = sc->cur_chan->tsf_val +
|
||||
ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
|
||||
}
|
||||
tsf += le64_to_cpu(avp->tsf_adjust);
|
||||
ath9k_ps_restore(sc);
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
||||
@ -1839,10 +1857,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
|
||||
u64 tsf)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_settsf64(sc->sc_ah, tsf);
|
||||
tsf -= le64_to_cpu(avp->tsf_adjust);
|
||||
getrawmonotonic(&avp->chanctx->tsf_ts);
|
||||
if (sc->cur_chan == avp->chanctx)
|
||||
ath9k_hw_settsf64(sc->sc_ah, tsf);
|
||||
avp->chanctx->tsf_val = tsf;
|
||||
ath9k_ps_restore(sc);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
@ -1850,11 +1873,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
|
||||
static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_reset_tsf(sc->sc_ah);
|
||||
getrawmonotonic(&avp->chanctx->tsf_ts);
|
||||
if (sc->cur_chan == avp->chanctx)
|
||||
ath9k_hw_reset_tsf(sc->sc_ah);
|
||||
avp->chanctx->tsf_val = 0;
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
@ -794,6 +794,8 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
||||
ath_err(common,
|
||||
"%s: eeprom read failed, offset %08x is out of range\n",
|
||||
__func__, off);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = pdata->eeprom_data[off];
|
||||
|
@ -35,26 +35,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
|
||||
return ch->head_blk_ctl->bd_cpu_addr;
|
||||
}
|
||||
|
||||
static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
|
||||
{
|
||||
wcn36xx_dbg(WCN36XX_DBG_DXE,
|
||||
"wcn36xx_ccu_write_register: addr=%x, data=%x\n",
|
||||
addr, data);
|
||||
|
||||
writel(data, wcn->ccu_base + addr);
|
||||
}
|
||||
|
||||
static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
|
||||
{
|
||||
wcn36xx_dbg(WCN36XX_DBG_DXE,
|
||||
"wcn36xx_dxe_write_register: addr=%x, data=%x\n",
|
||||
addr, data);
|
||||
|
||||
writel(data, wcn->mmio + addr);
|
||||
writel(data, wcn->dxe_base + addr);
|
||||
}
|
||||
|
||||
#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \
|
||||
do { \
|
||||
if (wcn->chip_version == WCN36XX_CHIP_3680) \
|
||||
wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
|
||||
else \
|
||||
wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
|
||||
} while (0) \
|
||||
|
||||
static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
|
||||
{
|
||||
*data = readl(wcn->mmio + addr);
|
||||
*data = readl(wcn->dxe_base + addr);
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_DXE,
|
||||
"wcn36xx_dxe_read_register: addr=%x, data=%x\n",
|
||||
@ -701,9 +702,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
|
||||
reg_data = WCN36XX_DXE_REG_RESET;
|
||||
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
|
||||
|
||||
/* Setting interrupt path */
|
||||
reg_data = WCN36XX_DXE_CCU_INT;
|
||||
wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
|
||||
/* Select channels for rx avail and xfer done interrupts... */
|
||||
reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
|
||||
WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
|
||||
if (wcn->is_pronto)
|
||||
wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
|
||||
else
|
||||
wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
|
||||
|
||||
/***************************************/
|
||||
/* Init descriptors for TX LOW channel */
|
||||
|
@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2
|
||||
*/
|
||||
|
||||
/* DXE registers */
|
||||
#define WCN36XX_DXE_MEM_REG 0x202000
|
||||
#define WCN36XX_DXE_MEM_REG 0
|
||||
|
||||
#define WCN36XX_DXE_CCU_INT 0xA0011
|
||||
#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10
|
||||
#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
|
||||
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
|
||||
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
|
||||
|
||||
/* TODO This must calculated properly but not hardcoded */
|
||||
#define WCN36XX_DXE_CTRL_TX_L 0x328a44
|
||||
|
@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req {
|
||||
|
||||
/* Update scan params - sent from host to PNO to be used during PNO
|
||||
* scanningx */
|
||||
struct update_scan_params_req_ex {
|
||||
struct wcn36xx_hal_update_scan_params_req_ex {
|
||||
|
||||
struct wcn36xx_hal_msg_header header;
|
||||
|
||||
@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex {
|
||||
|
||||
/* Cb State */
|
||||
enum phy_chan_bond_state state;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* Update scan params - sent from host to PNO to be used during PNO
|
||||
* scanningx */
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "wcn36xx.h"
|
||||
|
||||
unsigned int wcn36xx_dbg_mask;
|
||||
@ -259,17 +261,6 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
|
||||
}
|
||||
}
|
||||
|
||||
static void wcn36xx_detect_chip_version(struct wcn36xx *wcn)
|
||||
{
|
||||
if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) {
|
||||
wcn36xx_info("Chip is 3680\n");
|
||||
wcn->chip_version = WCN36XX_CHIP_3680;
|
||||
} else {
|
||||
wcn36xx_info("Chip is 3660\n");
|
||||
wcn->chip_version = WCN36XX_CHIP_3660;
|
||||
}
|
||||
}
|
||||
|
||||
static int wcn36xx_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
@ -324,9 +315,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
|
||||
wcn36xx_feat_caps_info(wcn);
|
||||
}
|
||||
|
||||
wcn36xx_detect_chip_version(wcn);
|
||||
wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
|
||||
|
||||
/* DMA channel initialization */
|
||||
ret = wcn36xx_dxe_init(wcn);
|
||||
if (ret) {
|
||||
@ -1064,7 +1052,11 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
|
||||
static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *mmio_node;
|
||||
struct resource *res;
|
||||
int index;
|
||||
int ret;
|
||||
|
||||
/* Set TX IRQ */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
"wcnss_wlantx_irq");
|
||||
@ -1083,19 +1075,40 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
|
||||
}
|
||||
wcn->rx_irq = res->start;
|
||||
|
||||
/* Map the memory */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"wcnss_mmio");
|
||||
if (!res) {
|
||||
wcn36xx_err("failed to get mmio\n");
|
||||
return -ENOENT;
|
||||
mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
|
||||
if (!mmio_node) {
|
||||
wcn36xx_err("failed to acquire qcom,mmio reference\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
wcn->mmio = ioremap(res->start, resource_size(res));
|
||||
if (!wcn->mmio) {
|
||||
wcn36xx_err("failed to map io memory\n");
|
||||
return -ENOMEM;
|
||||
|
||||
wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
|
||||
|
||||
/* Map the CCU memory */
|
||||
index = of_property_match_string(mmio_node, "reg-names", "ccu");
|
||||
wcn->ccu_base = of_iomap(mmio_node, index);
|
||||
if (!wcn->ccu_base) {
|
||||
wcn36xx_err("failed to map ccu memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto put_mmio_node;
|
||||
}
|
||||
|
||||
/* Map the DXE memory */
|
||||
index = of_property_match_string(mmio_node, "reg-names", "dxe");
|
||||
wcn->dxe_base = of_iomap(mmio_node, index);
|
||||
if (!wcn->dxe_base) {
|
||||
wcn36xx_err("failed to map dxe memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_ccu;
|
||||
}
|
||||
|
||||
of_node_put(mmio_node);
|
||||
return 0;
|
||||
|
||||
unmap_ccu:
|
||||
iounmap(wcn->ccu_base);
|
||||
put_mmio_node:
|
||||
of_node_put(mmio_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wcn36xx_probe(struct platform_device *pdev)
|
||||
@ -1138,7 +1151,8 @@ static int wcn36xx_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
out_unmap:
|
||||
iounmap(wcn->mmio);
|
||||
iounmap(wcn->ccu_base);
|
||||
iounmap(wcn->dxe_base);
|
||||
out_wq:
|
||||
ieee80211_free_hw(hw);
|
||||
out_err:
|
||||
@ -1154,7 +1168,8 @@ static int wcn36xx_remove(struct platform_device *pdev)
|
||||
mutex_destroy(&wcn->hal_mutex);
|
||||
|
||||
ieee80211_unregister_hw(hw);
|
||||
iounmap(wcn->mmio);
|
||||
iounmap(wcn->dxe_base);
|
||||
iounmap(wcn->ccu_base);
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
return 0;
|
||||
|
@ -674,22 +674,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
|
||||
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,
|
||||
u8 *channels, size_t channel_count)
|
||||
{
|
||||
struct wcn36xx_hal_update_scan_params_req msg_body;
|
||||
struct wcn36xx_hal_update_scan_params_req_ex msg_body;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&wcn->hal_mutex);
|
||||
INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
|
||||
|
||||
msg_body.dot11d_enabled = 0;
|
||||
msg_body.dot11d_resolved = 0;
|
||||
msg_body.channel_count = 26;
|
||||
msg_body.dot11d_enabled = false;
|
||||
msg_body.dot11d_resolved = true;
|
||||
|
||||
msg_body.channel_count = channel_count;
|
||||
memcpy(msg_body.channels, channels, channel_count);
|
||||
msg_body.active_min_ch_time = 60;
|
||||
msg_body.active_max_ch_time = 120;
|
||||
msg_body.passive_min_ch_time = 60;
|
||||
msg_body.passive_max_ch_time = 110;
|
||||
msg_body.state = 0;
|
||||
msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;
|
||||
|
||||
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
|
||||
|
||||
@ -2226,17 +2229,12 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
|
||||
|
||||
case WCN36XX_HAL_COEX_IND:
|
||||
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
|
||||
case WCN36XX_HAL_DEL_BA_IND:
|
||||
case WCN36XX_HAL_OTA_TX_COMPL_IND:
|
||||
case WCN36XX_HAL_MISSED_BEACON_IND:
|
||||
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
|
||||
msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
|
||||
if (!msg_ind)
|
||||
goto nomem;
|
||||
msg_ind->msg_len = len;
|
||||
msg_ind->msg = kmemdup(buf, len, GFP_KERNEL);
|
||||
if (!msg_ind->msg) {
|
||||
kfree(msg_ind);
|
||||
nomem:
|
||||
msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
|
||||
if (!msg_ind) {
|
||||
/*
|
||||
* FIXME: Do something smarter then just
|
||||
* printing an error.
|
||||
@ -2245,10 +2243,14 @@ nomem:
|
||||
msg_header->msg_type);
|
||||
break;
|
||||
}
|
||||
mutex_lock(&wcn->hal_ind_mutex);
|
||||
|
||||
msg_ind->msg_len = len;
|
||||
memcpy(msg_ind->msg, buf, len);
|
||||
|
||||
spin_lock(&wcn->hal_ind_lock);
|
||||
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
|
||||
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
|
||||
mutex_unlock(&wcn->hal_ind_mutex);
|
||||
spin_unlock(&wcn->hal_ind_lock);
|
||||
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
|
||||
break;
|
||||
default:
|
||||
@ -2262,8 +2264,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
|
||||
container_of(work, struct wcn36xx, hal_ind_work);
|
||||
struct wcn36xx_hal_msg_header *msg_header;
|
||||
struct wcn36xx_hal_ind_msg *hal_ind_msg;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&wcn->hal_ind_mutex);
|
||||
spin_lock_irqsave(&wcn->hal_ind_lock, flags);
|
||||
|
||||
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
|
||||
struct wcn36xx_hal_ind_msg,
|
||||
@ -2273,6 +2276,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
|
||||
|
||||
switch (msg_header->msg_type) {
|
||||
case WCN36XX_HAL_COEX_IND:
|
||||
case WCN36XX_HAL_DEL_BA_IND:
|
||||
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
|
||||
break;
|
||||
case WCN36XX_HAL_OTA_TX_COMPL_IND:
|
||||
@ -2295,9 +2299,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
|
||||
msg_header->msg_type);
|
||||
}
|
||||
list_del(wcn->hal_ind_queue.next);
|
||||
kfree(hal_ind_msg->msg);
|
||||
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
|
||||
kfree(hal_ind_msg);
|
||||
mutex_unlock(&wcn->hal_ind_mutex);
|
||||
}
|
||||
int wcn36xx_smd_open(struct wcn36xx *wcn)
|
||||
{
|
||||
@ -2310,7 +2313,7 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
|
||||
}
|
||||
INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
|
||||
INIT_LIST_HEAD(&wcn->hal_ind_queue);
|
||||
mutex_init(&wcn->hal_ind_mutex);
|
||||
spin_lock_init(&wcn->hal_ind_lock);
|
||||
|
||||
ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
|
||||
if (ret) {
|
||||
@ -2330,5 +2333,4 @@ void wcn36xx_smd_close(struct wcn36xx *wcn)
|
||||
{
|
||||
wcn->ctrl_ops->close();
|
||||
destroy_workqueue(wcn->hal_ind_wq);
|
||||
mutex_destroy(&wcn->hal_ind_mutex);
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ struct wcn36xx_fw_msg_status_rsp {
|
||||
|
||||
struct wcn36xx_hal_ind_msg {
|
||||
struct list_head list;
|
||||
u8 *msg;
|
||||
size_t msg_len;
|
||||
u8 msg[];
|
||||
};
|
||||
|
||||
struct wcn36xx;
|
||||
@ -63,7 +63,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
|
||||
int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
|
||||
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
|
||||
enum wcn36xx_hal_sys_mode mode);
|
||||
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
|
||||
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
|
||||
int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
|
||||
int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
|
||||
int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
|
||||
|
@ -193,7 +193,7 @@ struct wcn36xx {
|
||||
u8 fw_minor;
|
||||
u8 fw_major;
|
||||
u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
|
||||
u32 chip_version;
|
||||
bool is_pronto;
|
||||
|
||||
/* extra byte for the NULL termination */
|
||||
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
|
||||
@ -202,7 +202,8 @@ struct wcn36xx {
|
||||
/* IRQs */
|
||||
int tx_irq;
|
||||
int rx_irq;
|
||||
void __iomem *mmio;
|
||||
void __iomem *ccu_base;
|
||||
void __iomem *dxe_base;
|
||||
|
||||
struct wcn36xx_platform_ctrl_ops *ctrl_ops;
|
||||
/*
|
||||
@ -215,7 +216,7 @@ struct wcn36xx {
|
||||
struct completion hal_rsp_compl;
|
||||
struct workqueue_struct *hal_ind_wq;
|
||||
struct work_struct hal_ind_work;
|
||||
struct mutex hal_ind_mutex;
|
||||
spinlock_t hal_ind_lock;
|
||||
struct list_head hal_ind_queue;
|
||||
|
||||
/* DXE channels */
|
||||
@ -241,9 +242,6 @@ struct wcn36xx {
|
||||
|
||||
};
|
||||
|
||||
#define WCN36XX_CHIP_3660 0
|
||||
#define WCN36XX_CHIP_3680 1
|
||||
|
||||
static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
|
||||
u8 major,
|
||||
u8 minor,
|
||||
|
@ -40,6 +40,7 @@ struct ath9k_platform_data {
|
||||
bool tx_gain_buffalo;
|
||||
bool disable_2ghz;
|
||||
bool disable_5ghz;
|
||||
bool led_active_high;
|
||||
|
||||
int (*get_mac_revision)(void);
|
||||
int (*external_reset)(void);
|
||||
|
Loading…
Reference in New Issue
Block a user