Commit 500ff9f9 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: implement chanctx API

The chanctx API will allow ath10k to support
multi-channel operation.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 0a27347e
...@@ -284,6 +284,15 @@ struct ath10k_sta { ...@@ -284,6 +284,15 @@ struct ath10k_sta {
#endif #endif
}; };
struct ath10k_chanctx {
/* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally
* mac80211 should allow some sort of explicit locking to guarantee
* that the publicly available chanctx_conf can be accessed safely at
* all times.
*/
struct ieee80211_chanctx_conf conf;
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
enum ath10k_beacon_state { enum ath10k_beacon_state {
...@@ -607,6 +616,7 @@ struct ath10k { ...@@ -607,6 +616,7 @@ struct ath10k {
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
unsigned long long free_vdev_map; unsigned long long free_vdev_map;
struct ath10k_vif *monitor_arvif;
bool monitor; bool monitor;
int monitor_vdev_id; int monitor_vdev_id;
bool monitor_started; bool monitor_started;
......
...@@ -723,8 +723,87 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, ...@@ -723,8 +723,87 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
} }
} }
static struct ieee80211_channel *
ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
{
struct ath10k_peer *peer;
struct ath10k_vif *arvif;
struct cfg80211_chan_def def;
u16 peer_id;
lockdep_assert_held(&ar->data_lock);
if (!rxd)
return NULL;
if (rxd->attention.flags &
__cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID))
return NULL;
if (!(rxd->msdu_end.info0 &
__cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)))
return NULL;
peer_id = MS(__le32_to_cpu(rxd->mpdu_start.info0),
RX_MPDU_START_INFO0_PEER_IDX);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer)
return NULL;
arvif = ath10k_get_arvif(ar, peer->vdev_id);
if (WARN_ON_ONCE(!arvif))
return NULL;
if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
return NULL;
return def.chan;
}
static struct ieee80211_channel *
ath10k_htt_rx_h_vdev_channel(struct ath10k *ar, u32 vdev_id)
{
struct ath10k_vif *arvif;
struct cfg80211_chan_def def;
lockdep_assert_held(&ar->data_lock);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (arvif->vdev_id == vdev_id &&
ath10k_mac_vif_chan(arvif->vif, &def) == 0)
return def.chan;
}
return NULL;
}
static void
ath10k_htt_rx_h_any_chan_iter(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf,
void *data)
{
struct cfg80211_chan_def *def = data;
*def = conf->def;
}
static struct ieee80211_channel *
ath10k_htt_rx_h_any_channel(struct ath10k *ar)
{
struct cfg80211_chan_def def = {};
ieee80211_iter_chan_contexts_atomic(ar->hw,
ath10k_htt_rx_h_any_chan_iter,
&def);
return def.chan;
}
static bool ath10k_htt_rx_h_channel(struct ath10k *ar, static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
struct ieee80211_rx_status *status) struct ieee80211_rx_status *status,
struct htt_rx_desc *rxd,
u32 vdev_id)
{ {
struct ieee80211_channel *ch; struct ieee80211_channel *ch;
...@@ -732,6 +811,12 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar, ...@@ -732,6 +811,12 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
ch = ar->scan_channel; ch = ar->scan_channel;
if (!ch) if (!ch)
ch = ar->rx_channel; ch = ar->rx_channel;
if (!ch)
ch = ath10k_htt_rx_h_peer_channel(ar, rxd);
if (!ch)
ch = ath10k_htt_rx_h_vdev_channel(ar, vdev_id);
if (!ch)
ch = ath10k_htt_rx_h_any_channel(ar);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
if (!ch) if (!ch)
...@@ -769,7 +854,8 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar, ...@@ -769,7 +854,8 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
struct sk_buff_head *amsdu, struct sk_buff_head *amsdu,
struct ieee80211_rx_status *status) struct ieee80211_rx_status *status,
u32 vdev_id)
{ {
struct sk_buff *first; struct sk_buff *first;
struct htt_rx_desc *rxd; struct htt_rx_desc *rxd;
...@@ -801,7 +887,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, ...@@ -801,7 +887,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL; status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_signal(ar, status, rxd); ath10k_htt_rx_h_signal(ar, status, rxd);
ath10k_htt_rx_h_channel(ar, status); ath10k_htt_rx_h_channel(ar, status, rxd, vdev_id);
ath10k_htt_rx_h_rates(ar, status, rxd); ath10k_htt_rx_h_rates(ar, status, rxd);
} }
...@@ -1472,7 +1558,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -1472,7 +1558,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
break; break;
} }
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
...@@ -1519,7 +1605,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, ...@@ -1519,7 +1605,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
return; return;
} }
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
...@@ -1746,7 +1832,7 @@ static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar, ...@@ -1746,7 +1832,7 @@ static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL; status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_rx_offload_prot(status, msdu); ath10k_htt_rx_h_rx_offload_prot(status, msdu);
ath10k_htt_rx_h_channel(ar, status); ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
ath10k_process_rx(ar, status, msdu); ath10k_process_rx(ar, status, msdu);
} }
} }
...@@ -1819,7 +1905,7 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ...@@ -1819,7 +1905,7 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
* better to report something than nothing though. This * better to report something than nothing though. This
* should still give an idea about rx rate to the user. * should still give an idea about rx rate to the user.
*/ */
ath10k_htt_rx_h_ppdu(ar, &amsdu, status); ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status); ath10k_htt_rx_h_filter(ar, &amsdu, status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status); ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
ath10k_htt_rx_h_deliver(ar, &amsdu, status); ath10k_htt_rx_h_deliver(ar, &amsdu, status);
......
This diff is collapsed.
...@@ -53,6 +53,8 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); ...@@ -53,6 +53,8 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
void ath10k_drain_tx(struct ath10k *ar); void ath10k_drain_tx(struct ath10k *ar);
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
u8 keyidx); u8 keyidx);
int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
struct cfg80211_chan_def *def);
void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb); void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);
void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id); void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id);
......
...@@ -2425,6 +2425,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ...@@ -2425,6 +2425,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
u64 tsf) u64 tsf)
{ {
u32 reg0, reg1, tsf32l; u32 reg0, reg1, tsf32l;
struct ieee80211_channel *ch;
struct pulse_event pe; struct pulse_event pe;
u64 tsf64; u64 tsf64;
u8 rssi, width; u8 rssi, width;
...@@ -2453,6 +2454,15 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ...@@ -2453,6 +2454,15 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
if (!ar->dfs_detector) if (!ar->dfs_detector)
return; return;
spin_lock_bh(&ar->data_lock);
ch = ar->rx_channel;
spin_unlock_bh(&ar->data_lock);
if (!ch) {
ath10k_warn(ar, "failed to derive channel for radar pulse, treating as radar\n");
goto radar_detected;
}
/* report event to DFS pattern detector */ /* report event to DFS pattern detector */
tsf32l = __le32_to_cpu(phyerr->tsf_timestamp); tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
tsf64 = tsf & (~0xFFFFFFFFULL); tsf64 = tsf & (~0xFFFFFFFFULL);
...@@ -2468,7 +2478,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ...@@ -2468,7 +2478,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
rssi = 0; rssi = 0;
pe.ts = tsf64; pe.ts = tsf64;
pe.freq = ar->hw->conf.chandef.chan->center_freq; pe.freq = ch->center_freq;
pe.width = width; pe.width = width;
pe.rssi = rssi; pe.rssi = rssi;
pe.chirp = (MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP) != 0); pe.chirp = (MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP) != 0);
...@@ -2484,6 +2494,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ...@@ -2484,6 +2494,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
return; return;
} }
radar_detected:
ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n"); ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
ATH10K_DFS_STAT_INC(ar, radar_detected); ATH10K_DFS_STAT_INC(ar, radar_detected);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment