* [PATCH 06/16] iwlwifi: mvm: add a wrapper around rs_tx_status to handle locks
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Gregory Greenman, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Gregory Greenman <gregory.greenman@intel.com>
iwl_mvm_rs_tx_status can be called from two places in the code, but the
mutex is taken only on one of the calls. Split it into a wrapper taking
locks and an internal __iwl_mvm_rs_tx_status function.
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 28 ++++++++++++++-------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 02b4ef92543f..b50a47e86ef0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1218,8 +1218,10 @@ void iwl_mvm_rs_init_wk(struct work_struct *wk)
rcu_read_unlock();
}
-void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- int tid, struct ieee80211_tx_info *info, bool ndp)
+static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ int tid, struct ieee80211_tx_info *info,
+ bool ndp)
{
int legacy_success;
int retries;
@@ -1451,6 +1453,21 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
}
+void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int tid, struct ieee80211_tx_info *info, bool ndp)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ /* If it's locked we are in middle of init flow
+ * just wait for next tx status to update the lq_sta data
+ */
+ if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex))
+ return;
+
+ __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
+ mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex);
+}
+
/*
* mac80211 sends us Tx status
*/
@@ -1472,15 +1489,8 @@ static void rs_drv_mac80211_tx_status(void *mvm_r,
info->flags & IEEE80211_TX_CTL_NO_ACK)
return;
- /* If it's locked we are in middle of init flow
- * just wait for next tx status to update the lq_sta data
- */
- if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex))
- return;
-
iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info,
ieee80211_is_qos_nullfunc(hdr->frame_control));
- mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex);
}
/*
--
2.20.1
^ permalink raw reply related
* [PATCH 07/16] iwlwifi: dbg_ini: move iwl_dbg_tlv_load_bin out of debug override ifdef
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Shahar S Matityahu, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Shahar S Matityahu <shahar.s.matityahu@intel.com>
ini debug mode should work even if debug override is not defined.
Signed-off-by: Shahar S Matityahu <shahar.s.matityahu@intel.com>
Fixes: 68f6f492c4fa ("iwlwifi: trans: support loading ini TLVs from external file")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 57d09049e615..d91686b9a540 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1640,6 +1640,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
init_completion(&drv->request_firmware_complete);
INIT_LIST_HEAD(&drv->list);
+ iwl_load_fw_dbg_tlv(drv->trans->dev, drv->trans);
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the device debugfs entries. */
drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev),
--
2.20.1
^ permalink raw reply related
* [PATCH 08/16] iwlwifi: dbg_ini: move iwl_dbg_tlv_free outside of debugfs ifdef
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Shahar S Matityahu, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Shahar S Matityahu <shahar.s.matityahu@intel.com>
The driver should call iwl_dbg_tlv_free even if debugfs is not defined
since ini mode does not depend on debugfs ifdef.
Signed-off-by: Shahar S Matityahu <shahar.s.matityahu@intel.com>
Fixes: 68f6f492c4fa ("iwlwifi: trans: support loading ini TLVs from external file")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index d91686b9a540..38672dd5aae9 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1662,8 +1662,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
err_fw:
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(drv->dbgfs_drv);
- iwl_fw_dbg_free(drv->trans);
#endif
+ iwl_fw_dbg_free(drv->trans);
kfree(drv);
err:
return ERR_PTR(ret);
--
2.20.1
^ permalink raw reply related
* [PATCH 09/16] iwlwifi: fix locking in delayed GTK setting
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Johannes Berg, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Johannes Berg <johannes.berg@intel.com>
This code clearly never could have worked, since it locks
while already locked. Add an unlocked __iwl_mvm_mac_set_key()
variant that doesn't do locking to fix that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 39 ++++++++++++-------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 982682ec74fd..1c904b5226aa 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -207,11 +207,11 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
},
};
-static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
- enum set_key_cmd cmd,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
+static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
@@ -2738,7 +2738,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
mvmvif->ap_early_keys[i] = NULL;
- ret = iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
+ ret = __iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
if (ret)
goto out_quota_failed;
}
@@ -3506,11 +3506,11 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
return ret;
}
-static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
- enum set_key_cmd cmd,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -3565,8 +3565,6 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
return -EOPNOTSUPP;
}
- mutex_lock(&mvm->mutex);
-
switch (cmd) {
case SET_KEY:
if ((vif->type == NL80211_IFTYPE_ADHOC ||
@@ -3712,7 +3710,22 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
ret = -EINVAL;
}
+ return ret;
+}
+
+static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key);
mutex_unlock(&mvm->mutex);
+
return ret;
}
--
2.20.1
^ permalink raw reply related
* [PATCH 14/16] iwlwifi: mvm: fix possible out-of-bounds read when accessing lq_info
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Gregory Greenman, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Gregory Greenman <gregory.greenman@intel.com>
lq_info is an arary of size 2, active_tbl index is u8.
When accessing lq_info[1 - active_tbl], theoretically it's possible
that the access will be made to a negative index value.
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 28 +++++++++++++++------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 3fa50b1955bb..d3f04acfbacb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1352,6 +1352,18 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw);
}
+/* rs uses two tables, one is active and the second is for searching better
+ * configuration. This function, according to the index of the currently
+ * active table returns the search table, which is located at the
+ * index complementary to 1 according to the active table (active = 1,
+ * search = 0 or active = 0, search = 1).
+ * Since lq_info is an arary of size 2, make sure index cannot be out of bounds.
+ */
+static inline u8 rs_search_tbl(u8 active_tbl)
+{
+ return (active_tbl ^ 1) & 1;
+}
+
static s32 rs_get_best_rate(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl, /* "search" */
@@ -1699,9 +1711,9 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
enum rs_column col_id)
{
- struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
struct iwl_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
struct rs_rate *rate = &search_tbl->rate;
const struct rs_tx_column *column = &rs_tx_columns[col_id];
const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column];
@@ -2109,7 +2121,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
else
- active_tbl = 1 - lq_sta->active_tbl;
+ active_tbl = rs_search_tbl(lq_sta->active_tbl);
tbl = &(lq_sta->lq_info[active_tbl]);
rate = &tbl->rate;
@@ -2333,7 +2345,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* If new "search" mode was selected, set up in uCode table */
if (lq_sta->search_better_tbl) {
/* Access the "search" table, clear its history. */
- tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
rs_rate_scale_clear_tbl_windows(mvm, tbl);
/* Use new "search" start rate */
@@ -2676,7 +2688,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
else
- active_tbl = 1 - lq_sta->active_tbl;
+ active_tbl = rs_search_tbl(lq_sta->active_tbl);
tbl = &(lq_sta->lq_info[active_tbl]);
rate = &tbl->rate;
@@ -3172,9 +3184,9 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
if (!lq_sta->search_better_tbl) {
curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
- other_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ other_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
} else {
- curr_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ curr_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
other_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
}
@@ -3183,7 +3195,7 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
"Neither active nor search matches tx rate\n");
tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
- tmp_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ tmp_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)];
rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
rs_dump_rate(mvm, &lq_rate, "ACTUAL");
--
2.20.1
^ permalink raw reply related
* [PATCH 10/16] iwlwifi: mvm: fix comparison of u32 variable with less than zero
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Colin Ian King, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Colin Ian King <colin.king@canonical.com>
The comparison of the u32 variable wgds_tbl_idx with less than zero is
always going to be false because it is unsigned. Fix this by making
wgds_tbl_idx a plain signed int.
Addresses-Coverity: ("Unsigned compared against 0")
Fixes: 4fd445a2c855 ("iwlwifi: mvm: Add log information about SAR status")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index 719f793b3487..a9bb43a2f27b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -620,7 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
enum iwl_mcc_source src;
char mcc[3];
struct ieee80211_regdomain *regd;
- u32 wgds_tbl_idx;
+ int wgds_tbl_idx;
lockdep_assert_held(&mvm->mutex);
--
2.20.1
^ permalink raw reply related
* [PATCH 11/16] iwlwifi: mvm: send LQ command always ASYNC
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Gregory Greenman, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Gregory Greenman <gregory.greenman@intel.com>
The only place where the command was sent as SYNC is during
init and this is not really critical. This change is required
for replacing RS mutex with a spinlock (in the subsequent patch),
since SYNC comamnd requres sleeping and thus the flow cannot
be done when holding a spinlock.
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 23 ++++++++++---------
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +-
.../net/wireless/intel/iwlwifi/mvm/utils.c | 4 ++--
4 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index fd1764df592f..a263cc629d75 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1813,7 +1813,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync);
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq);
void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index b50a47e86ef0..bd977ec8629b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1328,7 +1328,7 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
IWL_DEBUG_RATE(mvm,
"Too many rates mismatch. Send sync LQ. rs_state %d\n",
lq_sta->rs_state);
- iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
}
/* Regardless, ignore this status info for outdated rate */
return;
@@ -1390,7 +1390,8 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
if (info->status.ampdu_ack_len == 0)
info->status.ampdu_len = 1;
- rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, tx_resp_rate.index,
+ rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl,
+ tx_resp_rate.index,
info->status.ampdu_len,
info->status.ampdu_ack_len);
@@ -1833,7 +1834,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl)
{
rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate);
- iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
}
static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm,
@@ -2935,7 +2936,7 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
static void rs_initialize_lq(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
- enum nl80211_band band, bool update)
+ enum nl80211_band band)
{
struct iwl_scale_tbl_info *tbl;
struct rs_rate *rate;
@@ -2965,7 +2966,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rs_set_expected_tpt_table(lq_sta, tbl);
rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
/* TODO restore station should remember the lq cmd */
- iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
}
static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
@@ -3214,7 +3215,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
* Called after adding a new station to initialize rate scaling
*/
static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band, bool update)
+ enum nl80211_band band)
{
int i, j;
struct ieee80211_hw *hw = mvm->hw;
@@ -3294,7 +3295,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
- rs_initialize_lq(mvm, sta, lq_sta, band, update);
+ rs_initialize_lq(mvm, sta, lq_sta, band);
}
static void rs_drv_rate_update(void *mvm_r,
@@ -3608,7 +3609,7 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params);
- iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false);
+ iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd);
ss_params |= LQ_SS_BFER_ALLOWED;
IWL_DEBUG_RATE(mvm,
@@ -3774,7 +3775,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
if (lq_sta->pers.dbg_fixed_rate) {
rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL);
- iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false);
+ iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq);
}
}
@@ -4177,7 +4178,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
mutex_lock(&mvmsta->lq_sta.rs_drv.mutex);
- rs_drv_rate_init(mvm, sta, band, update);
+ rs_drv_rate_init(mvm, sta, band);
mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex);
}
}
@@ -4209,7 +4210,7 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
lq->flags &= ~LQ_FLAG_USE_RTS_MSK;
}
- return iwl_mvm_send_lq_cmd(mvm, lq, false);
+ return iwl_mvm_send_lq_cmd(mvm, lq);
}
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 23fd3108adb9..88d16b5442e7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -2978,7 +2978,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid);
- return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq, false);
+ return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.rs_drv.lq);
}
static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 9ecd5f09615a..b8e20a01c192 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -653,12 +653,12 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
* this case to clear the state indicating that station creation is in
* progress.
*/
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync)
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)
{
struct iwl_host_cmd cmd = {
.id = LQ_CMD,
.len = { sizeof(struct iwl_lq_cmd), },
- .flags = sync ? 0 : CMD_ASYNC,
+ .flags = CMD_ASYNC,
.data = { lq, },
};
--
2.20.1
^ permalink raw reply related
* [PATCH 15/16] iwlwifi: add 3 new IDs for the 9000 series (iwl9260_2ac_160_cfg)
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Ihab Zhaika, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Ihab Zhaika <ihab.zhaika@intel.com>
Add a few PCI ID'S for 9000 series.
Signed-off-by: Ihab Zhaika <ihab.zhaika@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index ea2a03d4bf55..de711c1160d3 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -604,10 +604,13 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2526, 0x6010, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x6014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0xE010, iwl9260_2ac_160_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0xE014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)},
--
2.20.1
^ permalink raw reply related
* [PATCH 16/16] iwlwifi: mvm: fix version check for GEO_TX_POWER_LIMIT support
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Luca Coelho <luciano.coelho@intel.com>
We erroneously added a check for FW API version 41 before sending
GEO_TX_POWER_LIMIT, but this was already implemented in version 38.
Additionally, it was cherry-picked to older versions, namely 17, 26
and 29, so check for those as well.
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index a837cf40afde..00c89bcfdf6a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -886,9 +886,14 @@ static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm)
* The GEO_TX_POWER_LIMIT command is not supported on earlier
* firmware versions. Unfortunately, we don't have a TLV API
* flag to rely on, so rely on the major version which is in
- * the first byte of ucode_ver.
+ * the first byte of ucode_ver. This was implemented
+ * initially on version 38 and then backported to 36, 29 and
+ * 17.
*/
- return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 41;
+ return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 ||
+ IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 36 ||
+ IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 ||
+ IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17;
}
int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
--
2.20.1
^ permalink raw reply related
* [PATCH 12/16] iwlwifi: mvm: replace RS mutex with a spin_lock
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Gregory Greenman, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Gregory Greenman <gregory.greenman@intel.com>
The solution with the worker still had a bug, as in order
to get sta, rcu_read_lock should be used and thus no mutex
can be used inside iwl_mvm_rs_rate_init.
Also, spin_lock is a simpler solution, no need to spawn a
dedicated worker.
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 530 +++++++++----------
drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 6 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 1 -
4 files changed, 258 insertions(+), 285 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index bd977ec8629b..3fa50b1955bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1197,278 +1197,6 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr)
return tid;
}
-void iwl_mvm_rs_init_wk(struct work_struct *wk)
-{
- struct iwl_mvm_sta *mvmsta = container_of(wk, struct iwl_mvm_sta,
- rs_init_wk);
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
- struct ieee80211_sta *sta;
-
- rcu_read_lock();
-
- sta = rcu_dereference(mvmvif->mvm->fw_id_to_mac_id[mvmsta->sta_id]);
- if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
- rcu_read_unlock();
- return;
- }
-
- iwl_mvm_rs_rate_init(mvmvif->mvm, sta, mvmvif->phy_ctxt->channel->band,
- true);
-
- rcu_read_unlock();
-}
-
-static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
- int tid, struct ieee80211_tx_info *info,
- bool ndp)
-{
- int legacy_success;
- int retries;
- int i;
- struct iwl_lq_cmd *table;
- u32 lq_hwrate;
- struct rs_rate lq_rate, tx_resp_rate;
- struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
- u32 tlc_info = (uintptr_t)info->status.status_driver_data[0];
- u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK;
- u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info);
- u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
-
- /* Treat uninitialized rate scaling data same as non-existing. */
- if (!lq_sta) {
- IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
- return;
- } else if (!lq_sta->pers.drv) {
- IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
- return;
- }
-
- /* This packet was aggregated but doesn't carry status info */
- if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
- !(info->flags & IEEE80211_TX_STAT_AMPDU))
- return;
-
- if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band,
- &tx_resp_rate)) {
- WARN_ON_ONCE(1);
- return;
- }
-
-#ifdef CONFIG_MAC80211_DEBUGFS
- /* Disable last tx check if we are debugging with fixed rate but
- * update tx stats */
- if (lq_sta->pers.dbg_fixed_rate) {
- int index = tx_resp_rate.index;
- enum rs_column column;
- int attempts, success;
-
- column = rs_get_column_from_rate(&tx_resp_rate);
- if (WARN_ONCE(column == RS_COLUMN_INVALID,
- "Can't map rate 0x%x to column",
- tx_resp_hwrate))
- return;
-
- if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- attempts = info->status.ampdu_len;
- success = info->status.ampdu_ack_len;
- } else {
- attempts = info->status.rates[0].count;
- success = !!(info->flags & IEEE80211_TX_STAT_ACK);
- }
-
- lq_sta->pers.tx_stats[column][index].total += attempts;
- lq_sta->pers.tx_stats[column][index].success += success;
-
- IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n",
- tx_resp_hwrate, success, attempts);
- return;
- }
-#endif
-
- if (time_after(jiffies,
- (unsigned long)(lq_sta->last_tx +
- (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
- IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
- schedule_work(&mvmsta->rs_init_wk);
- return;
- }
- lq_sta->last_tx = jiffies;
-
- /* Ignore this Tx frame response if its initial rate doesn't match
- * that of latest Link Quality command. There may be stragglers
- * from a previous Link Quality command, but we're no longer interested
- * in those; they're either from the "active" mode while we're trying
- * to check "search" mode, or a prior "search" mode after we've moved
- * to a new "search" mode (which might become the new "active" mode).
- */
- table = &lq_sta->lq;
- lq_hwrate = le32_to_cpu(table->rs_table[0]);
- if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) {
- WARN_ON_ONCE(1);
- return;
- }
-
- /* Here we actually compare this rate to the latest LQ command */
- if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) {
- IWL_DEBUG_RATE(mvm,
- "tx resp color 0x%x does not match 0x%x\n",
- lq_color, LQ_FLAG_COLOR_GET(table->flags));
-
- /*
- * Since rates mis-match, the last LQ command may have failed.
- * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
- * ... driver.
- */
- lq_sta->missed_rate_counter++;
- if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
- lq_sta->missed_rate_counter = 0;
- IWL_DEBUG_RATE(mvm,
- "Too many rates mismatch. Send sync LQ. rs_state %d\n",
- lq_sta->rs_state);
- iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
- }
- /* Regardless, ignore this status info for outdated rate */
- return;
- } else
- /* Rate did match, so reset the missed_rate_counter */
- lq_sta->missed_rate_counter = 0;
-
- if (!lq_sta->search_better_tbl) {
- curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
- } else {
- curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
- other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- }
-
- if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) {
- IWL_DEBUG_RATE(mvm,
- "Neither active nor search matches tx rate\n");
- tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
- tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
- rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
- rs_dump_rate(mvm, &lq_rate, "ACTUAL");
-
- /*
- * no matching table found, let's by-pass the data collection
- * and continue to perform rate scale to find the rate table
- */
- rs_stay_in_table(lq_sta, true);
- goto done;
- }
-
- /*
- * Updating the frame history depends on whether packets were
- * aggregated.
- *
- * For aggregation, all packets were transmitted at the same rate, the
- * first index into rate scale table.
- */
- if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index,
- info->status.ampdu_len,
- info->status.ampdu_ack_len,
- reduced_txp);
-
- /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat
- * it as a single frame loss as we don't want the success ratio
- * to dip too quickly because a BA wasn't received.
- * For TPC, there's no need for this optimisation since we want
- * to recover very quickly from a bad power reduction and,
- * therefore we'd like the success ratio to get an immediate hit
- * when failing to get a BA, so we'd switch back to a lower or
- * zero power reduction. When FW transmits agg with a rate
- * different from the initial rate, it will not use reduced txp
- * and will send BA notification twice (one empty with reduced
- * txp equal to the value from LQ and one with reduced txp 0).
- * We need to update counters for each txp level accordingly.
- */
- if (info->status.ampdu_ack_len == 0)
- info->status.ampdu_len = 1;
-
- rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl,
- tx_resp_rate.index,
- info->status.ampdu_len,
- info->status.ampdu_ack_len);
-
- /* Update success/fail counts if not searching for new mode */
- if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
- lq_sta->total_success += info->status.ampdu_ack_len;
- lq_sta->total_failed += (info->status.ampdu_len -
- info->status.ampdu_ack_len);
- }
- } else {
- /* For legacy, update frame history with for each Tx retry. */
- retries = info->status.rates[0].count - 1;
- /* HW doesn't send more than 15 retries */
- retries = min(retries, 15);
-
- /* The last transmission may have been successful */
- legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
- /* Collect data for each rate used during failed TX attempts */
- for (i = 0; i <= retries; ++i) {
- lq_hwrate = le32_to_cpu(table->rs_table[i]);
- if (rs_rate_from_ucode_rate(lq_hwrate, info->band,
- &lq_rate)) {
- WARN_ON_ONCE(1);
- return;
- }
-
- /*
- * Only collect stats if retried rate is in the same RS
- * table as active/search.
- */
- if (rs_rate_column_match(&lq_rate, &curr_tbl->rate))
- tmp_tbl = curr_tbl;
- else if (rs_rate_column_match(&lq_rate,
- &other_tbl->rate))
- tmp_tbl = other_tbl;
- else
- continue;
-
- rs_collect_tpc_data(mvm, lq_sta, tmp_tbl,
- tx_resp_rate.index, 1,
- i < retries ? 0 : legacy_success,
- reduced_txp);
- rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl,
- tx_resp_rate.index, 1,
- i < retries ? 0 : legacy_success);
- }
-
- /* Update success/fail counts if not searching for new mode */
- if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
- lq_sta->total_success += legacy_success;
- lq_sta->total_failed += retries + (1 - legacy_success);
- }
- }
- /* The last TX rate is cached in lq_sta; it's set in if/else above */
- lq_sta->last_rate_n_flags = lq_hwrate;
- IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
-done:
- /* See if there's a better rate or modulation mode to try. */
- if (sta->supp_rates[info->band])
- rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
-}
-
-void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- int tid, struct ieee80211_tx_info *info, bool ndp)
-{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
- /* If it's locked we are in middle of init flow
- * just wait for next tx status to update the lq_sta data
- */
- if (!mutex_trylock(&mvmsta->lq_sta.rs_drv.mutex))
- return;
-
- __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
- mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex);
-}
-
/*
* mac80211 sends us Tx status
*/
@@ -3226,6 +2954,8 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_supported_band *sband;
unsigned long supp; /* must be unsigned long for for_each_set_bit */
+ lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock);
+
/* clear all non-persistent lq data */
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
@@ -3318,6 +3048,258 @@ static void rs_drv_rate_update(void *mvm_r,
iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
}
+static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ int tid, struct ieee80211_tx_info *info,
+ bool ndp)
+{
+ int legacy_success;
+ int retries;
+ int i;
+ struct iwl_lq_cmd *table;
+ u32 lq_hwrate;
+ struct rs_rate lq_rate, tx_resp_rate;
+ struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+ u32 tlc_info = (uintptr_t)info->status.status_driver_data[0];
+ u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK;
+ u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info);
+ u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
+
+ /* Treat uninitialized rate scaling data same as non-existing. */
+ if (!lq_sta) {
+ IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
+ return;
+ } else if (!lq_sta->pers.drv) {
+ IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+ return;
+ }
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band,
+ &tx_resp_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ /* Disable last tx check if we are debugging with fixed rate but
+ * update tx stats
+ */
+ if (lq_sta->pers.dbg_fixed_rate) {
+ int index = tx_resp_rate.index;
+ enum rs_column column;
+ int attempts, success;
+
+ column = rs_get_column_from_rate(&tx_resp_rate);
+ if (WARN_ONCE(column == RS_COLUMN_INVALID,
+ "Can't map rate 0x%x to column",
+ tx_resp_hwrate))
+ return;
+
+ if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+ attempts = info->status.ampdu_len;
+ success = info->status.ampdu_ack_len;
+ } else {
+ attempts = info->status.rates[0].count;
+ success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ }
+
+ lq_sta->pers.tx_stats[column][index].total += attempts;
+ lq_sta->pers.tx_stats[column][index].success += success;
+
+ IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n",
+ tx_resp_hwrate, success, attempts);
+ return;
+ }
+#endif
+
+ if (time_after(jiffies,
+ (unsigned long)(lq_sta->last_tx +
+ (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
+ IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
+ /* reach here only in case of driver RS, call directly
+ * the unlocked version
+ */
+ rs_drv_rate_init(mvm, sta, info->band);
+ return;
+ }
+ lq_sta->last_tx = jiffies;
+
+ /* Ignore this Tx frame response if its initial rate doesn't match
+ * that of latest Link Quality command. There may be stragglers
+ * from a previous Link Quality command, but we're no longer interested
+ * in those; they're either from the "active" mode while we're trying
+ * to check "search" mode, or a prior "search" mode after we've moved
+ * to a new "search" mode (which might become the new "active" mode).
+ */
+ table = &lq_sta->lq;
+ lq_hwrate = le32_to_cpu(table->rs_table[0]);
+ if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+ /* Here we actually compare this rate to the latest LQ command */
+ if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) {
+ IWL_DEBUG_RATE(mvm,
+ "tx resp color 0x%x does not match 0x%x\n",
+ lq_color, LQ_FLAG_COLOR_GET(table->flags));
+
+ /* Since rates mis-match, the last LQ command may have failed.
+ * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+ * ... driver.
+ */
+ lq_sta->missed_rate_counter++;
+ if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
+ lq_sta->missed_rate_counter = 0;
+ IWL_DEBUG_RATE(mvm,
+ "Too many rates mismatch. Send sync LQ. rs_state %d\n",
+ lq_sta->rs_state);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq);
+ }
+ /* Regardless, ignore this status info for outdated rate */
+ return;
+ }
+
+ /* Rate did match, so reset the missed_rate_counter */
+ lq_sta->missed_rate_counter = 0;
+
+ if (!lq_sta->search_better_tbl) {
+ curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+ other_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ } else {
+ curr_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ other_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+ }
+
+ if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) {
+ IWL_DEBUG_RATE(mvm,
+ "Neither active nor search matches tx rate\n");
+ tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+ rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
+ tmp_tbl = &lq_sta->lq_info[1 - lq_sta->active_tbl];
+ rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
+ rs_dump_rate(mvm, &lq_rate, "ACTUAL");
+
+ /* no matching table found, let's by-pass the data collection
+ * and continue to perform rate scale to find the rate table
+ */
+ rs_stay_in_table(lq_sta, true);
+ goto done;
+ }
+
+ /* Updating the frame history depends on whether packets were
+ * aggregated.
+ *
+ * For aggregation, all packets were transmitted at the same rate, the
+ * first index into rate scale table.
+ */
+ if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+ rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index,
+ info->status.ampdu_len,
+ info->status.ampdu_ack_len,
+ reduced_txp);
+
+ /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat
+ * it as a single frame loss as we don't want the success ratio
+ * to dip too quickly because a BA wasn't received.
+ * For TPC, there's no need for this optimisation since we want
+ * to recover very quickly from a bad power reduction and,
+ * therefore we'd like the success ratio to get an immediate hit
+ * when failing to get a BA, so we'd switch back to a lower or
+ * zero power reduction. When FW transmits agg with a rate
+ * different from the initial rate, it will not use reduced txp
+ * and will send BA notification twice (one empty with reduced
+ * txp equal to the value from LQ and one with reduced txp 0).
+ * We need to update counters for each txp level accordingly.
+ */
+ if (info->status.ampdu_ack_len == 0)
+ info->status.ampdu_len = 1;
+
+ rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl,
+ tx_resp_rate.index,
+ info->status.ampdu_len,
+ info->status.ampdu_ack_len);
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
+ lq_sta->total_success += info->status.ampdu_ack_len;
+ lq_sta->total_failed += (info->status.ampdu_len -
+ info->status.ampdu_ack_len);
+ }
+ } else {
+ /* For legacy, update frame history with for each Tx retry. */
+ retries = info->status.rates[0].count - 1;
+ /* HW doesn't send more than 15 retries */
+ retries = min(retries, 15);
+
+ /* The last transmission may have been successful */
+ legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ /* Collect data for each rate used during failed TX attempts */
+ for (i = 0; i <= retries; ++i) {
+ lq_hwrate = le32_to_cpu(table->rs_table[i]);
+ if (rs_rate_from_ucode_rate(lq_hwrate, info->band,
+ &lq_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+ /* Only collect stats if retried rate is in the same RS
+ * table as active/search.
+ */
+ if (rs_rate_column_match(&lq_rate, &curr_tbl->rate))
+ tmp_tbl = curr_tbl;
+ else if (rs_rate_column_match(&lq_rate,
+ &other_tbl->rate))
+ tmp_tbl = other_tbl;
+ else
+ continue;
+
+ rs_collect_tpc_data(mvm, lq_sta, tmp_tbl,
+ tx_resp_rate.index, 1,
+ i < retries ? 0 : legacy_success,
+ reduced_txp);
+ rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl,
+ tx_resp_rate.index, 1,
+ i < retries ? 0 : legacy_success);
+ }
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
+ lq_sta->total_success += legacy_success;
+ lq_sta->total_failed += retries + (1 - legacy_success);
+ }
+ }
+ /* The last TX rate is cached in lq_sta; it's set in if/else above */
+ lq_sta->last_rate_n_flags = lq_hwrate;
+ IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
+done:
+ /* See if there's a better rate or modulation mode to try. */
+ if (sta->supp_rates[info->band])
+ rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
+}
+
+void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int tid, struct ieee80211_tx_info *info, bool ndp)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ /* If it's locked we are in middle of init flow
+ * just wait for next tx status to update the lq_sta data
+ */
+ if (!spin_trylock(&mvmsta->lq_sta.rs_drv.pers.lock))
+ return;
+
+ __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
+ spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
+}
+
#ifdef CONFIG_MAC80211_DEBUGFS
static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
struct iwl_lq_cmd *lq_cmd,
@@ -4177,9 +4159,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
} else {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- mutex_lock(&mvmsta->lq_sta.rs_drv.mutex);
+ spin_lock(&mvmsta->lq_sta.rs_drv.pers.lock);
rs_drv_rate_init(mvm, sta, band);
- mutex_unlock(&mvmsta->lq_sta.rs_drv.mutex);
+ spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
index 086f47e2a4f0..428642e66658 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
@@ -376,9 +376,6 @@ struct iwl_lq_sta {
/* tx power reduce for this sta */
int tpc_reduce;
- /* avoid races of reinit and update table from rx_tx */
- struct mutex mutex;
-
/* persistent fields - initialized only once - keep last! */
struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -393,6 +390,7 @@ struct iwl_lq_sta {
s8 last_rssi;
struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
struct iwl_mvm *drv;
+ spinlock_t lock; /* for races in reinit/update table */
} pers;
};
@@ -443,8 +441,6 @@ struct iwl_mvm_sta;
int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable);
-void iwl_mvm_rs_init_wk(struct work_struct *wk);
-
#ifdef CONFIG_IWLWIFI_DEBUGFS
void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm);
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 88d16b5442e7..10f18536dd0d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1685,9 +1685,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if (iwl_mvm_has_tlc_offload(mvm))
iwl_mvm_rs_add_sta(mvm, mvm_sta);
else
- mutex_init(&mvm_sta->lq_sta.rs_drv.mutex);
-
- INIT_WORK(&mvm_sta->rs_init_wk, iwl_mvm_rs_init_wk);
+ spin_lock_init(&mvm_sta->lq_sta.rs_drv.pers.lock);
iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant);
@@ -1850,8 +1848,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (ret)
return ret;
- cancel_work_sync(&mvm_sta->rs_init_wk);
-
/* flush its queues here since we are freeing mvm_sta */
ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0);
if (ret)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 4823c06e6909..8d70093847cb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -432,7 +432,6 @@ struct iwl_mvm_sta {
struct iwl_lq_sta_rs_fw rs_fw;
struct iwl_lq_sta rs_drv;
} lq_sta;
- struct work_struct rs_init_wk;
struct ieee80211_vif *vif;
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
struct iwl_mvm_rxq_dup_data *dup_data;
--
2.20.1
^ permalink raw reply related
* [PATCH 13/16] iwlwifi: mvm: fix frame drop from the reordering buffer
From: Luca Coelho @ 2019-07-20 10:25 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, Emmanuel Grumbach, Luca Coelho
In-Reply-To: <20190720102545.5952-1-luca@coelho.fi>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
An earlier patch made sure that the queues are not lagging
too far behind. This means that iwl_mvm_release_frames
should not be called with a head_sn too far behind NSSN.
Don't take the risk to change completely the entry
condition to iwl_mvm_release_frames, but don't update
the head_sn is the NSSN is more than 2048 packets ahead
of us. Since this just cannot be right. This means that
the scenario described here happened. We are queue 0.
Q:0 Q:1
head_sn: 0 -> 2047
head_sn: 2048
Lots of packets arrive:
head_sn: 2047 -> 2150
send NSSN_SYNC notification
Handle notification
from the firmware and
do NOT move the head_sn
back to 2048
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 44 ++++++++++++++-----
1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 4f4fdaf49eef..854edd7d7103 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -518,12 +518,17 @@ static void iwl_mvm_sync_nssn(struct iwl_mvm *mvm, u8 baid, u16 nssn)
#define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10)
+enum iwl_mvm_release_flags {
+ IWL_MVM_RELEASE_SEND_RSS_SYNC = BIT(0),
+ IWL_MVM_RELEASE_FROM_RSS_SYNC = BIT(1),
+};
+
static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct napi_struct *napi,
struct iwl_mvm_baid_data *baid_data,
struct iwl_mvm_reorder_buffer *reorder_buf,
- u16 nssn, bool sync_rss)
+ u16 nssn, u32 flags)
{
struct iwl_mvm_reorder_buf_entry *entries =
&baid_data->entries[reorder_buf->queue *
@@ -532,6 +537,18 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
lockdep_assert_held(&reorder_buf->lock);
+ /*
+ * We keep the NSSN not too far behind, if we are sync'ing it and it
+ * is more than 2048 ahead of us, it must be behind us. Discard it.
+ * This can happen if the queue that hit the 0 / 2048 seqno was lagging
+ * behind and this queue already processed packets. The next if
+ * would have caught cases where this queue would have processed less
+ * than 64 packets, but it may have processed more than 64 packets.
+ */
+ if ((flags & IWL_MVM_RELEASE_FROM_RSS_SYNC) &&
+ ieee80211_sn_less(nssn, ssn))
+ goto set_timer;
+
/* ignore nssn smaller than head sn - this can happen due to timeout */
if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
goto set_timer;
@@ -542,7 +559,8 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
struct sk_buff *skb;
ssn = ieee80211_sn_inc(ssn);
- if (sync_rss && (ssn == 2048 || ssn == 0))
+ if ((flags & IWL_MVM_RELEASE_SEND_RSS_SYNC) &&
+ (ssn == 2048 || ssn == 0))
iwl_mvm_sync_nssn(mvm, baid_data->baid, ssn);
/*
@@ -631,7 +649,7 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t)
iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif,
sta, baid_data->tid);
iwl_mvm_release_frames(buf->mvm, sta, NULL, baid_data,
- buf, sn, true);
+ buf, sn, IWL_MVM_RELEASE_SEND_RSS_SYNC);
rcu_read_unlock();
} else {
/*
@@ -674,7 +692,7 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf,
ieee80211_sn_add(reorder_buf->head_sn,
reorder_buf->buf_size),
- false);
+ 0);
spin_unlock_bh(&reorder_buf->lock);
del_timer_sync(&reorder_buf->reorder_timer);
@@ -684,7 +702,8 @@ static void iwl_mvm_del_ba(struct iwl_mvm *mvm, int queue,
static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm,
struct napi_struct *napi,
- u8 baid, u16 nssn, int queue)
+ u8 baid, u16 nssn, int queue,
+ u32 flags)
{
struct ieee80211_sta *sta;
struct iwl_mvm_reorder_buffer *reorder_buf;
@@ -711,7 +730,7 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm,
spin_lock_bh(&reorder_buf->lock);
iwl_mvm_release_frames(mvm, sta, napi, ba_data,
- reorder_buf, nssn, false);
+ reorder_buf, nssn, flags);
spin_unlock_bh(&reorder_buf->lock);
out:
@@ -723,7 +742,8 @@ static void iwl_mvm_nssn_sync(struct iwl_mvm *mvm,
const struct iwl_mvm_nssn_sync_data *data)
{
iwl_mvm_release_frames_from_notif(mvm, napi, data->baid,
- data->nssn, queue);
+ data->nssn, queue,
+ IWL_MVM_RELEASE_FROM_RSS_SYNC);
}
void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi,
@@ -851,7 +871,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
if (ieee80211_is_back_req(hdr->frame_control)) {
iwl_mvm_release_frames(mvm, sta, napi, baid_data,
- buffer, nssn, false);
+ buffer, nssn, 0);
goto drop;
}
@@ -871,7 +891,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;
iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer,
- min_sn, true);
+ min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC);
}
/* drop any oudated packets */
@@ -963,7 +983,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
*/
if (!amsdu || last_subframe)
iwl_mvm_release_frames(mvm, sta, napi, baid_data,
- buffer, nssn, true);
+ buffer, nssn,
+ IWL_MVM_RELEASE_SEND_RSS_SYNC);
spin_unlock_bh(&buffer->lock);
return true;
@@ -1936,5 +1957,6 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
struct iwl_frame_release *release = (void *)pkt->data;
iwl_mvm_release_frames_from_notif(mvm, napi, release->baid,
- le16_to_cpu(release->nssn), queue);
+ le16_to_cpu(release->nssn),
+ queue, 0);
}
--
2.20.1
^ permalink raw reply related
* [PATCH] rat_cs: Remove duplicate code
From: Hariprasad Kelam @ 2019-07-20 17:46 UTC (permalink / raw)
To: Kalle Valo, David S. Miller, linux-wireless, netdev, linux-kernel
Code is same if translate is true/false in case invalid packet is
received.So remove else part.
Issue identified with coccicheck
Signed-off-by: Hariprasad Kelam <hariprasad.kelam@gmail.com>
---
drivers/net/wireless/ray_cs.c | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index cf37268..a51bbe7 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -2108,29 +2108,16 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
#endif
if (!sniffer) {
- if (translate) {
/* TBD length needs fixing for translated header */
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
- }
- } else { /* encapsulated ethernet */
-
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
+ if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+ rx_len >
+ (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
+ FCS_LEN)) {
+ pr_debug(
+ "ray_cs invalid packet length %d received\n",
+ rx_len);
+ return;
}
- }
}
pr_debug("ray_cs rx_data packet\n");
/* If fragmented packet, verify sizes of fragments add up */
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] brcmfmac: change the order of things in brcmf_detach()
From: Rafał Miłecki @ 2019-07-20 16:26 UTC (permalink / raw)
To: Arend Van Spriel, Piotr Figiel; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <74b9f312-8c1a-daa8-6137-c664d37f06d1@broadcom.com>
On 30.04.2019 12:10, Arend Van Spriel wrote:
> On 4/30/2019 10:11 AM, Piotr Figiel wrote:
>> Hi Arend,
>>
>> On Mon, Apr 29, 2019 at 12:09:21PM +0200, Arend van Spriel wrote:
>>> When brcmf_detach() from the bus layer upon rmmod we can no longer
>>> communicate. Hence we will set the bus state to DOWN and cleanup
>>> the event and protocol layer. The network interfaces need to be
>>> deleted before brcmf_cfg80211_detach() because the latter does the
>>> wiphy_unregister() which issues a warning if there are still network
>>> devices linked to the wiphy instance.
>>
>> This seems to already happen - brcmf_cfg80211_detach() is called after the
>> interfaces are removed.
>
> Right. This was just to remind me why brcmf_cfg80211_detach() must be called after removing the interfaces.
>
>>> This change solves a null pointer dereference issue which happened
>>> upon issueing rmmod while there are packets queued in bus protocol
>>> layer.
>>>
>>> Reported-by: Rafał Miłecki <rafal@milecki.pl>
>>> Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
>>> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
>>> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
>>> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
>>> ---
>>> Hi Piotr,
>>>
>>> While working on an issue with msgbuf protocol (used for PCIe devices)
>>> your change 5cdb0ef6144f ("brcmfmac: fix NULL pointer derefence during
>>> USB disconnect") conflicted. I suspect my reordering stuff in
>>> brcmf_detach() also fixes your issue so could you retest this patch,
>>> which basically reverts your change and applies my reordering, and see
>>> whether my suspicion can be confirmed.
>>
>> Does the issue reported by Rafał you are trying to solve with this patch occur
>> on current linux-next?
>
> Looking at you patch I suspect it does, because brcmf_proto_msgbuf_detach() is invoked in brcmf_proto_detach_post_delif(). However, I could not reproduce it with or without the patch.
>
> Rafał,
>
> Do you know whether your reported issue, ie. calling brcmf_tx_finalize() after interfaces were removed, still exists in wireless-testing (or linux-next).
Sorry for a terribly late reply. It took me many attempts to crash a
firmware in a fully reproducible way.
I can say for sure this patch fixes crashes in brcmf_txfinalize() I saw
when unloading brcmfmac after a crash.
^ permalink raw reply
* pull-request: mac80211 2019-07-20
From: Johannes Berg @ 2019-07-20 20:24 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-wireless
Hi Dave,
Sorry, this really should've gone out much earlier, in partilar
the vendor command fixes. Not much for now, more -next material
will come later.
Please pull and let me know if there's any problem.
Thanks,
johannes
The following changes since commit 1a03bb532934e90c7d662f7c59f4f66ea8451fa4:
r8169: fix RTL8168g PHY init (2019-07-20 12:17:45 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2019-07-20
for you to fetch changes up to d2b3fe42bc629c2d4002f652b3abdfb2e72991c7:
mac80211: don't warn about CW params when not using them (2019-07-20 21:40:32 +0200)
----------------------------------------------------------------
We have a handful of fixes:
* ignore bad CW parameters if we aren't using them,
instead of warning
* fix operation (and then build) with the new netlink vendor
command policy requirement
* fix a memory leak in an error path when setting beacons
----------------------------------------------------------------
Brian Norris (1):
mac80211: don't warn about CW params when not using them
Johannes Berg (2):
wireless: fix nl80211 vendor commands
nl80211: fix VENDOR_CMD_RAW_DATA
John Crispin (1):
nl80211: fix NL80211_HE_MAX_CAPABILITY_LEN
Lorenzo Bianconi (1):
mac80211: fix possible memory leak in ieee80211_assign_beacon
drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++++
drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c | 1 +
drivers/net/wireless/ti/wlcore/vendor_cmd.c | 3 +++
include/net/cfg80211.h | 2 +-
include/uapi/linux/nl80211.h | 2 +-
net/mac80211/cfg.c | 8 ++++++--
net/mac80211/driver-ops.c | 13 +++++++++----
7 files changed, 25 insertions(+), 8 deletions(-)
^ permalink raw reply
* Re: [PATCH] mt76: mt7603: fix watchdog rescheduling in mt7603_set_channel
From: Johannes Berg @ 2019-07-20 20:28 UTC (permalink / raw)
To: Lorenzo Bianconi, nbd; +Cc: lorenzo.bianconi, linux-wireless
In-Reply-To: <a266417a71907f663991142f5ce44becc09e6996.1563490117.git.lorenzo@kernel.org>
On Fri, 2019-07-19 at 00:50 +0200, Lorenzo Bianconi wrote:
> Convert MT7603_WATCHDOG_TIME in jiffies rescheduling watchdog delayed
> work
Seems a bit inconsistent to me, the previous patch for mt7615 used
jiffies in the define, but here you convert?
johannes
^ permalink raw reply
* Re: Regression with the latest iwlwifi-9260-*-46.ucode
From: Takashi Iwai @ 2019-07-20 20:42 UTC (permalink / raw)
To: Luciano Coelho
Cc: dor.shaish, Josh Boyer, Johannes Berg, Emmanuel Grumbach,
linux-wireless, linux-kernel
In-Reply-To: <s5ho91pzyml.wl-tiwai@suse.de>
On Fri, 19 Jul 2019 20:07:46 +0200,
Takashi Iwai wrote:
>
> On Fri, 19 Jul 2019 18:36:53 +0200,
> Luciano Coelho wrote:
> >
> > Adding Dor.
> >
> > Hi Takashi,
> >
> > Do you have full logs of the crash? We can't see much from the log
> > snippet pasted in the bug report.
>
> OK, I'll ask reporters. If you have a SUSE/openSUSE bugzilla account,
> feel free to join there.
FYI, the dmesg's have been uploaded to the same bugzilla entry:
https://bugzilla.opensuse.org/show_bug.cgi?id=1142128
thanks,
Takashi
^ permalink raw reply
* Re: Regression with the latest iwlwifi-9260-*-46.ucode
From: Luca Coelho @ 2019-07-20 20:49 UTC (permalink / raw)
To: Takashi Iwai
Cc: dor.shaish, Josh Boyer, Johannes Berg, Emmanuel Grumbach,
linux-wireless, linux-kernel
In-Reply-To: <s5hwogcxwt4.wl-tiwai@suse.de>
On Sat, 2019-07-20 at 22:42 +0200, Takashi Iwai wrote:
> On Fri, 19 Jul 2019 20:07:46 +0200,
> Takashi Iwai wrote:
> > On Fri, 19 Jul 2019 18:36:53 +0200,
> > Luciano Coelho wrote:
> > > Adding Dor.
> > >
> > > Hi Takashi,
> > >
> > > Do you have full logs of the crash? We can't see much from the log
> > > snippet pasted in the bug report.
> >
> > OK, I'll ask reporters. If you have a SUSE/openSUSE bugzilla account,
> > feel free to join there.
>
> FYI, the dmesg's have been uploaded to the same bugzilla entry:
> https://bugzilla.opensuse.org/show_bug.cgi?id=1142128
>
Thanks!
BTW, I pushed new firmwares to our firmware tree in git.kernel.org
today. This is the patch:
https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/linux-firmware.git/commit/?id=b5f09bb4f816abace0227d0f4e749859364cef6b
It would be great if you can try it out and let us know whether the problem is gone or not.
--
Cheers,
Luca.
^ permalink raw reply
* Re: [PATCH 2/7] brcmfmac: change the order of things in brcmf_detach()
From: Rafał Miłecki @ 2019-07-20 21:26 UTC (permalink / raw)
To: Arend van Spriel, Kalle Valo; +Cc: linux-wireless
In-Reply-To: <1562835912-1404-3-git-send-email-arend.vanspriel@broadcom.com>
On 11.07.2019 11:05, Arend van Spriel wrote:
> When brcmf_detach() from the bus layer upon rmmod we can no longer
> communicate. Hence we will set the bus state to DOWN and cleanup
> the event and protocol layer. The network interfaces need to be
> deleted before brcmf_cfg80211_detach() because the latter does the
> wiphy_unregister() which issues a warning if there are still network
> devices linked to the wiphy instance.
>
> Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
This fixes a rmmod crash in brcmf_txfinalize() that I reported in the:
brcmfmac: NULL pointer dereference during brcmf_detach() after firmware crash
<b519e746-ddfd-421f-d897-7620d229e4b2@gmail.com>
https://www.spinics.net/lists/linux-wireless/msg182913.html
Tested-by: Rafał Miłecki <rafal@milecki.pl>
^ permalink raw reply
* Re: [PATCH] mt76: mt7603: fix watchdog rescheduling in mt7603_set_channel
From: Lorenzo Bianconi @ 2019-07-20 21:29 UTC (permalink / raw)
To: Johannes Berg; +Cc: Lorenzo Bianconi, Felix Fietkau, linux-wireless
In-Reply-To: <2dffacc1bcbf001d38a173cdce7d141a3dd130a7.camel@sipsolutions.net>
>
> On Fri, 2019-07-19 at 00:50 +0200, Lorenzo Bianconi wrote:
> > Convert MT7603_WATCHDOG_TIME in jiffies rescheduling watchdog delayed
> > work
>
> Seems a bit inconsistent to me, the previous patch for mt7615 used
> jiffies in the define, but here you convert?
>
Hi Johannes,
I personally prefer to define the timeout directly in jiffies (as it
is done in mt76x02) but MT7603_WATCHDOG_TIME is already used in this
way (e.g. mt7603_mac_work()) so I have just maintained the convention.
Anyway we can convert it as well.
Regards,
Lorenzo
> johannes
>
^ permalink raw reply
* Re: [PATCH] brcmfmac: change the order of things in brcmf_detach()
From: Arend Van Spriel @ 2019-07-20 21:34 UTC (permalink / raw)
To: Rafał Miłecki, Piotr Figiel; +Cc: linux-wireless
In-Reply-To: <b0cacc7a-22b2-82dd-f2e0-154abf1c9f69@milecki.pl>
On July 20, 2019 6:26:30 PM Rafał Miłecki <rafal@milecki.pl> wrote:
> On 30.04.2019 12:10, Arend Van Spriel wrote:
>> On 4/30/2019 10:11 AM, Piotr Figiel wrote:
>>> Hi Arend,
>>>
>>> On Mon, Apr 29, 2019 at 12:09:21PM +0200, Arend van Spriel wrote:
>>>> When brcmf_detach() from the bus layer upon rmmod we can no longer
>>>> communicate. Hence we will set the bus state to DOWN and cleanup
>>>> the event and protocol layer. The network interfaces need to be
>>>> deleted before brcmf_cfg80211_detach() because the latter does the
>>>> wiphy_unregister() which issues a warning if there are still network
>>>> devices linked to the wiphy instance.
>>>
>>> This seems to already happen - brcmf_cfg80211_detach() is called after the
>>> interfaces are removed.
>>
>> Right. This was just to remind me why brcmf_cfg80211_detach() must be
>> called after removing the interfaces.
>>
>>>> This change solves a null pointer dereference issue which happened
>>>> upon issueing rmmod while there are packets queued in bus protocol
>>>> layer.
>>>>
>>>>
>>>> Reported-by: Rafał Miłecki <rafal@milecki.pl>
>>>> Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
>>>> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
>>>> Reviewed-by: Franky Lin <franky.lin@broadcom.com>
>>>> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
>>>> ---
>>>> Hi Piotr,
>>>>
>>>>
>>>> While working on an issue with msgbuf protocol (used for PCIe devices)
>>>> your change 5cdb0ef6144f ("brcmfmac: fix NULL pointer derefence during
>>>> USB disconnect") conflicted. I suspect my reordering stuff in
>>>> brcmf_detach() also fixes your issue so could you retest this patch,
>>>> which basically reverts your change and applies my reordering, and see
>>>> whether my suspicion can be confirmed.
>>>
>>> Does the issue reported by Rafał you are trying to solve with this patch occur
>>> on current linux-next?
>>
>> Looking at you patch I suspect it does, because brcmf_proto_msgbuf_detach()
>> is invoked in brcmf_proto_detach_post_delif(). However, I could not
>> reproduce it with or without the patch.
>>
>> Rafał,
>>
>> Do you know whether your reported issue, ie. calling brcmf_tx_finalize()
>> after interfaces were removed, still exists in wireless-testing (or
>> linux-next).
>
> Sorry for a terribly late reply. It took me many attempts to crash a
> firmware in a fully reproducible way.
>
> I can say for sure this patch fixes crashes in brcmf_txfinalize() I saw
> when unloading brcmfmac after a crash.
Thanks, Rafał
There was no deadline so no need to feel sorry.
Regards,
Arend
^ permalink raw reply
* Re: [PATCH] rat_cs: Remove duplicate code
From: Stefano Brivio @ 2019-07-21 9:12 UTC (permalink / raw)
To: Hariprasad Kelam
Cc: Kalle Valo, David S. Miller, linux-wireless, netdev, linux-kernel
In-Reply-To: <20190720174613.GA31062@hari-Inspiron-1545>
On Sat, 20 Jul 2019 23:16:47 +0530
Hariprasad Kelam <hariprasad.kelam@gmail.com> wrote:
> Code is same if translate is true/false in case invalid packet is
> received.So remove else part.
>
> Issue identified with coccicheck
>
> Signed-off-by: Hariprasad Kelam <hariprasad.kelam@gmail.com>
> ---
> drivers/net/wireless/ray_cs.c | 29 ++++++++---------------------
> 1 file changed, 8 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
> index cf37268..a51bbe7 100644
> --- a/drivers/net/wireless/ray_cs.c
> +++ b/drivers/net/wireless/ray_cs.c
> @@ -2108,29 +2108,16 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
> #endif
>
> if (!sniffer) {
> - if (translate) {
> /* TBD length needs fixing for translated header */
> - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
> - rx_len >
> - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
> - FCS_LEN)) {
> - pr_debug(
> - "ray_cs invalid packet length %d received\n",
> - rx_len);
> - return;
> - }
> - } else { /* encapsulated ethernet */
> -
> - if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
> - rx_len >
> - (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
> - FCS_LEN)) {
> - pr_debug(
> - "ray_cs invalid packet length %d received\n",
> - rx_len);
> - return;
> + if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
> + rx_len >
> + (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
> + FCS_LEN)) {
> + pr_debug(
> + "ray_cs invalid packet length %d received\n",
> + rx_len);
> + return;
> }
> - }
NACK. The TBD comment makes no sense anymore if you remove one of the
branches. Believe me or not, I have one of those cards, a (yes, 22
years old) Buslink Raytheon model 24020. That check needed (for sure)
and needs (maybe) to be fixed.
Besides, patch subject and resulting coding style are also wrong.
--
Stefano
^ permalink raw reply
* Re: [PATCH 1/3] mt76: fix checkpatch warnings and errors
From: Kalle Valo @ 2019-07-21 10:26 UTC (permalink / raw)
To: Ryder Lee
Cc: Felix Fietkau, Lorenzo Bianconi, Roy Luo, YF Luo, Yiwei Chung,
Sean Wang, linux-wireless, linux-mediatek, linux-kernel
In-Reply-To: <50d28c9b0f9e7d6b277d36fc93f55142d7535259.1563518381.git.ryder.lee@mediatek.com>
Ryder Lee <ryder.lee@mediatek.com> writes:
> Fix warnings and errors as much as possible.
>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> ---
> drivers/net/wireless/mediatek/mt76/agg-rx.c | 21 +++++----
> drivers/net/wireless/mediatek/mt76/dma.c | 2 +-
> drivers/net/wireless/mediatek/mt76/mac80211.c | 30 ++++++------
> drivers/net/wireless/mediatek/mt76/mt76.h | 46 +++++++++----------
> .../wireless/mediatek/mt76/mt7603/beacon.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7603/core.c | 2 +-
> .../wireless/mediatek/mt76/mt7603/debugfs.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7603/dma.c | 7 +--
> .../wireless/mediatek/mt76/mt7603/eeprom.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7603/init.c | 3 +-
> .../net/wireless/mediatek/mt76/mt7603/mac.c | 6 +--
> .../net/wireless/mediatek/mt76/mt7603/main.c | 7 +--
> .../net/wireless/mediatek/mt76/mt7603/mcu.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7603/pci.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7603/soc.c | 2 +-
> .../wireless/mediatek/mt76/mt7615/debugfs.c | 2 +-
> .../net/wireless/mediatek/mt76/mt7615/mac.c | 5 +-
> .../net/wireless/mediatek/mt76/mt7615/mcu.c | 2 -
> .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 +-
> .../net/wireless/mediatek/mt76/mt76x0/phy.c | 23 ++++++----
> .../net/wireless/mediatek/mt76/mt76x0/phy.h | 10 ++--
> .../net/wireless/mediatek/mt76/mt76x0/usb.c | 6 +--
> drivers/net/wireless/mediatek/mt76/mt76x02.h | 24 +++++-----
> .../wireless/mediatek/mt76/mt76x02_beacon.c | 3 +-
> .../net/wireless/mediatek/mt76/mt76x02_mac.c | 16 +++----
> .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 13 +++---
> .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 11 +++--
> .../net/wireless/mediatek/mt76/mt76x02_phy.c | 3 +-
> .../net/wireless/mediatek/mt76/mt76x02_regs.h | 18 ++++----
> .../wireless/mediatek/mt76/mt76x02_trace.h | 3 +-
> .../wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +-
> .../net/wireless/mediatek/mt76/mt76x02_util.c | 20 ++++----
> .../wireless/mediatek/mt76/mt76x2/eeprom.c | 10 ++--
> .../wireless/mediatek/mt76/mt76x2/pci_init.c | 1 -
> .../wireless/mediatek/mt76/mt76x2/pci_mcu.c | 4 +-
> .../net/wireless/mediatek/mt76/mt76x2/phy.c | 3 +-
> drivers/net/wireless/mediatek/mt76/trace.h | 9 ++--
> drivers/net/wireless/mediatek/mt76/tx.c | 14 +++---
> drivers/net/wireless/mediatek/mt76/usb.c | 31 +++++++------
> .../net/wireless/mediatek/mt76/usb_trace.h | 11 +++--
> drivers/net/wireless/mediatek/mt76/util.h | 4 +-
> 41 files changed, 201 insertions(+), 185 deletions(-)
This is way too big and the commit log is too vague, please fix one
problem at a time and describe in the commit log what you fixed.
--
Kalle Valo
^ permalink raw reply
* Re: [PATCH 3/3] mt76: mt7615: add cwmin/cwmax initial values
From: Kalle Valo @ 2019-07-21 10:28 UTC (permalink / raw)
To: Ryder Lee
Cc: Felix Fietkau, Lorenzo Bianconi, Roy Luo, YF Luo, Yiwei Chung,
Sean Wang, linux-wireless, linux-mediatek, linux-kernel
In-Reply-To: <c83e14787bc86f8f8062e0aa44e03ef80c3fd38a.1563518381.git.ryder.lee@mediatek.com>
Ryder Lee <ryder.lee@mediatek.com> writes:
> Add initial values in mt7615_mcu_set_wmm() to cleanup setup flow.
>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
[...]
> -#define WMM_AIFS_SET BIT(0)
> -#define WMM_CW_MIN_SET BIT(1)
> -#define WMM_CW_MAX_SET BIT(2)
> -#define WMM_TXOP_SET BIT(3)
> +#define WMM_PARAM_SET GENMASK(3, 0)
I don't see how this is any better? IMHO you just hide what is the
meaning of each bit.
--
Kalle Valo
^ permalink raw reply
* Problems loading ath9k (ar93xx) calibration data
From: Kristian Evensen @ 2019-07-21 13:10 UTC (permalink / raw)
To: linux-wireless
Hello,
I am currently trying to bring up a ramips-based board with a built-in
wifi based on ar93xx. The wifi does not have an eeprom, instead the
calibration data is stored on the flash storage. I have set the
"qca,no-eeprom" option in the node in the dts, extracted the
calibration data and stored it in a file with the correct name in
/lib/firmware. The content of calibration data file can be seen here:
https://pastebin.com/zF6cRetV
I can see that the firmware file is loaded when I boot my board, but
initialization of the wifi device fails. The error message I get is:
[ 12.314349] bus=0x1, slot = 0x0, irq=0xff
[ 12.318839] ath9k 0000:01:00.0: Direct firmware load for
ath9k-eeprom-pci-0000:01:00.0.bin failed with error -2
[ 12.328932] ath9k 0000:01:00.0: Falling back to user helper
[ 12.424131] ath: phy0: both bands are disabled
[ 12.428713] ath: phy0: Unable to initialize hardware;
initialization status: -22
[ 12.436127] ath9k 0000:01:00.0: Failed to initialize device
[ 12.441890] ath9k: probe of 0000:01:00.0 failed with error -22
When looking into the content of the eeprom-file, I see that the byte
matching opFlags has the value 0x08. Based on my understanding of the
driver, the only valid values are 0x1, 0x2 and 0x3.
Considering that the next byte has the value 0x1, I suspect the issue
might be related to endianess. However, I haven't found a way to
trigger an endianess-conversion when the calibration data is read for
file. Is there something I am missing or is this not supported?
Could endianess be an explanation for the error I am seeing, or are
there other things in the calibration data the looks like it could
cause problems as well?
Thanks in advance for any help.
BR,
Kristian
^ permalink raw reply
* Re: Problems loading ath9k (ar93xx) calibration data
From: Kristian Evensen @ 2019-07-21 13:52 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <CAKfDRXhVQvJYAiacyMx0sGqrh6L7KR606FaBdh4nhznsKY0TMg@mail.gmail.com>
Hello again,
On Sun, Jul 21, 2019 at 3:10 PM Kristian Evensen
<kristian.evensen@gmail.com> wrote:
> Considering that the next byte has the value 0x1, I suspect the issue
> might be related to endianess. However, I haven't found a way to
> trigger an endianess-conversion when the calibration data is read for
> file. Is there something I am missing or is this not supported?
>
> Could endianess be an explanation for the error I am seeing, or are
> there other things in the calibration data the looks like it could
> cause problems as well?
I took a second look at the ath9k-driver and see that 0x1 is the value
of AR5416_OPFLAGS_11A, which sets the CAP_5GHz flag. My card is only
2.4 GHz, so then I guess the endianess-theory was wrong.
BR,
Kristian
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox