wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/652-02-ath12k-Update-hw-generic-mac-ops-handling.patch
John Crispin b9b03a6e38 ipq95xx: add Qualcomm wifi-7 support
Signed-off-by: John Crispin <john@phrozen.org>
2023-04-10 14:25:48 +02:00

638 lines
16 KiB
Diff

From d515e964f7ce49ec3478135fb7dc36c05c7221da Mon Sep 17 00:00:00 2001
From: Sriram R <quic_srirrama@quicinc.com>
Date: Wed, 22 Dec 2021 12:08:29 +0530
Subject: [PATCH 02/10] ath12k: Update hw generic mac ops handling
Handle the below mac ops.
1. start/stop
2. get_antenna/set_antenna
3. set_rts_threshold
4. add_chanctx
5. remove_chanctx
Note that antenna/rts configs will have to be made link
specific configs so that they can updated individually.
Other feature specific ops with just 'hw' as arg
like config/configure_filter will be handled in monitor support.
reconfig_complete() will be handled in HW restart support.
Co-developed-by: P Praneesh <quic_ppranees@quicinc.com>
Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 279 +++++++++++++++++++++-------------
1 file changed, 172 insertions(+), 107 deletions(-)
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -621,6 +621,33 @@ struct ath12k_vif *ath12k_mac_get_arvif_
return NULL;
}
+static struct ath12k *ath12k_mac_get_ar_by_band(struct ieee80211_hw *hw,
+ enum nl80211_band band)
+{
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int i;
+
+ ar = ah->radio;
+ for (i = 0; i < ah->num_radio; i++) {
+ if (ar->mac.sbands[band].channels)
+ return ar;
+ ar++;
+ }
+ return NULL;
+}
+
+static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ if (!ctx)
+ return NULL;
+
+ /* TODO 5G low high split radio changes */
+
+ return ath12k_mac_get_ar_by_band(hw, ctx->def.chan->band);
+}
+
struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
{
int i;
@@ -1150,46 +1177,54 @@ static int ath12k_mac_monitor_stop(struc
static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
struct ieee80211_conf *conf = &hw->conf;
- int ret;
+ int ret, i;
- mutex_lock(&ar->conf_mutex);
+ mutex_lock(&ah->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- if (conf->flags & IEEE80211_CONF_MONITOR) {
- set_bit(MONITOR_CONF_ENABLED, &ar->monitor_flags);
- if (test_bit(MONITOR_VDEV_CREATED,
- &ar->monitor_flags))
- goto exit;
+ ar = ah->radio;
- ret = ath12k_mac_monitor_vdev_create(ar);
- if (ret)
- goto exit;
- ret = ath12k_mac_monitor_start(ar);
- if (ret)
- goto err_mon_del;
- } else {
- clear_bit(MONITOR_CONF_ENABLED, &ar->monitor_flags);
- if (!test_bit(MONITOR_VDEV_CREATED,
- &ar->monitor_flags))
- goto exit;
+ for (i = 0; i < ah->num_radio; i++) {
+ mutex_lock(&ar->conf_mutex);
- ret = ath12k_mac_monitor_stop(ar);
- if (ret)
- goto exit;
- ath12k_mac_monitor_vdev_delete(ar);
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+ if (conf->flags & IEEE80211_CONF_MONITOR) {
+ set_bit(MONITOR_CONF_ENABLED, &ar->monitor_flags);
+ if (test_bit(MONITOR_VDEV_CREATED,
+ &ar->monitor_flags))
+ goto out;
+
+ ret = ath12k_mac_monitor_vdev_create(ar);
+ if (ret)
+ goto out;
+ ret = ath12k_mac_monitor_start(ar);
+ if (ret) {
+ ath12k_mac_monitor_vdev_delete(ar);
+ goto out;
+ }
+ } else {
+ clear_bit(MONITOR_CONF_ENABLED, &ar->monitor_flags);
+ if (!test_bit(MONITOR_VDEV_CREATED,
+ &ar->monitor_flags))
+ goto out;
+
+ ret = ath12k_mac_monitor_stop(ar);
+ if (ret)
+ goto out;
+
+ ath12k_mac_monitor_vdev_delete(ar);
+ }
}
+out:
+ mutex_unlock(&ar->conf_mutex);
+ ar++;
}
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
+ mutex_unlock(&ah->conf_mutex);
-err_mon_del:
- ath12k_mac_monitor_vdev_delete(ar);
- mutex_unlock(&ar->conf_mutex);
- return 0;
+ return ret;
}
static void ath12k_mac_setup_bcn_tmpl_vif_params(struct ath12k_vif *arvif,
@@ -5143,11 +5178,11 @@ static void ath12k_mac_op_sta_set_4addr(
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_hw *ah = hw->priv;
struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv;
if (enabled && !arsta->use_4addr_set) {
- ieee80211_queue_work(ar->hw, &arsta->set_4addr_wk);
+ ieee80211_queue_work(ah->hw, &arsta->set_4addr_wk);
arsta->use_4addr_set = true;
}
}
@@ -5590,15 +5625,6 @@ static void ath12k_mac_setup_ht_vht_cap(
}
}
-static int ath12k_check_chain_mask(struct ath12k *ar, u32 ant, bool is_tx_ant)
-{
- /* TODO: Check the request chainmask against the supported
- * chainmask table which is advertised in extented_service_ready event
- */
-
- return 0;
-}
-
static void ath12k_gen_ppe_thresh(struct ath12k_ppe_threshold *fw_ppet,
u8 *he_ppet)
{
@@ -6075,11 +6101,12 @@ static int __ath12k_set_antenna(struct a
lockdep_assert_held(&ar->conf_mutex);
- if (ath12k_check_chain_mask(ar, tx_ant, true))
- return -EINVAL;
-
- if (ath12k_check_chain_mask(ar, rx_ant, false))
- return -EINVAL;
+ /* Since we advertised the max cap of all radios combined during wiphy
+ * registration, ensure we dont set the antenna config higher than our
+ * limits
+ */
+ tx_ant = min_t(u32, tx_ant, ar->pdev->cap.tx_chain_mask);
+ rx_ant = min_t(u32, rx_ant, ar->pdev->cap.rx_chain_mask);
ar->cfg_tx_chainmask = tx_ant;
ar->cfg_rx_chainmask = rx_ant;
@@ -6315,10 +6342,10 @@ static void ath12k_mac_op_tx(struct ieee
struct sk_buff *skb)
{
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
- struct ath12k *ar = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k *ar = arvif->ar;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
struct ath12k_sta *arsta = NULL;
@@ -6397,9 +6424,8 @@ static int ath12k_mac_config_mon_status_
return ret;
}
-static int ath12k_mac_op_start(struct ieee80211_hw *hw)
+static int ath12k_mac_radio_start(struct ath12k *ar)
{
- struct ath12k *ar = hw->priv;
struct ath12k_base *ab = ar->ab;
struct ath12k_pdev *pdev = ar->pdev;
int ret;
@@ -6426,14 +6452,14 @@ static int ath12k_mac_op_start(struct ie
1, pdev->pdev_id);
if (ret) {
- ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret);
+ ath12k_err(ab, "failed to enable PMF QOS: (%d\n", ret);
goto err;
}
ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1,
pdev->pdev_id);
if (ret) {
- ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret);
+ ath12k_err(ab, "failed to enable dynamic bw: %d\n", ret);
goto err;
}
@@ -6463,7 +6489,7 @@ static int ath12k_mac_op_start(struct ie
1, pdev->pdev_id);
if (ret) {
- ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
+ ath12k_err(ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
goto err;
}
@@ -6493,7 +6519,7 @@ static int ath12k_mac_op_start(struct ie
}
if (ret == -ENOTSUPP)
- ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
"monitor status config is not yet supported");
/* Configure the hash seed for hash based reo dest ring selection */
@@ -6522,9 +6548,8 @@ err:
return ret;
}
-static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
+static void ath12k_mac_radio_stop(struct ath12k *ar)
{
- struct ath12k *ar = hw->priv;
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
int ret;
@@ -6561,6 +6586,62 @@ static void ath12k_mac_op_stop(struct ie
spin_unlock_bh(&ar->data_lock);
}
+static int ath12k_mac_op_start(struct ieee80211_hw *hw)
+{
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ struct ath12k_base *ab;
+ int i;
+ int ret;
+
+ mutex_lock(&ah->conf_mutex);
+ ar = ah->radio;
+ ab = ar->ab;
+
+ /* TODO Maintain state for ah? */
+
+ for (i = 0; i < ah->num_radio; i++) {
+ ab = ar->ab;
+ ret = ath12k_mac_radio_start(ar);
+ if (ret) {
+ ath12k_err(ab, "fail to start mac operations in radio %d ret %d\n",
+ i, ret);
+ goto err;
+ }
+ ar++;
+ }
+
+ mutex_unlock(&ah->conf_mutex);
+ return 0;
+err:
+ ar = ah->radio;
+ for (i = i - 1; i >= 0; i--) {
+ ath12k_mac_radio_stop(ar);
+ ar++;
+ }
+ mutex_unlock(&ah->conf_mutex);
+ return ret;
+}
+
+static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
+{
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int i;
+
+ mutex_lock(&ah->conf_mutex);
+ ar = ah->radio;
+
+ /* TODO Maintain state for ah? */
+
+ for (i = 0; i < ah->num_radio; i++) {
+ ath12k_mac_radio_stop(ar);
+ ar++;
+ }
+
+ mutex_unlock(&ah->conf_mutex);
+}
+
static u8
ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
{
@@ -7098,38 +7179,71 @@ static void ath12k_mac_op_configure_filt
unsigned int *total_flags,
u64 multicast)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int i;
- mutex_lock(&ar->conf_mutex);
+ mutex_lock(&ah->conf_mutex);
- *total_flags &= SUPPORTED_FILTERS;
- ar->filter_flags = *total_flags;
+ ar = ah->radio;
+ for (i = 0; i < ah->num_radio; i++) {
+ mutex_lock(&ar->conf_mutex);
- mutex_unlock(&ar->conf_mutex);
+ *total_flags &= SUPPORTED_FILTERS;
+ ar->filter_flags = *total_flags;
+
+ mutex_unlock(&ar->conf_mutex);
+ ar++;
+ }
+ mutex_unlock(&ah->conf_mutex);
}
+/* TODO Also support link based antenna configs, below might not be accurate */
static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int antennas_rx = 0, antennas_tx = 0, i;
- mutex_lock(&ar->conf_mutex);
+ mutex_lock(&ah->conf_mutex);
- *tx_ant = ar->cfg_tx_chainmask;
- *rx_ant = ar->cfg_rx_chainmask;
+ ar = ah->radio;
+ for (i = 0; i < ah->num_radio; i++) {
+ mutex_lock(&ar->conf_mutex);
- mutex_unlock(&ar->conf_mutex);
+ antennas_tx = max_t(u32, antennas_tx, ar->cfg_tx_chainmask);
+ antennas_rx = max_t(u32, antennas_rx, ar->cfg_rx_chainmask);
+
+ mutex_unlock(&ar->conf_mutex);
+ ar++;
+ }
+
+ *tx_ant = antennas_tx;
+ *rx_ant = antennas_rx;
+
+ mutex_unlock(&ah->conf_mutex);
return 0;
}
static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
{
- struct ath12k *ar = hw->priv;
- int ret;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int ret = 0, i;
- mutex_lock(&ar->conf_mutex);
- ret = __ath12k_set_antenna(ar, tx_ant, rx_ant);
- mutex_unlock(&ar->conf_mutex);
+ mutex_lock(&ah->conf_mutex);
+
+ ar = ah->radio;
+ for (i = 0; i < ah->num_radio; i++) {
+ mutex_lock(&ar->conf_mutex);
+ ret = __ath12k_set_antenna(ar, tx_ant, rx_ant);
+ mutex_unlock(&ar->conf_mutex);
+
+ ar++;
+ }
+
+ mutex_unlock(&ah->conf_mutex);
return ret;
}
@@ -7170,10 +7284,14 @@ static int ath12k_mac_op_ampdu_action(st
static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
- struct ath12k *ar = hw->priv;
- struct ath12k_base *ab = ar->ab;
+ struct ath12k *ar;
- ath12k_dbg(ab, ATH12K_DBG_MAC,
+ ar = ath12k_get_ar_by_ctx(hw, ctx);
+
+ if (!ar)
+ return -EINVAL;
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"mac chanctx add freq %u width %d ptr %pK\n",
ctx->def.chan->center_freq, ctx->def.width, ctx);
@@ -7194,10 +7312,14 @@ static int ath12k_mac_op_add_chanctx(str
static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
- struct ath12k *ar = hw->priv;
- struct ath12k_base *ab = ar->ab;
+ struct ath12k *ar;
- ath12k_dbg(ab, ATH12K_DBG_MAC,
+ ar = ath12k_get_ar_by_ctx(hw, ctx);
+
+ if (!ar)
+ return;
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"mac chanctx remove freq %u width %d ptr %pK\n",
ctx->def.chan->center_freq, ctx->def.width, ctx);
@@ -8409,13 +8531,28 @@ ath12k_set_vdev_param_to_all_vifs(struct
/* mac80211 stores device specific RTS/Fragmentation threshold value,
* this is set interface specific to firmware from ath12k driver
+ * TODO Move to link specific config
*/
static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int i, ret;
int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
- return ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
+ ar = ah->radio;
+
+ for (i = 0; i < ah->num_radio; i++) {
+ ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to set RTS config for all vdevs of pdev %d",
+ ar->pdev->pdev_id);
+ break;
+ }
+ ar++;
+ }
+
+ return ret;
}
static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
@@ -8433,33 +8570,63 @@ static int ath12k_mac_op_set_frag_thresh
return -EOPNOTSUPP;
}
-static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 queues, bool drop)
+static void ath12k_mac_flush(struct ath12k *ar)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k_base *ab = ar->ab;
long time_left;
- if (drop)
- return;
+ lockdep_assert_held(&ar->ab->ah->conf_mutex);
time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
(atomic_read(&ar->dp.num_tx_pending) == 0),
ATH12K_FLUSH_TIMEOUT);
if (time_left == 0)
- ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
+ ath12k_warn(ab, "failed to flush transmit queue %ld\n", time_left);
time_left = wait_event_timeout(ar->txmgmt_empty_waitq,
(atomic_read(&ar->num_pending_mgmt_tx) == 0),
ATH12K_FLUSH_TIMEOUT);
if (time_left == 0)
- ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n",
+ ath12k_warn(ab, "failed to flush mgmt transmit queue %ld\n",
time_left);
- ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac mgmt tx flush mgmt pending %d\n",
atomic_read(&ar->num_pending_mgmt_tx));
}
+static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 queues, bool drop)
+{
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar;
+ int i;
+
+ if (drop)
+ return;
+
+ mutex_lock(&ah->conf_mutex);
+
+ if (!vif) {
+ /* FIXME: Need to identify which radio to flush.
+ * Until flush all the device if vif NULL
+ */
+ ar = ah->radio;
+ for (i = 0; i < ah->num_radio; i++) {
+ ath12k_mac_flush(ar);
+ ar++;
+ }
+ } else {
+ ar = ath12k_get_ar_by_vif(hw, vif);
+ if (!ar) {
+ goto out;
+ }
+ ath12k_mac_flush(ar);
+ }
+out:
+ mutex_unlock(&ah->conf_mutex);
+}
+
static int
ath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar,
enum nl80211_band band,
@@ -9189,6 +9356,7 @@ static void
ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
+ /* TODO Handle hw restart */
struct ath12k *ar = hw->priv;
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
@@ -9241,38 +9409,55 @@ ath12k_mac_update_bss_chan_survey(struct
static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
- struct ath12k *ar = hw->priv;
+ struct ath12k *ar;
struct ieee80211_supported_band *sband;
struct survey_info *ar_survey;
int ret = 0;
+ enum nl80211_band band;
if (idx >= ATH12K_NUM_CHANS)
return -ENOENT;
- ar_survey = &ar->survey[idx];
-
- mutex_lock(&ar->conf_mutex);
-
+ band = NL80211_BAND_2GHZ;
sband = hw->wiphy->bands[NL80211_BAND_2GHZ];
if (sband && idx >= sband->n_channels) {
idx -= sband->n_channels;
sband = NULL;
}
- if (!sband)
+ /* TODO: If 5G HB/LB are split across two radios then it requires
+ * idx check as well
+ */
+ if (!sband) {
sband = hw->wiphy->bands[NL80211_BAND_5GHZ];
+ band = NL80211_BAND_5GHZ;
+ }
+
if (sband && idx >= sband->n_channels) {
idx -= sband->n_channels;
sband = NULL;
}
- if (!sband)
+ if (!sband) {
sband = hw->wiphy->bands[NL80211_BAND_6GHZ];
+ band = NL80211_BAND_6GHZ;
+ }
+
if (!sband || idx >= sband->n_channels) {
ret = -ENOENT;
goto exit;
}
+ ar = ath12k_mac_get_ar_by_band(hw, band);
+ if (!ar) {
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ ar_survey = &ar->survey[idx];
+
+ mutex_lock(&ar->conf_mutex);
+
ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
spin_lock_bh(&ar->data_lock);
@@ -9284,8 +9469,9 @@ static int ath12k_mac_op_get_survey(stru
if (ar->rx_channel == survey->channel)
survey->filled |= SURVEY_INFO_IN_USE;
-exit:
mutex_unlock(&ar->conf_mutex);
+
+exit:
return ret;
}