Merge branch 'for-linville' of git://github.com/kvalo/ath
This commit is contained in:
commit
559c33d84d
@ -37,3 +37,10 @@ config ATH10K_TRACING
|
||||
---help---
|
||||
Select this to ath10k use tracing infrastructure.
|
||||
|
||||
config ATH10K_DFS_CERTIFIED
|
||||
bool "Atheros DFS support for certified platforms"
|
||||
depends on ATH10K && CFG80211_CERTIFICATION_ONUS
|
||||
default n
|
||||
---help---
|
||||
This option enables DFS support for initiating radiation on
|
||||
ath10k.
|
||||
|
@ -253,6 +253,9 @@ struct ath10k_vif {
|
||||
u8 bssid[ETH_ALEN];
|
||||
} ibss;
|
||||
} u;
|
||||
|
||||
u8 fixed_rate;
|
||||
u8 fixed_nss;
|
||||
};
|
||||
|
||||
struct ath10k_vif_iter {
|
||||
@ -272,6 +275,8 @@ struct ath10k_debug {
|
||||
struct delayed_work htt_stats_dwork;
|
||||
struct ath10k_dfs_stats dfs_stats;
|
||||
struct ath_dfs_pool_stats dfs_pool_stats;
|
||||
|
||||
u32 fw_dbglog_mask;
|
||||
};
|
||||
|
||||
enum ath10k_state {
|
||||
@ -306,6 +311,9 @@ enum ath10k_fw_features {
|
||||
/* firmware support tx frame management over WMI, otherwise it's HTT */
|
||||
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2,
|
||||
|
||||
/* Firmware does not support P2P */
|
||||
ATH10K_FW_FEATURE_NO_P2P = 3,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
@ -429,6 +437,9 @@ struct ath10k {
|
||||
struct list_head peers;
|
||||
wait_queue_head_t peer_mapping_wq;
|
||||
|
||||
/* number of created peers; protected by data_lock */
|
||||
int num_peers;
|
||||
|
||||
struct work_struct offchan_tx_work;
|
||||
struct sk_buff_head offchan_tx_queue;
|
||||
struct completion offchan_tx_completed;
|
||||
|
@ -614,6 +614,61 @@ static const struct file_operations fops_htt_stats_mask = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_read_fw_dbglog(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned int len;
|
||||
char buf[32];
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "0x%08x\n",
|
||||
ar->debug.fw_dbglog_mask);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_write_fw_dbglog(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned long mask;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul_from_user(user_buf, count, 0, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ar->debug.fw_dbglog_mask = mask;
|
||||
|
||||
if (ar->state == ATH10K_STATE_ON) {
|
||||
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
|
||||
if (ret) {
|
||||
ath10k_warn("dbglog cfg failed from debugfs: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_fw_dbglog = {
|
||||
.read = ath10k_read_fw_dbglog,
|
||||
.write = ath10k_write_fw_dbglog,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_start(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
@ -625,6 +680,14 @@ int ath10k_debug_start(struct ath10k *ar)
|
||||
/* continue normally anyway, this isn't serious */
|
||||
ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
|
||||
|
||||
if (ar->debug.fw_dbglog_mask) {
|
||||
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
|
||||
if (ret)
|
||||
/* not serious */
|
||||
ath10k_warn("failed to enable dbglog during start: %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -747,6 +810,9 @@ int ath10k_debug_create(struct ath10k *ar)
|
||||
debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_htt_stats_mask);
|
||||
|
||||
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_fw_dbglog);
|
||||
|
||||
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
|
||||
debugfs_create_file("dfs_simulate_radar", S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
|
@ -1183,6 +1183,7 @@ struct htt_rx_info {
|
||||
} rate;
|
||||
bool fcs_err;
|
||||
bool amsdu_more;
|
||||
bool mic_err;
|
||||
};
|
||||
|
||||
struct ath10k_htt {
|
||||
|
@ -838,6 +838,20 @@ static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
@ -960,6 +974,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
|
||||
info.skb = msdu_head;
|
||||
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
|
||||
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
|
||||
info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
info.signal += rx->ppdu.combined_rssi;
|
||||
|
||||
|
@ -115,6 +115,7 @@ enum ath10k_mcast2ucast_mode {
|
||||
#define TARGET_10X_MAC_AGGR_DELIM 0
|
||||
#define TARGET_10X_AST_SKID_LIMIT 16
|
||||
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
|
||||
#define TARGET_10X_NUM_PEERS_MAX 128
|
||||
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
|
||||
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
|
||||
#define TARGET_10X_NUM_PEER_KEYS 2
|
||||
|
@ -332,6 +332,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
||||
ath10k_warn("Failed to wait for created wmi peer: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->num_peers++;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -377,6 +380,10 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->num_peers--;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -396,6 +403,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
||||
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
@ -411,6 +419,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
}
|
||||
ar->num_peers = 0;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
@ -2205,7 +2214,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
enum wmi_sta_powersave_param param;
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
u32 value, param_id;
|
||||
int bit;
|
||||
u32 vdev_param;
|
||||
|
||||
@ -2297,6 +2306,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
param_id = ar->wmi.pdev_param->sta_kickout_th;
|
||||
|
||||
/* Disable STA KICKOUT functionality in FW */
|
||||
ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to disable STA KICKOUT\n");
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
|
||||
@ -2842,6 +2858,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
int max_num_peers;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
@ -2852,9 +2869,21 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
/*
|
||||
* New station addition.
|
||||
*/
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
|
||||
max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
|
||||
else
|
||||
max_num_peers = TARGET_NUM_PEERS;
|
||||
|
||||
if (ar->num_peers >= max_num_peers) {
|
||||
ath10k_warn("Number of peers exceeded: peers number %d (max peers %d)\n",
|
||||
ar->num_peers, max_num_peers);
|
||||
ret = -ENOBUFS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d peer create %pM (new sta)\n",
|
||||
arvif->vdev_id, sta->addr);
|
||||
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
|
||||
arvif->vdev_id, sta->addr, ar->num_peers);
|
||||
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret)
|
||||
@ -2904,7 +2933,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
ath10k_warn("Failed to disassociate station: %pM\n",
|
||||
sta->addr);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
@ -3310,6 +3339,307 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Helper table for legacy fixed_rate/bitrate_mask */
|
||||
static const u8 cck_ofdm_rate[] = {
|
||||
/* CCK */
|
||||
3, /* 1Mbps */
|
||||
2, /* 2Mbps */
|
||||
1, /* 5.5Mbps */
|
||||
0, /* 11Mbps */
|
||||
/* OFDM */
|
||||
3, /* 6Mbps */
|
||||
7, /* 9Mbps */
|
||||
2, /* 12Mbps */
|
||||
6, /* 18Mbps */
|
||||
1, /* 24Mbps */
|
||||
5, /* 36Mbps */
|
||||
0, /* 48Mbps */
|
||||
4, /* 54Mbps */
|
||||
};
|
||||
|
||||
/* Check if only one bit set */
|
||||
static int ath10k_check_single_mask(u32 mask)
|
||||
{
|
||||
int bit;
|
||||
|
||||
bit = ffs(mask);
|
||||
if (!bit)
|
||||
return 0;
|
||||
|
||||
mask &= ~BIT(bit - 1);
|
||||
if (mask)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_default_bitrate_mask(struct ath10k *ar,
|
||||
enum ieee80211_band band,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
u32 legacy = 0x00ff;
|
||||
u8 ht = 0xff, i;
|
||||
u16 vht = 0x3ff;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
legacy = 0x00fff;
|
||||
vht = 0;
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mask->control[band].legacy != legacy)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ar->num_rf_chains; i++)
|
||||
if (mask->control[band].ht_mcs[i] != ht)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ar->num_rf_chains; i++)
|
||||
if (mask->control[band].vht_mcs[i] != vht)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
int ht_nss = 0, vht_nss = 0, i;
|
||||
|
||||
/* check legacy */
|
||||
if (ath10k_check_single_mask(mask->control[band].legacy))
|
||||
return false;
|
||||
|
||||
/* check HT */
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
|
||||
if (mask->control[band].ht_mcs[i] == 0xff)
|
||||
continue;
|
||||
else if (mask->control[band].ht_mcs[i] == 0x00)
|
||||
break;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
ht_nss = i;
|
||||
|
||||
/* check VHT */
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
|
||||
if (mask->control[band].vht_mcs[i] == 0x03ff)
|
||||
continue;
|
||||
else if (mask->control[band].vht_mcs[i] == 0x0000)
|
||||
break;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
vht_nss = i;
|
||||
|
||||
if (ht_nss > 0 && vht_nss > 0)
|
||||
return false;
|
||||
|
||||
if (ht_nss)
|
||||
*fixed_nss = ht_nss;
|
||||
else if (vht_nss)
|
||||
*fixed_nss = vht_nss;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
enum wmi_rate_preamble *preamble)
|
||||
{
|
||||
int legacy = 0, ht = 0, vht = 0, i;
|
||||
|
||||
*preamble = WMI_RATE_PREAMBLE_OFDM;
|
||||
|
||||
/* check legacy */
|
||||
legacy = ath10k_check_single_mask(mask->control[band].legacy);
|
||||
if (legacy > 1)
|
||||
return false;
|
||||
|
||||
/* check HT */
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]);
|
||||
if (ht > 1)
|
||||
return false;
|
||||
|
||||
/* check VHT */
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
|
||||
vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]);
|
||||
if (vht > 1)
|
||||
return false;
|
||||
|
||||
/* Currently we support only one fixed_rate */
|
||||
if ((legacy + ht + vht) != 1)
|
||||
return false;
|
||||
|
||||
if (ht)
|
||||
*preamble = WMI_RATE_PREAMBLE_HT;
|
||||
else if (vht)
|
||||
*preamble = WMI_RATE_PREAMBLE_VHT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_rate,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
u8 rate = 0, pream = 0, nss = 0, i;
|
||||
enum wmi_rate_preamble preamble;
|
||||
|
||||
/* Check if single rate correct */
|
||||
if (!ath10k_bitrate_mask_correct(mask, band, &preamble))
|
||||
return false;
|
||||
|
||||
pream = preamble;
|
||||
|
||||
switch (preamble) {
|
||||
case WMI_RATE_PREAMBLE_CCK:
|
||||
case WMI_RATE_PREAMBLE_OFDM:
|
||||
i = ffs(mask->control[band].legacy) - 1;
|
||||
|
||||
if (band == IEEE80211_BAND_2GHZ && i < 4)
|
||||
pream = WMI_RATE_PREAMBLE_CCK;
|
||||
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
i += 4;
|
||||
|
||||
if (i >= ARRAY_SIZE(cck_ofdm_rate))
|
||||
return false;
|
||||
|
||||
rate = cck_ofdm_rate[i];
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_HT:
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
if (mask->control[band].ht_mcs[i])
|
||||
break;
|
||||
|
||||
if (i == IEEE80211_HT_MCS_MASK_LEN)
|
||||
return false;
|
||||
|
||||
rate = ffs(mask->control[band].ht_mcs[i]) - 1;
|
||||
nss = i;
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_VHT:
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
|
||||
if (mask->control[band].vht_mcs[i])
|
||||
break;
|
||||
|
||||
if (i == NL80211_VHT_NSS_MAX)
|
||||
return false;
|
||||
|
||||
rate = ffs(mask->control[band].vht_mcs[i]) - 1;
|
||||
nss = i;
|
||||
break;
|
||||
}
|
||||
|
||||
*fixed_nss = nss + 1;
|
||||
nss <<= 4;
|
||||
pream <<= 6;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
|
||||
pream, nss, rate);
|
||||
|
||||
*fixed_rate = pream | nss | rate;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_rate,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
/* First check full NSS mask, if we can simply limit NSS */
|
||||
if (ath10k_bitrate_mask_nss(mask, band, fixed_nss))
|
||||
return true;
|
||||
|
||||
/* Next Check single rate is set */
|
||||
return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
|
||||
}
|
||||
|
||||
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
|
||||
u8 fixed_rate,
|
||||
u8 fixed_nss)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 vdev_param;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (arvif->fixed_rate == fixed_rate &&
|
||||
arvif->fixed_nss == fixed_nss)
|
||||
goto exit;
|
||||
|
||||
if (fixed_rate == WMI_FIXED_RATE_NONE)
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->fixed_rate;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
vdev_param, fixed_rate);
|
||||
if (ret) {
|
||||
ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n",
|
||||
fixed_rate, ret);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arvif->fixed_rate = fixed_rate;
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->nss;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
vdev_param, fixed_nss);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn("Could not set fixed_nss param %d: %d\n",
|
||||
fixed_nss, ret);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arvif->fixed_nss = fixed_nss;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k *ar = arvif->ar;
|
||||
enum ieee80211_band band = ar->hw->conf.chandef.chan->band;
|
||||
u8 fixed_rate = WMI_FIXED_RATE_NONE;
|
||||
u8 fixed_nss = ar->num_rf_chains;
|
||||
|
||||
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
|
||||
if (!ath10k_get_fixed_rate_nss(mask, band,
|
||||
&fixed_rate,
|
||||
&fixed_nss))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx = ath10k_tx,
|
||||
.start = ath10k_start,
|
||||
@ -3332,6 +3662,7 @@ static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx_last_beacon = ath10k_tx_last_beacon,
|
||||
.restart_complete = ath10k_restart_complete,
|
||||
.get_survey = ath10k_get_survey,
|
||||
.set_bitrate_mask = ath10k_set_bitrate_mask,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ath10k_suspend,
|
||||
.resume = ath10k_resume,
|
||||
@ -3464,14 +3795,12 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = {
|
||||
static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
|
||||
{
|
||||
.max = 8,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
|
||||
{
|
||||
@ -3481,19 +3810,22 @@ static const struct ieee80211_iface_combination ath10k_if_comb[] = {
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
},
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
|
||||
{
|
||||
.limits = ath10k_if_dfs_limits,
|
||||
.n_limits = ARRAY_SIZE(ath10k_if_dfs_limits),
|
||||
.limits = ath10k_10x_if_limits,
|
||||
.n_limits = ARRAY_SIZE(ath10k_10x_if_limits),
|
||||
.max_interfaces = 8,
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
BIT(NL80211_CHAN_WIDTH_20) |
|
||||
BIT(NL80211_CHAN_WIDTH_40) |
|
||||
BIT(NL80211_CHAN_WIDTH_80),
|
||||
}
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
||||
@ -3672,9 +4004,12 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
ar->hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
|
||||
ar->hw->wiphy->interface_modes |=
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
@ -3717,8 +4052,15 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
*/
|
||||
ar->hw->queues = 4;
|
||||
|
||||
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb);
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
|
||||
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(ath10k_10x_if_comb);
|
||||
} else {
|
||||
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(ath10k_if_comb);
|
||||
}
|
||||
|
||||
ar->hw->netdev_features = NETIF_F_HW_CSUM;
|
||||
|
||||
|
@ -182,6 +182,27 @@ TRACE_EVENT(ath10k_htt_stats,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_dbglog,
|
||||
TP_PROTO(void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"len %zu",
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
|
||||
|
||||
/* we don't want to use include/trace/events */
|
||||
|
@ -231,7 +231,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
if (info->status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
|
||||
if (info->mic_err)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (info->fcs_err)
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "htc.h"
|
||||
@ -875,6 +876,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
struct wmi_mgmt_rx_event_v2 *ev_v2;
|
||||
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_channel *ch;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 rx_status;
|
||||
u32 channel;
|
||||
@ -927,7 +929,25 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
if (rx_status & WMI_RX_STATUS_ERR_MIC)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
status->band = phy_mode_to_band(phy_mode);
|
||||
/* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to
|
||||
* MODE_11B. This means phy_mode is not a reliable source for the band
|
||||
* of mgmt rx. */
|
||||
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
|
||||
if (ch) {
|
||||
status->band = ch->band;
|
||||
|
||||
if (phy_mode == MODE_11B &&
|
||||
status->band == IEEE80211_BAND_5GHZ)
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
|
||||
} else {
|
||||
ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
|
||||
status->band = phy_mode_to_band(phy_mode);
|
||||
}
|
||||
|
||||
status->freq = ieee80211_channel_to_frequency(channel, status->band);
|
||||
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
status->rate_idx = get_rate_idx(rate, status->band);
|
||||
@ -937,7 +957,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
if (fc & IEEE80211_FCTL_PROTECTED) {
|
||||
/* FW delivers WEP Shared Auth frame with Protected Bit set and
|
||||
* encrypted payload. However in case of PMF it delivers decrypted
|
||||
* frames with Protected Bit set. */
|
||||
if (ieee80211_has_protected(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
@ -1047,9 +1071,14 @@ static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
|
||||
static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_MESG_EVENTID\n");
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
|
||||
skb->len);
|
||||
|
||||
trace_ath10k_wmi_dbglog(skb->data, skb->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_update_stats(struct ath10k *ar,
|
||||
@ -1653,9 +1682,37 @@ static void ath10k_wmi_event_profile_match(struct ath10k *ar,
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_debug_print(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_PRINT_EVENTID\n");
|
||||
char buf[101], c;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(buf) - 1; i++) {
|
||||
if (i >= skb->len)
|
||||
break;
|
||||
|
||||
c = skb->data[i];
|
||||
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
if (isascii(c) && isprint(c))
|
||||
buf[i] = c;
|
||||
else
|
||||
buf[i] = '.';
|
||||
}
|
||||
|
||||
if (i == sizeof(buf) - 1)
|
||||
ath10k_warn("wmi debug print truncated: %d\n", skb->len);
|
||||
|
||||
/* for some reason the debug prints end with \n, remove that */
|
||||
if (skb->data[i - 1] == '\n')
|
||||
i--;
|
||||
|
||||
/* the last byte is always reserved for the null character */
|
||||
buf[i] = '\0';
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
|
||||
@ -3445,3 +3502,40 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
|
||||
type, delay_ms);
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
|
||||
}
|
||||
|
||||
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
|
||||
{
|
||||
struct wmi_dbglog_cfg_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
u32 cfg;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
|
||||
|
||||
if (module_enable) {
|
||||
cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE,
|
||||
ATH10K_DBGLOG_CFG_LOG_LVL);
|
||||
} else {
|
||||
/* set back defaults, all modules with WARN level */
|
||||
cfg = SM(ATH10K_DBGLOG_LEVEL_WARN,
|
||||
ATH10K_DBGLOG_CFG_LOG_LVL);
|
||||
module_enable = ~0;
|
||||
}
|
||||
|
||||
cmd->module_enable = __cpu_to_le32(module_enable);
|
||||
cmd->module_valid = __cpu_to_le32(~0);
|
||||
cmd->config_enable = __cpu_to_le32(cfg);
|
||||
cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI,
|
||||
"wmi dbglog cfg modules %08x %08x config %08x %08x\n",
|
||||
__le32_to_cpu(cmd->module_enable),
|
||||
__le32_to_cpu(cmd->module_valid),
|
||||
__le32_to_cpu(cmd->config_enable),
|
||||
__le32_to_cpu(cmd->config_valid));
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
|
||||
}
|
||||
|
@ -3003,6 +3003,18 @@ struct wmi_vdev_install_key_arg {
|
||||
const void *key_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* vdev fixed rate format:
|
||||
* - preamble - b7:b6 - see WMI_RATE_PREMABLE_
|
||||
* - nss - b5:b4 - ss number (0 mean 1ss)
|
||||
* - rate_mcs - b3:b0 - as below
|
||||
* CCK: 0 - 11Mbps, 1 - 5,5Mbps, 2 - 2Mbps, 3 - 1Mbps,
|
||||
* 4 - 11Mbps (s), 5 - 5,5Mbps (s), 6 - 2Mbps (s)
|
||||
* OFDM: 0 - 48Mbps, 1 - 24Mbps, 2 - 12Mbps, 3 - 6Mbps,
|
||||
* 4 - 54Mbps, 5 - 36Mbps, 6 - 18Mbps, 7 - 9Mbps
|
||||
* HT/VHT: MCS index
|
||||
*/
|
||||
|
||||
/* Preamble types to be used with VDEV fixed rate configuration */
|
||||
enum wmi_rate_preamble {
|
||||
WMI_RATE_PREAMBLE_OFDM,
|
||||
@ -4090,6 +4102,54 @@ struct wmi_force_fw_hang_cmd {
|
||||
__le32 delay_ms;
|
||||
} __packed;
|
||||
|
||||
enum ath10k_dbglog_level {
|
||||
ATH10K_DBGLOG_LEVEL_VERBOSE = 0,
|
||||
ATH10K_DBGLOG_LEVEL_INFO = 1,
|
||||
ATH10K_DBGLOG_LEVEL_WARN = 2,
|
||||
ATH10K_DBGLOG_LEVEL_ERR = 3,
|
||||
};
|
||||
|
||||
/* VAP ids to enable dbglog */
|
||||
#define ATH10K_DBGLOG_CFG_VAP_LOG_LSB 0
|
||||
#define ATH10K_DBGLOG_CFG_VAP_LOG_MASK 0x0000ffff
|
||||
|
||||
/* to enable dbglog in the firmware */
|
||||
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_LSB 16
|
||||
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_MASK 0x00010000
|
||||
|
||||
/* timestamp resolution */
|
||||
#define ATH10K_DBGLOG_CFG_RESOLUTION_LSB 17
|
||||
#define ATH10K_DBGLOG_CFG_RESOLUTION_MASK 0x000E0000
|
||||
|
||||
/* number of queued messages before sending them to the host */
|
||||
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_LSB 20
|
||||
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_MASK 0x0ff00000
|
||||
|
||||
/*
|
||||
* Log levels to enable. This defines the minimum level to enable, this is
|
||||
* not a bitmask. See enum ath10k_dbglog_level for the values.
|
||||
*/
|
||||
#define ATH10K_DBGLOG_CFG_LOG_LVL_LSB 28
|
||||
#define ATH10K_DBGLOG_CFG_LOG_LVL_MASK 0x70000000
|
||||
|
||||
/*
|
||||
* Note: this is a cleaned up version of a struct firmware uses. For
|
||||
* example, config_valid was hidden inside an array.
|
||||
*/
|
||||
struct wmi_dbglog_cfg_cmd {
|
||||
/* bitmask to hold mod id config*/
|
||||
__le32 module_enable;
|
||||
|
||||
/* see ATH10K_DBGLOG_CFG_ */
|
||||
__le32 config_enable;
|
||||
|
||||
/* mask of module id bits to be changed */
|
||||
__le32 module_valid;
|
||||
|
||||
/* mask of config bits to be changed, see ATH10K_DBGLOG_CFG_ */
|
||||
__le32 config_valid;
|
||||
} __packed;
|
||||
|
||||
#define ATH10K_RTS_MAX 2347
|
||||
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
|
||||
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
|
||||
@ -4167,5 +4227,6 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
|
||||
int ath10k_wmi_force_fw_hang(struct ath10k *ar,
|
||||
enum wmi_force_fw_hang_type type, u32 delay_ms);
|
||||
int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
|
||||
|
||||
#endif /* _WMI_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user