* [PATCH 04/16] iwlwifi: mvm: re-aggregate shared queue after unsharing
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Liad Kaufman, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Liad Kaufman <liad.kaufman@intel.com>
When a shared queue becomes unshared, aggregations should be
re-enabled if they've existed before. Make sure that they do
this, if required.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 17 +++
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 166 +++++++++++++++++++++----
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 +
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 38 +++++-
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 8 +-
5 files changed, 205 insertions(+), 28 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 28ebc12..ee5a9ad 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -697,6 +697,10 @@ struct iwl_mvm_baid_data {
* it. In this state, when a new queue is needed to be allocated but no
* such free queue exists, an inactive queue might be freed and given to
* the new RA/TID.
+ * @IWL_MVM_QUEUE_RECONFIGURING: queue is being reconfigured
+ * This is the state of a queue that has had traffic pass through it, but
+ * needs to be reconfigured for some reason, e.g. the queue needs to
+ * become unshared and aggregations re-enabled on.
*/
enum iwl_mvm_queue_status {
IWL_MVM_QUEUE_FREE,
@@ -704,6 +708,7 @@ enum iwl_mvm_queue_status {
IWL_MVM_QUEUE_READY,
IWL_MVM_QUEUE_SHARED,
IWL_MVM_QUEUE_INACTIVE,
+ IWL_MVM_QUEUE_RECONFIGURING,
};
#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ)
@@ -1122,6 +1127,18 @@ static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
(mvm->trans->runtime_pm_mode != IWL_PLAT_PM_MODE_D0I3);
}
+static inline bool iwl_mvm_is_dqa_data_queue(struct iwl_mvm *mvm, u8 queue)
+{
+ return (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE) &&
+ (queue <= IWL_MVM_DQA_MAX_DATA_QUEUE);
+}
+
+static inline bool iwl_mvm_is_dqa_mgmt_queue(struct iwl_mvm *mvm, u8 queue)
+{
+ return (queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE) &&
+ (queue <= IWL_MVM_DQA_MAX_MGMT_QUEUE);
+}
+
static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
{
bool nvm_lar = mvm->nvm_data->lar_enabled;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 5960eb4..1f235e8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -468,6 +468,11 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
i != IWL_MVM_DQA_BSS_CLIENT_QUEUE)
continue;
+ /* Don't try and take queues being reconfigured */
+ if (mvm->queue_info[queue].status ==
+ IWL_MVM_QUEUE_RECONFIGURING)
+ continue;
+
ac_to_queue[mvm->queue_info[i].mac80211_ac] = i;
}
@@ -501,27 +506,33 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
queue = ac_to_queue[IEEE80211_AC_VO];
/* Make sure queue found (or not) is legal */
- if (!((queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE &&
- queue <= IWL_MVM_DQA_MAX_MGMT_QUEUE) ||
- (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE &&
- queue <= IWL_MVM_DQA_MAX_DATA_QUEUE) ||
- (queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE))) {
+ if (!iwl_mvm_is_dqa_data_queue(mvm, queue) &&
+ !iwl_mvm_is_dqa_mgmt_queue(mvm, queue) &&
+ (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)) {
IWL_ERR(mvm, "No DATA queues available to share\n");
- queue = -ENOSPC;
+ return -ENOSPC;
+ }
+
+ /* Make sure the queue isn't in the middle of being reconfigured */
+ if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_RECONFIGURING) {
+ IWL_ERR(mvm,
+ "TXQ %d is in the middle of re-config - try again\n",
+ queue);
+ return -EBUSY;
}
return queue;
}
/*
- * If a given queue has a higher AC than the TID stream that is being added to
- * it, the queue needs to be redirected to the lower AC. This function does that
+ * If a given queue has a higher AC than the TID stream that is being compared
+ * to, the queue needs to be redirected to the lower AC. This function does that
* in such a case, otherwise - if no redirection required - it does nothing,
* unless the %force param is true.
*/
-static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
- int ac, int ssn, unsigned int wdg_timeout,
- bool force)
+int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
+ int ac, int ssn, unsigned int wdg_timeout,
+ bool force)
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
@@ -555,7 +566,7 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1);
spin_unlock_bh(&mvm->queue_info_lock);
- IWL_DEBUG_TX_QUEUES(mvm, "Redirecting shared TXQ #%d to FIFO #%d\n",
+ IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n",
queue, iwl_mvm_ac_to_tx_fifo[ac]);
/* Stop MAC queues and wait for this queue to empty */
@@ -709,7 +720,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
if (WARN_ON(queue <= 0)) {
IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n",
tid, cfg.sta_id);
- return -ENOSPC;
+ return queue;
}
/*
@@ -827,6 +838,84 @@ out_err:
return ret;
}
+static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ s8 sta_id;
+ int tid = -1;
+ unsigned long tid_bitmap;
+ unsigned int wdg_timeout;
+ int ssn;
+ int ret = true;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ sta_id = mvm->queue_info[queue].ra_sta_id;
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ /* Find TID for queue, and make sure it is the only one on the queue */
+ tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
+ if (tid_bitmap != BIT(tid)) {
+ IWL_ERR(mvm, "Failed to unshare q %d, active tids=0x%lx\n",
+ queue, tid_bitmap);
+ return;
+ }
+
+ IWL_DEBUG_TX_QUEUES(mvm, "Unsharing TXQ %d, keeping tid %d\n", queue,
+ tid);
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
+ return;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
+
+ ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number);
+
+ ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid,
+ tid_to_mac80211_ac[tid], ssn,
+ wdg_timeout, true);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue);
+ return;
+ }
+
+ /* If aggs should be turned back on - do it */
+ if (mvmsta->tid_data[tid].state == IWL_AGG_ON) {
+ struct iwl_mvm_add_sta_cmd cmd;
+
+ mvmsta->tid_disable_agg &= ~BIT(tid);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
+ cmd.sta_id = mvmsta->sta_id;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+ cmd.tfd_queue_msk = cpu_to_le32(mvmsta->tfd_queue_msk);
+ cmd.tid_disable_tx = cpu_to_le16(mvmsta->tid_disable_agg);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+ iwl_mvm_add_sta_cmd_size(mvm), &cmd);
+ if (!ret) {
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "TXQ #%d is now aggregated again\n",
+ queue);
+
+ /* Mark queue intenally as aggregating again */
+ iwl_trans_txq_set_shared_mode(mvm->trans, queue, false);
+ }
+ }
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
+ spin_unlock_bh(&mvm->queue_info_lock);
+}
+
static inline u8 iwl_mvm_tid_to_ac_queue(int tid)
{
if (tid == IWL_MAX_TID_COUNT)
@@ -894,13 +983,26 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
unsigned long deferred_tid_traffic;
- int sta_id, tid;
+ int queue, sta_id, tid;
/* Check inactivity of queues */
iwl_mvm_inactivity_check(mvm);
mutex_lock(&mvm->mutex);
+ /* Reconfigure queues requiring reconfiguation */
+ for (queue = 0; queue < IWL_MAX_HW_QUEUES; queue++) {
+ bool reconfig;
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ reconfig = (mvm->queue_info[queue].status ==
+ IWL_MVM_QUEUE_RECONFIGURING);
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ if (reconfig)
+ iwl_mvm_unshare_queue(mvm, queue);
+ }
+
/* Go over all stations with deferred traffic */
for_each_set_bit(sta_id, mvm->sta_deferred_frames,
IWL_MVM_STATION_COUNT) {
@@ -1956,7 +2058,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO;
}
- spin_lock_bh(&mvm->queue_info_lock);
+ spin_lock(&mvm->queue_info_lock);
/*
* Note the possible cases:
@@ -1967,14 +2069,20 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* non-DQA mode, since the TXQ hasn't yet been allocated
*/
txq_id = mvmsta->tid_data[tid].txq_id;
- if (!iwl_mvm_is_dqa_supported(mvm) ||
+ if (iwl_mvm_is_dqa_supported(mvm) &&
+ unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED)) {
+ ret = -ENXIO;
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Can't start tid %d agg on shared queue!\n",
+ tid);
+ goto release_locks;
+ } else if (!iwl_mvm_is_dqa_supported(mvm) ||
mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
mvm->first_agg_queue,
mvm->last_agg_queue);
if (txq_id < 0) {
ret = txq_id;
- spin_unlock_bh(&mvm->queue_info_lock);
IWL_ERR(mvm, "Failed to allocate agg queue\n");
goto release_locks;
}
@@ -1982,7 +2090,8 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* TXQ hasn't yet been enabled, so mark it only as reserved */
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED;
}
- spin_unlock_bh(&mvm->queue_info_lock);
+
+ spin_unlock(&mvm->queue_info_lock);
IWL_DEBUG_TX_QUEUES(mvm,
"AGG for tid %d will be on queue #%d\n",
@@ -2006,8 +2115,11 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
ret = 0;
+ goto out;
release_locks:
+ spin_unlock(&mvm->queue_info_lock);
+out:
spin_unlock_bh(&mvmsta->lock);
return ret;
@@ -2023,6 +2135,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false);
int queue, ret;
bool alloc_queue = true;
+ enum iwl_mvm_queue_status queue_status;
u16 ssn;
struct iwl_trans_txq_scd_cfg cfg = {
@@ -2048,13 +2161,15 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cfg.fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+ spin_lock_bh(&mvm->queue_info_lock);
+ queue_status = mvm->queue_info[queue].status;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
/* In DQA mode, the existing queue might need to be reconfigured */
if (iwl_mvm_is_dqa_supported(mvm)) {
- spin_lock_bh(&mvm->queue_info_lock);
/* Maybe there is no need to even alloc a queue... */
if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY)
alloc_queue = false;
- spin_unlock_bh(&mvm->queue_info_lock);
/*
* Only reconfig the SCD for the queue if the window size has
@@ -2089,9 +2204,12 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
vif->hw_queue[tid_to_mac80211_ac[tid]], ssn,
&cfg, wdg_timeout);
- ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
- if (ret)
- return -EIO;
+ /* Send ADD_STA command to enable aggs only if the queue isn't shared */
+ if (queue_status != IWL_MVM_QUEUE_SHARED) {
+ ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
+ if (ret)
+ return -EIO;
+ }
/* No need to mark as reserved */
spin_lock_bh(&mvm->queue_info_lock);
@@ -2123,7 +2241,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16 txq_id;
int err;
-
/*
* If mac80211 is cleaning its state, then say that we finished since
* our state has been cleared anyway.
@@ -2152,6 +2269,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*/
if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED)
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE;
+
spin_unlock_bh(&mvm->queue_info_lock);
switch (tid_data->state) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index bbc1cab..709542b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -554,4 +554,8 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
+int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
+ int ac, int ssn, unsigned int wdg_timeout,
+ bool force);
+
#endif /* __sta_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index c6585ab..8b91544 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -838,6 +838,22 @@ static void iwl_mvm_tx_add_stream(struct iwl_mvm *mvm,
}
}
+/* Check if there are any timed-out TIDs on a given shared TXQ */
+static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id)
+{
+ unsigned long queue_tid_bitmap = mvm->queue_info[txq_id].tid_bitmap;
+ unsigned long now = jiffies;
+ int tid;
+
+ for_each_set_bit(tid, &queue_tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ if (time_before(mvm->queue_info[txq_id].last_frame_time[tid] +
+ IWL_MVM_DQA_QUEUE_TIMEOUT, now))
+ return true;
+ }
+
+ return false;
+}
+
/*
* Sets the fields in the Tx cmd that are crypto related
*/
@@ -940,7 +956,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
spin_unlock(&mvmsta->lock);
return 0;
-
}
/* If we are here - TXQ exists and needs to be re-activated */
@@ -953,8 +968,25 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
txq_id);
}
- /* Keep track of the time of the last frame for this RA/TID */
- mvm->queue_info[txq_id].last_frame_time[tid] = jiffies;
+ if (iwl_mvm_is_dqa_supported(mvm)) {
+ /* Keep track of the time of the last frame for this RA/TID */
+ mvm->queue_info[txq_id].last_frame_time[tid] = jiffies;
+
+ /*
+ * If we have timed-out TIDs - schedule the worker that will
+ * reconfig the queues and update them
+ *
+ * Note that the mvm->queue_info_lock isn't being taken here in
+ * order to not serialize the TX flow. This isn't dangerous
+ * because scheduling mvm->add_stream_wk can't ruin the state,
+ * and if we DON'T schedule it due to some race condition then
+ * next TX we get here we will.
+ */
+ if (unlikely(mvm->queue_info[txq_id].status ==
+ IWL_MVM_QUEUE_SHARED &&
+ iwl_mvm_txq_should_update(mvm, txq_id)))
+ schedule_work(&mvm->add_stream_wk);
+ }
IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
tid, txq_id, IEEE80211_SEQ_TO_SN(seq_number));
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 68f4e7f..dae64a6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1131,7 +1131,13 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]);
}
- /* TODO: if queue was shared - need to re-enable AGGs */
+ /* If the queue is marked as shared - "unshare" it */
+ if (mvm->queue_info[queue].hw_queue_refcount == 1 &&
+ mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) {
+ mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING;
+ IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n",
+ queue);
+ }
}
void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
--
2.8.1
^ permalink raw reply related
* [PATCH 03/16] iwlwifi: mvm: support new paging command format
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Sara Sharon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Sara Sharon <sara.sharon@intel.com>
For a000 devices there is a support of 64 bit DMA addressing.
The paging command was changed accordingly - support it.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 8 +++++--
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 28 ++++++++++++++++++-------
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++++
3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
index 71076f0..57b574b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
@@ -482,13 +482,17 @@ struct iwl_nvm_access_cmd {
* @block_size: the block size in powers of 2
* @block_num: number of blocks specified in the command.
* @device_phy_addr: virtual addresses from device side
+ * 32 bit address for API version 1, 64 bit address for API version 2.
*/
struct iwl_fw_paging_cmd {
__le32 flags;
__le32 block_size;
__le32 block_num;
- __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS];
-} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */
+ union {
+ __le32 addr32[NUM_OF_FW_PAGING_BLOCKS];
+ __le64 addr64[NUM_OF_FW_PAGING_BLOCKS];
+ } device_phy_addr;
+} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_2 */
/*
* Fw items ID's
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 7e0cdbf..47e8e70 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -385,9 +385,7 @@ static int iwl_save_fw_paging(struct iwl_mvm *mvm,
/* send paging cmd to FW in case CPU2 has paging image */
static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw)
{
- int blk_idx;
- __le32 dev_phy_addr;
- struct iwl_fw_paging_cmd fw_paging_cmd = {
+ struct iwl_fw_paging_cmd paging_cmd = {
.flags =
cpu_to_le32(PAGING_CMD_IS_SECURED |
PAGING_CMD_IS_ENABLED |
@@ -396,18 +394,32 @@ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw)
.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE),
.block_num = cpu_to_le32(mvm->num_of_paging_blk),
};
+ int blk_idx, size = sizeof(paging_cmd);
+
+ /* A bit hard coded - but this is the old API and will be deprecated */
+ if (!iwl_mvm_has_new_tx_api(mvm))
+ size -= NUM_OF_FW_PAGING_BLOCKS * 4;
/* loop for for all paging blocks + CSS block */
for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) {
- dev_phy_addr =
- cpu_to_le32(mvm->fw_paging_db[blk_idx].fw_paging_phys >>
- PAGE_2_EXP_SIZE);
- fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr;
+ dma_addr_t addr = mvm->fw_paging_db[blk_idx].fw_paging_phys;
+
+ addr = addr >> PAGE_2_EXP_SIZE;
+
+ if (iwl_mvm_has_new_tx_api(mvm)) {
+ __le64 phy_addr = cpu_to_le64(addr);
+
+ paging_cmd.device_phy_addr.addr64[blk_idx] = phy_addr;
+ } else {
+ __le32 phy_addr = cpu_to_le32(addr);
+
+ paging_cmd.device_phy_addr.addr32[blk_idx] = phy_addr;
+ }
}
return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD,
IWL_ALWAYS_LONG_GROUP, 0),
- 0, sizeof(fw_paging_cmd), &fw_paging_cmd);
+ 0, size, &paging_cmd);
}
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 0b0855a..28ebc12 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1192,6 +1192,12 @@ static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT);
}
+static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm)
+{
+ /* TODO - replace with TLV once defined */
+ return mvm->trans->cfg->use_tfh;
+}
+
static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm)
{
#ifdef CONFIG_THERMAL
--
2.8.1
^ permalink raw reply related
* [PATCH 05/16] iwlwifi: mvm: keep track of tid associated with each queue
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Liad Kaufman, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Liad Kaufman <liad.kaufman@intel.com>
When sending the SCD_QUEUE_CONFIG command, the queue is
associated to a specific TID. If later there is a need to
use this TID on a different queue instead, it first needs to
be unassociated from the first queue.
Keep track for every queue what TID is associated with it.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 +
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 +++++++
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 3 +++
3 files changed, 11 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index ee5a9ad..1806495 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -772,6 +772,7 @@ struct iwl_mvm {
u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
bool reserved; /* Is this the TXQ reserved for a STA */
u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */
+ u8 txq_tid; /* The TID "owner" of this queue*/
u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
/* Timestamp for inactivation per TID of this queue */
unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1];
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 1f235e8..730ba78 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -562,6 +562,7 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac];
+ cmd.tid = mvm->queue_info[queue].txq_tid;
mq = mvm->queue_info[queue].hw_queue_to_mac80211;
shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1);
spin_unlock_bh(&mvm->queue_info_lock);
@@ -591,6 +592,11 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
cmd.sta_id, tid, LINK_QUAL_AGG_FRAME_LIMIT_DEF,
ssn, wdg_timeout);
+ /* Update the TID "owner" of the queue */
+ spin_lock_bh(&mvm->queue_info_lock);
+ mvm->queue_info[queue].txq_tid = tid;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
/* TODO: Work-around SCD bug when moving back by multiples of 0x40 */
/* Redirect to lower AC */
@@ -749,6 +755,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
ac = mvm->queue_info[queue].mac80211_ac;
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[ac];
+ cmd.tid = mvm->queue_info[queue].txq_tid;
spin_unlock_bh(&mvm->queue_info_lock);
/* Disable the queue */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index dae64a6..423efab 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -669,6 +669,8 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
tid_to_mac80211_ac[cfg->tid];
else
mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO;
+
+ mvm->queue_info[queue].txq_tid = cfg->tid;
}
IWL_DEBUG_TX_QUEUES(mvm,
@@ -761,6 +763,7 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
}
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
+ cmd.tid = mvm->queue_info[queue].txq_tid;
/* Make sure queue info is correct even though we overwrite it */
WARN(mvm->queue_info[queue].hw_queue_refcount ||
--
2.8.1
^ permalink raw reply related
* [PATCH 06/16] iwlwifi: mvm: re-assign old queues after hw restart in dqa mode
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Liad Kaufman, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Liad Kaufman <liad.kaufman@intel.com>
When working in DQA mode, if a queue is shared and a HW restart
occurs, there might be a possible race condition between
stations on the queues, and an existing queue might be left
with no queues.
To solve this, make sure in DQA mode to re-assign the same
queues as before the HW restart.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 72 +++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 730ba78..1ddcbea 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -759,8 +759,9 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
spin_unlock_bh(&mvm->queue_info_lock);
/* Disable the queue */
- iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids,
- true);
+ if (disable_agg_tids)
+ iwl_mvm_invalidate_sta_queue(mvm, queue,
+ disable_agg_tids, false);
iwl_trans_txq_disable(mvm->trans, queue, false);
ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
&cmd);
@@ -776,6 +777,10 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
return ret;
}
+
+ /* If TXQ is allocated to another STA, update removal in FW */
+ if (cmd.sta_id != mvmsta->sta_id)
+ iwl_mvm_invalidate_sta_queue(mvm, queue, 0, true);
}
IWL_DEBUG_TX_QUEUES(mvm,
@@ -1072,6 +1077,61 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
return 0;
}
+/*
+ * In DQA mode, after a HW restart the queues should be allocated as before, in
+ * order to avoid race conditions when there are shared queues. This function
+ * does the re-mapping and queue allocation.
+ *
+ * Note that re-enabling aggregations isn't done in this function.
+ */
+static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvm_sta)
+{
+ unsigned int wdg_timeout =
+ iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false);
+ int i;
+ struct iwl_trans_txq_scd_cfg cfg = {
+ .sta_id = mvm_sta->sta_id,
+ .frame_limit = IWL_FRAME_LIMIT,
+ };
+
+ /* Make sure reserved queue is still marked as such (or allocated) */
+ mvm->queue_info[mvm_sta->reserved_queue].status =
+ IWL_MVM_QUEUE_RESERVED;
+
+ for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
+ struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i];
+ int txq_id = tid_data->txq_id;
+ int ac;
+ u8 mac_queue;
+
+ if (txq_id == IEEE80211_INVAL_HW_QUEUE)
+ continue;
+
+ skb_queue_head_init(&tid_data->deferred_tx_frames);
+
+ ac = tid_to_mac80211_ac[i];
+ mac_queue = mvm_sta->vif->hw_queue[ac];
+
+ cfg.tid = i;
+ cfg.fifo = iwl_mvm_ac_to_tx_fifo[ac];
+ cfg.aggregate = (txq_id >= IWL_MVM_DQA_MIN_DATA_QUEUE ||
+ txq_id == IWL_MVM_DQA_BSS_CLIENT_QUEUE);
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Re-mapping sta %d tid %d to queue %d\n",
+ mvm_sta->sta_id, i, txq_id);
+
+ iwl_mvm_enable_txq(mvm, txq_id, mac_queue,
+ IEEE80211_SEQ_TO_SN(tid_data->seq_number),
+ &cfg, wdg_timeout);
+
+ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY;
+ }
+
+ atomic_set(&mvm->pending_frames[mvm_sta->sta_id], 0);
+}
+
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -1094,6 +1154,13 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
spin_lock_init(&mvm_sta->lock);
+ /* In DQA mode, if this is a HW restart, re-alloc existing queues */
+ if (iwl_mvm_is_dqa_supported(mvm) &&
+ test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta);
+ goto update_fw;
+ }
+
mvm_sta->sta_id = sta_id;
mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color);
@@ -1157,6 +1224,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
goto err;
}
+update_fw:
ret = iwl_mvm_sta_send_to_fw(mvm, sta, false, 0);
if (ret)
goto err;
--
2.8.1
^ permalink raw reply related
* [PATCH 07/16] iwlwifi: mvm: use defines for SCD_CONFIG_CMD enablement
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Liad Kaufman, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Liad Kaufman <liad.kaufman@intel.com>
Due to the addition of another option in the SCD_CONFIG_CMD's
%enable field, change the assignment of this field to use
defines rather than hard-code the value itself.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 12 ++++++++++--
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 13 +++++++------
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h
index 4144623..6b4c63a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h
@@ -675,13 +675,21 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp)
tx_resp->frame_count) & 0xfff;
}
+/* Available options for the SCD_QUEUE_CFG HCMD */
+enum iwl_scd_cfg_actions {
+ SCD_CFG_DISABLE_QUEUE = 0x0,
+ SCD_CFG_ENABLE_QUEUE = 0x1,
+ SCD_CFG_UPDATE_QUEUE_TID = 0x2,
+};
+
/**
* struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
* @token:
* @sta_id: station id
* @tid:
* @scd_queue: scheduler queue to confiug
- * @enable: 1 queue enable, 0 queue disable
+ * @action: 1 queue enable, 0 queue disable, 2 change txq's tid owner
+ * Value is one of %iwl_scd_cfg_actions options
* @aggregate: 1 aggregated queue, 0 otherwise
* @tx_fifo: %enum iwl_mvm_tx_fifo
* @window: BA window size
@@ -692,7 +700,7 @@ struct iwl_scd_txq_cfg_cmd {
u8 sta_id;
u8 tid;
u8 scd_queue;
- u8 enable;
+ u8 action;
u8 aggregate;
u8 tx_fifo;
u8 window;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 1ddcbea..e87473a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -536,7 +536,7 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
- .enable = 0,
+ .action = SCD_CFG_DISABLE_QUEUE,
};
bool shared_queue;
unsigned long mq;
@@ -745,7 +745,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
if (using_inactive_queue) {
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
- .enable = 0,
+ .action = SCD_CFG_DISABLE_QUEUE,
};
u8 ac;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 423efab..7c138fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -610,7 +610,7 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
- .enable = 1,
+ .action = SCD_CFG_ENABLE_QUEUE,
.window = frame_limit,
.sta_id = sta_id,
.ssn = cpu_to_le16(ssn),
@@ -684,7 +684,7 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
if (enable_queue) {
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
- .enable = 1,
+ .action = SCD_CFG_ENABLE_QUEUE,
.window = cfg->frame_limit,
.sta_id = cfg->sta_id,
.ssn = cpu_to_le16(ssn),
@@ -711,7 +711,7 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
- .enable = 0,
+ .action = SCD_CFG_DISABLE_QUEUE,
};
bool remove_mac_queue = true;
int ret;
@@ -746,8 +746,9 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
~BIT(mac80211_queue);
mvm->queue_info[queue].hw_queue_refcount--;
- cmd.enable = mvm->queue_info[queue].hw_queue_refcount ? 1 : 0;
- if (!cmd.enable)
+ cmd.action = mvm->queue_info[queue].hw_queue_refcount ?
+ SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE;
+ if (cmd.action == SCD_CFG_DISABLE_QUEUE)
mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE;
IWL_DEBUG_TX_QUEUES(mvm,
@@ -757,7 +758,7 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
mvm->queue_info[queue].hw_queue_to_mac80211);
/* If the queue is still enabled - nothing left to do in this func */
- if (cmd.enable) {
+ if (cmd.action == SCD_CFG_ENABLE_QUEUE) {
spin_unlock_bh(&mvm->queue_info_lock);
return;
}
--
2.8.1
^ permalink raw reply related
* [PATCH 08/16] iwlwifi: mvm: support txq tid owner change
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Liad Kaufman, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Liad Kaufman <liad.kaufman@intel.com>
Every active TXQ is assigned to a TID given through the
SCD_CONFIG_CMD, and acts as an identifier in the FW. However,
there may be cases this ownership needs to be changed.
For example, in the following scenario:
1. TID x is owner of a queue
2. Due to a shortage of queues, TID y and z share with x
3. TID x becomes inactive and needs to be removed from the
shared queue.
In this scenario, if another queue is freed and traffic on x
continues, we can't allocate it a new queue as long as it is
the owner of the first queue.
Support moving ownership of a TXQ to a different TID (same
STA) without stopping the queue.
Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 51 ++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index e87473a..30fc3af 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -850,6 +850,41 @@ out_err:
return ret;
}
+static void iwl_mvm_change_queue_owner(struct iwl_mvm *mvm, int queue)
+{
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .action = SCD_CFG_UPDATE_QUEUE_TID,
+ };
+ s8 sta_id;
+ int tid;
+ unsigned long tid_bitmap;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ sta_id = mvm->queue_info[queue].ra_sta_id;
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ if (WARN(!tid_bitmap, "TXQ %d has no tids assigned to it\n", queue))
+ return;
+
+ /* Find any TID for queue */
+ tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
+ cmd.tid = tid;
+ cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to update owner of TXQ %d (ret=%d)\n",
+ queue, ret);
+ else
+ IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n",
+ queue, tid);
+}
+
static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)
{
struct ieee80211_sta *sta;
@@ -1005,14 +1040,30 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
/* Reconfigure queues requiring reconfiguation */
for (queue = 0; queue < IWL_MAX_HW_QUEUES; queue++) {
bool reconfig;
+ bool change_owner;
spin_lock_bh(&mvm->queue_info_lock);
reconfig = (mvm->queue_info[queue].status ==
IWL_MVM_QUEUE_RECONFIGURING);
+
+ /*
+ * We need to take into account a situation in which a TXQ was
+ * allocated to TID x, and then turned shared by adding TIDs y
+ * and z. If TID x becomes inactive and is removed from the TXQ,
+ * ownership must be given to one of the remaining TIDs.
+ * This is mainly because if TID x continues - a new queue can't
+ * be allocated for it as long as it is an owner of another TXQ.
+ */
+ change_owner = !(mvm->queue_info[queue].tid_bitmap &
+ BIT(mvm->queue_info[queue].txq_tid)) &&
+ (mvm->queue_info[queue].status ==
+ IWL_MVM_QUEUE_SHARED);
spin_unlock_bh(&mvm->queue_info_lock);
if (reconfig)
iwl_mvm_unshare_queue(mvm, queue);
+ else if (change_owner)
+ iwl_mvm_change_queue_owner(mvm, queue);
}
/* Go over all stations with deferred traffic */
--
2.8.1
^ permalink raw reply related
* [PATCH 09/16] iwlwifi: rename and reorder 9000 series configuration structs
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Oren Givon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Oren Givon <oren.givon@intel.com>
Rename and reorder the 9000 series configuration structs:
- struct containing configuration of 5165 was renamed to 9000.
Signed-off-by: Oren Givon <oren.givon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 63 +++++++++++++------------
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 +-
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 34 +++++++------
3 files changed, 50 insertions(+), 51 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index fbaf705..b8356a8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -72,15 +72,15 @@
#define IWL9000_SMEM_OFFSET 0x400000
#define IWL9000_SMEM_LEN 0x68000
-#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-lc-a0-"
+#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-"
#define IWL9260_FW_PRE "iwlwifi-9260-th-a0-jf-a0-"
-#define IWL9260LC_FW_PRE "iwlwifi-9260-th-a0-lc-a0-"
+#define IWL9000LC_FW_PRE "iwlwifi-9000-pu-a0-lc-a0-"
#define IWL9000_MODULE_FIRMWARE(api) \
IWL9000_FW_PRE "-" __stringify(api) ".ucode"
#define IWL9260_MODULE_FIRMWARE(api) \
IWL9260_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL9260LC_MODULE_FIRMWARE(api) \
- IWL9260LC_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL9000LC_MODULE_FIRMWARE(api) \
+ IWL9000LC_FW_PRE "-" __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_9000 10
@@ -147,40 +147,41 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.rf_id = true
const struct iwl_cfg iwl9260_2ac_cfg = {
- .name = "Intel(R) Dual Band Wireless AC 9260",
- .fw_name_pre = IWL9260_FW_PRE,
- IWL_DEVICE_9000,
- .ht_params = &iwl9000_ht_params,
- .nvm_ver = IWL9000_NVM_VERSION,
- .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
- .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .name = "Intel(R) Dual Band Wireless AC 9260",
+ .fw_name_pre = IWL9260_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+};
+
+const struct iwl_cfg iwl9000_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 9000",
+ .fw_name_pre = IWL9000_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
};
/*
* TODO the struct below is for internal testing only this should be
* removed by EO 2016~
*/
-const struct iwl_cfg iwl9260lc_2ac_cfg = {
- .name = "Intel(R) Dual Band Wireless AC 9260",
- .fw_name_pre = IWL9260LC_FW_PRE,
- IWL_DEVICE_9000,
- .ht_params = &iwl9000_ht_params,
- .nvm_ver = IWL9000_NVM_VERSION,
- .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
- .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
-};
-
-const struct iwl_cfg iwl5165_2ac_cfg = {
- .name = "Intel(R) Dual Band Wireless AC 5165",
- .fw_name_pre = IWL9000_FW_PRE,
- IWL_DEVICE_9000,
- .ht_params = &iwl9000_ht_params,
- .nvm_ver = IWL9000_NVM_VERSION,
- .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
- .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
- .integrated = true,
+const struct iwl_cfg iwl9000lc_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 9000",
+ .fw_name_pre = IWL9000LC_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
};
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9260_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL9260LC_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL9000LC_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 423b233..04260fc 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -449,9 +449,9 @@ extern const struct iwl_cfg iwl4165_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
extern const struct iwl_cfg iwl8265_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
+extern const struct iwl_cfg iwl9000_2ac_cfg;
+extern const struct iwl_cfg iwl9000lc_2ac_cfg;
extern const struct iwl_cfg iwl9260_2ac_cfg;
-extern const struct iwl_cfg iwl9260lc_2ac_cfg;
-extern const struct iwl_cfg iwl5165_2ac_cfg;
extern const struct iwl_cfg iwla000_2ac_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 78cf9a7..bf523f5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -504,18 +504,18 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 9000 Series */
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x2526, 0x1420, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9000_2ac_cfg)},
/* a000 Series */
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg)},
@@ -608,7 +608,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
const struct iwl_cfg *cfg_7265d __maybe_unused = NULL;
- const struct iwl_cfg *cfg_9260lc __maybe_unused = NULL;
struct iwl_trans *iwl_trans;
int ret;
@@ -637,11 +636,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
if (iwl_trans->cfg->rf_id) {
- if (cfg == &iwl9260_2ac_cfg)
- cfg_9260lc = &iwl9260lc_2ac_cfg;
- if (cfg_9260lc && iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_LC) {
- cfg = cfg_9260lc;
- iwl_trans->cfg = cfg_9260lc;
+ if (cfg == &iwl9000_2ac_cfg &&
+ iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_LC) {
+ cfg = &iwl9000lc_2ac_cfg;
+ iwl_trans->cfg = cfg;
}
}
#endif
--
2.8.1
^ permalink raw reply related
* [PATCH 10/16] iwlwifi: add a new series 9460 with new PCI ID
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Oren Givon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Oren Givon <oren.givon@intel.com>
Add a new series to the 9000 series called 9460.
In addition, add a new PCI ID that is the 9460 new series.
Signed-off-by: Oren Givon <oren.givon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +-
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 27 +++++++++++++------------
3 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index b8356a8..5621cf2 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -156,8 +156,8 @@ const struct iwl_cfg iwl9260_2ac_cfg = {
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
};
-const struct iwl_cfg iwl9000_2ac_cfg = {
- .name = "Intel(R) Dual Band Wireless AC 9000",
+const struct iwl_cfg iwl9460_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 9460",
.fw_name_pre = IWL9000_FW_PRE,
IWL_DEVICE_9000,
.ht_params = &iwl9000_ht_params,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 04260fc..a18b57f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -449,9 +449,9 @@ extern const struct iwl_cfg iwl4165_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
extern const struct iwl_cfg iwl8265_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
-extern const struct iwl_cfg iwl9000_2ac_cfg;
extern const struct iwl_cfg iwl9000lc_2ac_cfg;
extern const struct iwl_cfg iwl9260_2ac_cfg;
+extern const struct iwl_cfg iwl9460_2ac_cfg;
extern const struct iwl_cfg iwla000_2ac_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index bf523f5..d053183 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -504,18 +504,19 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 9000 Series */
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9000_2ac_cfg)},
- {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9000_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg)},
/* a000 Series */
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg)},
@@ -636,7 +637,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
if (iwl_trans->cfg->rf_id) {
- if (cfg == &iwl9000_2ac_cfg &&
+ if (cfg == &iwl9460_2ac_cfg &&
iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_LC) {
cfg = &iwl9000lc_2ac_cfg;
iwl_trans->cfg = cfg;
--
2.8.1
^ permalink raw reply related
* [PATCH 11/16] iwlwifi: add new 9460 series PCI IDs
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Oren Givon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Oren Givon <oren.givon@intel.com>
Add 4 more new 9460 series PCI IDs.
Signed-off-by: Oren Givon <oren.givon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index d053183..3e5a11a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -517,6 +517,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x0060, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x0060, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0xA370, 0x0060, iwl9460_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg)},
/* a000 Series */
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg)},
--
2.8.1
^ permalink raw reply related
* [PATCH 14/16] iwlwifi: pcie: refrain from SCD accesses
From: Luca Coelho @ 2016-08-30 11:39 UTC (permalink / raw)
To: linux-wireless; +Cc: Sara Sharon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Sara Sharon <sara.sharon@intel.com>
Up till now we accessed SCD configuration only for initial
configuration and for enabling command queue.
For a000 generation the command queue is open by default
and firmware configures the rest. No driver SCD accesses
are expected. Make sure this is the case.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 4 ++++
drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 13 ++++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 74f2f03..559f118 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1960,6 +1960,10 @@ void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq)
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
+ if (trans->cfg->use_tfh)
+ /* TODO: access new SCD registers and dump them */
+ return;
+
scd_sram_addr = trans_pcie->scd_base_addr +
SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 18650dc..9636dc8 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -703,6 +703,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+ if (trans->cfg->use_tfh)
+ return;
+
trans_pcie->scd_base_addr =
iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
@@ -970,11 +973,13 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
}
}
- if (trans->cfg->use_tfh)
+ if (trans->cfg->use_tfh) {
iwl_write_direct32(trans, TFH_TRANSFER_MODE,
TFH_TRANSFER_MAX_PENDING_REQ |
TFH_CHUNK_SIZE_128 |
TFH_CHUNK_SPLIT_MODE);
+ return 0;
+ }
iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE);
if (trans->cfg->base_params->num_of_queues > 20)
@@ -1249,6 +1254,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
if (test_and_set_bit(txq_id, trans_pcie->queue_used))
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
+ if (cfg && trans->cfg->use_tfh)
+ WARN_ONCE(1, "Expected no calls to SCD configuration");
+
txq->wd_timeout = msecs_to_jiffies(wdg_timeout);
if (cfg) {
@@ -1366,6 +1374,9 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
return;
}
+ if (configure_scd && trans->cfg->use_tfh)
+ WARN_ONCE(1, "Expected no calls to SCD configuration");
+
if (configure_scd) {
iwl_scd_txq_set_inactive(trans, txq_id);
--
2.8.1
^ permalink raw reply related
* [PATCH 12/16] iwlwifi: add the new 9270 series
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Oren Givon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Oren Givon <oren.givon@intel.com>
Add a new config struct for the new 9270 series and add
the first PCI ID for it.
Signed-off-by: Oren Givon <oren.givon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 10 ++++++++++
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 +
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 +
3 files changed, 12 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index 5621cf2..e442650 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -156,6 +156,16 @@ const struct iwl_cfg iwl9260_2ac_cfg = {
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
};
+const struct iwl_cfg iwl9270_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 9270",
+ .fw_name_pre = IWL9260_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+};
+
const struct iwl_cfg iwl9460_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9460",
.fw_name_pre = IWL9000_FW_PRE,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index a18b57f..0ab415c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -451,6 +451,7 @@ extern const struct iwl_cfg iwl8265_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
extern const struct iwl_cfg iwl9000lc_2ac_cfg;
extern const struct iwl_cfg iwl9260_2ac_cfg;
+extern const struct iwl_cfg iwl9270_2ac_cfg;
extern const struct iwl_cfg iwl9460_2ac_cfg;
extern const struct iwl_cfg iwla000_2ac_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 3e5a11a..1be0ac2 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -504,6 +504,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 9000 Series */
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)},
{IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9460_2ac_cfg)},
--
2.8.1
^ permalink raw reply related
* [PATCH 13/16] iwlwifi: add the new 9170 series
From: Luca Coelho @ 2016-08-30 11:38 UTC (permalink / raw)
To: linux-wireless; +Cc: Oren Givon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Oren Givon <oren.givon@intel.com>
Add a new config struct for the new 9170 series and add
the first PCI ID for it.
Signed-off-by: Oren Givon <oren.givon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 10 ++++++++++
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 +
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 +
3 files changed, 12 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index e442650..1fec6af 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -146,6 +146,16 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.mac_addr_from_csr = true, \
.rf_id = true
+const struct iwl_cfg iwl9160_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 9160",
+ .fw_name_pre = IWL9260_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+};
+
const struct iwl_cfg iwl9260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9260",
.fw_name_pre = IWL9260_FW_PRE,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 0ab415c..7008319 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -450,6 +450,7 @@ extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
extern const struct iwl_cfg iwl8265_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
extern const struct iwl_cfg iwl9000lc_2ac_cfg;
+extern const struct iwl_cfg iwl9160_2ac_cfg;
extern const struct iwl_cfg iwl9260_2ac_cfg;
extern const struct iwl_cfg iwl9270_2ac_cfg;
extern const struct iwl_cfg iwl9460_2ac_cfg;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 1be0ac2..c6e24fb 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -502,6 +502,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24FD, 0x0850, iwl8265_2ac_cfg)},
/* 9000 Series */
+ {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)},
--
2.8.1
^ permalink raw reply related
* [PATCH 15/16] iwlwifi: pcie: fix ucode load flow for a000 devices
From: Luca Coelho @ 2016-08-30 11:39 UTC (permalink / raw)
To: linux-wireless; +Cc: Sara Sharon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Sara Sharon <sara.sharon@intel.com>
Turns out we should access TFH relative addresses.
Also, the FH_UCODE_LOAD_STATUS was replaced by
UREG_UCODE_LOAD_STATUS.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 15 ++++++-----
drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 8 ++++++
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 33 +++++++++++++++++++------
3 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
index 1d6f5d2..dd75ea7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
@@ -77,7 +77,6 @@
*/
#define FH_MEM_LOWER_BOUND (0x1000)
#define FH_MEM_UPPER_BOUND (0x2000)
-#define TFH_MEM_LOWER_BOUND (0xA06000)
/**
* Keep-Warm (KW) buffer base address.
@@ -120,7 +119,7 @@
#define FH_MEM_CBBC_20_31_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xB20)
#define FH_MEM_CBBC_20_31_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xB80)
/* a000 TFD table address, 64 bit */
-#define TFH_TFDQ_CBB_TABLE (TFH_MEM_LOWER_BOUND + 0x1C00)
+#define TFH_TFDQ_CBB_TABLE (0x1C00)
/* Find TFD CB base pointer for given queue */
static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
@@ -156,7 +155,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
* In case of DRAM read address which is not aligned to 128B, the TFH will
* enable transfer size which doesn't cross 64B DRAM address boundary.
*/
-#define TFH_TRANSFER_MODE (TFH_MEM_LOWER_BOUND + 0x1F40)
+#define TFH_TRANSFER_MODE (0x1F40)
#define TFH_TRANSFER_MAX_PENDING_REQ 0xc
#define TFH_CHUNK_SIZE_128 BIT(8)
#define TFH_CHUNK_SPLIT_MODE BIT(10)
@@ -167,7 +166,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
* the start of the TFD first TB.
* In case of a DRAM Tx CMD update the TFH will update PN and Key ID
*/
-#define TFH_TXCMD_UPDATE_CFG (TFH_MEM_LOWER_BOUND + 0x1F48)
+#define TFH_TXCMD_UPDATE_CFG (0x1F48)
/*
* Controls TX DMA operation
*
@@ -181,22 +180,22 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
* set to 1 - interrupt is sent to the driver
* Bit 0: Indicates the snoop configuration
*/
-#define TFH_SRV_DMA_CHNL0_CTRL (TFH_MEM_LOWER_BOUND + 0x1F60)
+#define TFH_SRV_DMA_CHNL0_CTRL (0x1F60)
#define TFH_SRV_DMA_SNOOP BIT(0)
#define TFH_SRV_DMA_TO_DRIVER BIT(24)
#define TFH_SRV_DMA_START BIT(31)
/* Defines the DMA SRAM write start address to transfer a data block */
-#define TFH_SRV_DMA_CHNL0_SRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F64)
+#define TFH_SRV_DMA_CHNL0_SRAM_ADDR (0x1F64)
/* Defines the 64bits DRAM start address to read the DMA data block from */
-#define TFH_SRV_DMA_CHNL0_DRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F68)
+#define TFH_SRV_DMA_CHNL0_DRAM_ADDR (0x1F68)
/*
* Defines the number of bytes to transfer from DRAM to SRAM.
* Note that this register may be configured with non-dword aligned size.
*/
-#define TFH_SRV_DMA_CHNL0_BC (TFH_MEM_LOWER_BOUND + 0x1F70)
+#define TFH_SRV_DMA_CHNL0_BC (0x1F70)
/**
* Rx SRAM Control and Status Registers (RSCSR)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 459bf73..849ee79 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -303,6 +303,14 @@
#define FH_UCODE_LOAD_STATUS (0x1AF0)
#define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70)
+
+/*
+ * Replacing FH_UCODE_LOAD_STATUS
+ * This register is writen by driver and is read by uCode during boot flow.
+ * Note this address is cleared after MAC reset.
+ */
+#define UREG_UCODE_LOAD_STATUS (0xa05c40)
+
enum secure_load_status_reg {
LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001,
LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 559f118..039eeca 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -827,10 +827,16 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans,
if (ret)
return ret;
- /* Notify the ucode of the loaded section number and status */
- val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS);
- val = val | (sec_num << shift_param);
- iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val);
+ /* Notify ucode of loaded section number and status */
+ if (trans->cfg->use_tfh) {
+ val = iwl_read_prph(trans, UREG_UCODE_LOAD_STATUS);
+ val = val | (sec_num << shift_param);
+ iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS, val);
+ } else {
+ val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS);
+ val = val | (sec_num << shift_param);
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val);
+ }
sec_num = (sec_num << 1) | 0x1;
}
@@ -838,10 +844,21 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans,
iwl_enable_interrupts(trans);
- if (cpu == 1)
- iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF);
- else
- iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
+ if (trans->cfg->use_tfh) {
+ if (cpu == 1)
+ iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS,
+ 0xFFFF);
+ else
+ iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS,
+ 0xFFFFFFFF);
+ } else {
+ if (cpu == 1)
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS,
+ 0xFFFF);
+ else
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS,
+ 0xFFFFFFFF);
+ }
return 0;
}
--
2.8.1
^ permalink raw reply related
* [PATCH 16/16] iwlwifi: pcie: remove dead code
From: Luca Coelho @ 2016-08-30 11:39 UTC (permalink / raw)
To: linux-wireless; +Cc: Sara Sharon, Luca Coelho
In-Reply-To: <1472557142-14782-1-git-send-email-luca@coelho.fi>
From: Sara Sharon <sara.sharon@intel.com>
If device family is 8000 then iwl_pcie_load_cpu_sections()
won't be called at all (iwl_pcie_load_cpu_sections_8000() is
called in that case) so this piece of code never gets called.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 13 -------------
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 --------
2 files changed, 21 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 849ee79..406ef30 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -302,7 +302,6 @@
#define OSC_CLK_FORCE_CONTROL (0x8)
#define FH_UCODE_LOAD_STATUS (0x1AF0)
-#define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70)
/*
* Replacing FH_UCODE_LOAD_STATUS
@@ -311,21 +310,9 @@
*/
#define UREG_UCODE_LOAD_STATUS (0xa05c40)
-enum secure_load_status_reg {
- LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001,
- LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003,
- LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007,
- LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
- LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
-};
-
-#define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38)
-#define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C)
#define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78)
#define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C)
-#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000)
-#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000)
#define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000)
#define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 039eeca..2f46eed 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -903,14 +903,6 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
return ret;
}
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
- iwl_set_bits_prph(trans,
- CSR_UCODE_LOAD_STATUS_ADDR,
- (LMPM_CPU_UCODE_LOADING_COMPLETED |
- LMPM_CPU_HDRS_LOADING_COMPLETED |
- LMPM_CPU_UCODE_LOADING_STARTED) <<
- shift_param);
-
*first_ucode_section = last_read_idx;
return 0;
--
2.8.1
^ permalink raw reply related
* [PATCH v4] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Toke Høiland-Jørgensen @ 2016-08-30 13:15 UTC (permalink / raw)
To: make-wifi-fast, linux-wireless; +Cc: Toke Høiland-Jørgensen
In-Reply-To: <20160824162015.29933-1-toke@toke.dk>
The TXQ intermediate queues can cause packet reordering when more than
one flow is active to a single station. Since some of the wifi-specific
packet handling (notably sequence number and encryption handling) is
sensitive to re-ordering, things break if they are applied before the
TXQ.
This splits up the TX handlers and fast_xmit logic into two parts: An
early part and a late part. The former is applied before TXQ enqueue,
and the latter after dequeue. The non-TXQ path just applies both parts
at once.
To avoid having to deal with fragmentation on dequeue, the split is set
to be after the fragmentation handler. This means that some reordering
of TX handlers is necessary, and some handlers had to be made aware of
fragmentation due to this reordering.
This approach avoids having to scatter special cases for when TXQ is
enabled, at the cost of making the fast_xmit and TX handler code
slightly more complex.
Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
---
Changes since v3:
- Fix sequence number assignment in the fast path.
- Code cleanup.
include/net/mac80211.h | 2 +
net/mac80211/tx.c | 269 ++++++++++++++++++++++++++++++++++++++-----=
------
net/mac80211/wpa.c | 18 +++-
3 files changed, 227 insertions(+), 62 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cca510a..9a6a3e9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags {
* frame (PS-Poll or uAPSD).
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate info=
rmation
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
+ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xm=
it path
*
* These flags are used in tx_info->control.flags.
*/
@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_PS_RESPONSE =3D BIT(1),
IEEE80211_TX_CTRL_RATE_INJECT =3D BIT(2),
IEEE80211_TX_CTRL_AMSDU =3D BIT(3),
+ IEEE80211_TX_CTRL_FAST_XMIT =3D BIT(4),
};
=20
/*
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1d0746d..56dca2d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,6 +38,12 @@
#include "wme.h"
#include "rate.h"
=20
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx);
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sda=
ta,
+ struct sta_info *sta,
+ struct ieee80211_fast_tx *fast_tx,
+ struct sk_buff *skb, bool xmit);
+
/* misc utils */
=20
static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
@@ -585,20 +591,27 @@ static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
struct ieee80211_key *key;
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(tx->skb);
- struct ieee80211_hdr *hdr =3D (struct ieee80211_hdr *)tx->skb->data;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb =3D tx->skb;
+
+ if (!skb)
+ skb =3D skb_peek(&tx->skbs);
+
+ info =3D IEEE80211_SKB_CB(skb);
+ hdr =3D (struct ieee80211_hdr *)skb->data;
=20
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key =3D NULL;
else if (tx->sta &&
(key =3D rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
tx->key =3D key;
- else if (ieee80211_is_group_privacy_action(tx->skb) &&
+ else if (ieee80211_is_group_privacy_action(skb) &&
(key =3D rcu_dereference(tx->sdata->default_multicast_key)))
tx->key =3D key;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
- ieee80211_is_robust_mgmt_frame(tx->skb) &&
+ ieee80211_is_robust_mgmt_frame(skb) &&
(key =3D rcu_dereference(tx->sdata->default_mgmt_key)))
tx->key =3D key;
else if (is_multicast_ether_addr(hdr->addr1) &&
@@ -628,8 +641,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *t=
x)
case WLAN_CIPHER_SUITE_GCMP_256:
if (!ieee80211_is_data_present(hdr->frame_control) &&
!ieee80211_use_mfp(hdr->frame_control, tx->sta,
- tx->skb) &&
- !ieee80211_is_group_privacy_action(tx->skb))
+ skb) &&
+ !ieee80211_is_group_privacy_action(skb))
tx->key =3D NULL;
else
skip_hw =3D (tx->key->conf.flags &
@@ -799,10 +812,12 @@ static __le16 ieee80211_tx_next_seq(struct sta_info=
*sta, int tid)
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(tx->skb);
- struct ieee80211_hdr *hdr =3D (struct ieee80211_hdr *)tx->skb->data;
+ struct sk_buff *skb =3D skb_peek(&tx->skbs);
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr =3D (struct ieee80211_hdr *)skb->data;
u8 *qc;
int tid;
+ u16 fragnum, seq;
=20
/*
* Packet injection may want to control the sequence
@@ -829,10 +844,16 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *t=
x)
*/
if (!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1)) {
- /* driver should assign sequence number */
- info->flags |=3D IEEE80211_TX_CTL_ASSIGN_SEQ;
- /* for pure STA mode without beacons, we can do it */
- hdr->seq_ctrl =3D cpu_to_le16(tx->sdata->sequence_number);
+ fragnum =3D 0;
+ seq =3D cpu_to_le16(tx->sdata->sequence_number);
+ skb_queue_walk(&tx->skbs, skb) {
+ info =3D IEEE80211_SKB_CB(skb);
+ hdr =3D (struct ieee80211_hdr *)skb->data;
+ /* driver should assign sequence number */
+ info->flags |=3D IEEE80211_TX_CTL_ASSIGN_SEQ;
+ /* for pure STA mode without beacons, we can do it */
+ hdr->seq_ctrl =3D seq | fragnum++;
+ }
tx->sdata->sequence_number +=3D 0x10;
if (tx->sta)
tx->sta->tx_stats.msdu[IEEE80211_NUM_TIDS]++;
@@ -853,8 +874,14 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx=
)
tid =3D *qc & IEEE80211_QOS_CTL_TID_MASK;
tx->sta->tx_stats.msdu[tid]++;
=20
- if (!tx->sta->sta.txq[0])
- hdr->seq_ctrl =3D ieee80211_tx_next_seq(tx->sta, tid);
+ if (!tx->sta->sta.txq[0]) {
+ seq =3D ieee80211_tx_next_seq(tx->sta, tid);
+ fragnum =3D 0;
+ skb_queue_walk(&tx->skbs, skb) {
+ hdr =3D (struct ieee80211_hdr *)skb->data;
+ hdr->seq_ctrl =3D seq | fragnum++;
+ }
+ }
=20
return TX_CONTINUE;
}
@@ -927,7 +954,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
struct ieee80211_hdr *hdr =3D (void *)skb->data;
int frag_threshold =3D tx->local->hw.wiphy->frag_threshold;
int hdrlen;
- int fragnum;
=20
/* no matter what happens, tx->skb moves to tx->skbs */
__skb_queue_tail(&tx->skbs, skb);
@@ -964,9 +990,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold))
return TX_DROP;
=20
- /* update duration/seq/flags of fragments */
- fragnum =3D 0;
-
skb_queue_walk(&tx->skbs, skb) {
const __le16 morefrags =3D cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
=20
@@ -987,8 +1010,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx=
)
} else {
hdr->frame_control &=3D ~morefrags;
}
- hdr->seq_ctrl |=3D cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
- fragnum++;
}
=20
return TX_CONTINUE;
@@ -1481,33 +1502,58 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee8=
0211_hw *hw,
{
struct ieee80211_local *local =3D hw_to_local(hw);
struct txq_info *txqi =3D container_of(txq, struct txq_info, txq);
- struct ieee80211_hdr *hdr;
struct sk_buff *skb =3D NULL;
struct fq *fq =3D &local->fq;
struct fq_tin *tin =3D &txqi->tin;
+ struct ieee80211_tx_info *info;
=20
spin_lock_bh(&fq->lock);
=20
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
goto out;
=20
+begin:
skb =3D fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
if (!skb)
goto out;
=20
ieee80211_set_skb_vif(skb, txqi);
=20
- hdr =3D (struct ieee80211_hdr *)skb->data;
- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
+ info =3D IEEE80211_SKB_CB(skb);
+ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
struct sta_info *sta =3D container_of(txq->sta, struct sta_info,
sta);
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct ieee80211_fast_tx *fast_tx;
=20
- hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, txq->tid);
- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
- info->flags |=3D IEEE80211_TX_CTL_AMPDU;
- else
- info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
+ fast_tx =3D rcu_dereference(sta->fast_tx);
+ if (!fast_tx ||
+ !ieee80211_xmit_fast_finish(sta->sdata, sta, fast_tx, skb,
+ false)) {
+ /* fast xmit was started, but fails to finish */
+ ieee80211_free_txskb(hw, skb);
+ goto begin;
+ }
+ } else {
+ struct ieee80211_tx_data tx =3D { };
+
+ __skb_queue_head_init(&tx.skbs);
+ tx.local =3D local;
+ if (txq->sta) {
+ struct sta_info *sta =3D container_of(txq->sta,
+ struct sta_info,
+ sta);
+ tx.sta =3D container_of(txq->sta, struct sta_info, sta);
+ tx.sdata =3D sta->sdata;
+ } else {
+ tx.sdata =3D vif_to_sdata(info->control.vif);
+ }
+
+ __skb_queue_tail(&tx.skbs, skb);
+
+ if (invoke_tx_handlers_late(&tx))
+ goto begin;
+
+ __skb_unlink(skb, &tx.skbs);
}
=20
out:
@@ -1521,6 +1567,71 @@ out:
}
EXPORT_SYMBOL(ieee80211_tx_dequeue);
=20
+static bool ieee80211_queue_skb(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct fq *fq =3D &local->fq;
+ struct ieee80211_vif *vif;
+ struct txq_info *txqi;
+
+ if (!local->ops->wake_tx_queue)
+ return false;
+
+ if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
+ sdata =3D container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+
+ vif =3D &sdata->vif;
+ txqi =3D ieee80211_get_txq(local, vif, sta, skb);
+
+ if (!txqi)
+ return false;
+
+ info->control.vif =3D vif;
+
+ spin_lock_bh(&fq->lock);
+ ieee80211_txq_enqueue(local, txqi, skb);
+ spin_unlock_bh(&fq->lock);
+
+ drv_wake_tx_queue(local, txqi);
+
+ return true;
+}
+
+static bool ieee80211_queue_frags(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct sk_buff_head *skbs)
+{
+ struct sk_buff *skb;
+ struct ieee80211_sta *pubsta;
+
+ if (WARN_ON(skb_queue_empty(skbs)))
+ return true;
+
+ if (!local->ops->wake_tx_queue ||
+ sdata->vif.type =3D=3D NL80211_IFTYPE_MONITOR)
+ return false;
+
+ if (sta && sta->uploaded)
+ pubsta =3D &sta->sta;
+ else
+ pubsta =3D NULL;
+
+ while (!skb_queue_empty(skbs)) {
+ skb =3D __skb_dequeue(skbs);
+ if (unlikely(!ieee80211_queue_skb(local, sdata, pubsta, skb))) {
+ __skb_queue_head(skbs, skb);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool ieee80211_tx_frags(struct ieee80211_local *local,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -1528,9 +1639,7 @@ static bool ieee80211_tx_frags(struct ieee80211_loc=
al *local,
bool txpending)
{
struct ieee80211_tx_control control =3D {};
- struct fq *fq =3D &local->fq;
struct sk_buff *skb, *tmp;
- struct txq_info *txqi;
unsigned long flags;
=20
skb_queue_walk_safe(skbs, skb, tmp) {
@@ -1545,21 +1654,6 @@ static bool ieee80211_tx_frags(struct ieee80211_lo=
cal *local,
}
#endif
=20
- txqi =3D ieee80211_get_txq(local, vif, sta, skb);
- if (txqi) {
- info->control.vif =3D vif;
-
- __skb_unlink(skb, skbs);
-
- spin_lock_bh(&fq->lock);
- ieee80211_txq_enqueue(local, txqi, skb);
- spin_unlock_bh(&fq->lock);
-
- drv_wake_tx_queue(local, txqi);
-
- continue;
- }
-
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
@@ -1680,8 +1774,12 @@ static bool __ieee80211_tx(struct ieee80211_local =
*local,
/*
* Invoke TX handlers, return 0 on success and non-zero if the
* frame was dropped or queued.
+ *
+ * The handlers are split into an early and late part. The latter is eve=
rything
+ * that can be sensitive to reordering, and will be deferred to after pa=
ckets
+ * are dequeued from the intermediate queues (when they are enabled).
*/
-static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
+static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
{
struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(tx->skb);
ieee80211_tx_result res =3D TX_DROP;
@@ -1697,7 +1795,6 @@ static int invoke_tx_handlers(struct ieee80211_tx_d=
ata *tx)
CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
- CALL_TXH(ieee80211_tx_h_select_key);
if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
CALL_TXH(ieee80211_tx_h_rate_ctrl);
=20
@@ -1706,11 +1803,32 @@ static int invoke_tx_handlers(struct ieee80211_tx=
_data *tx)
tx->skb =3D NULL;
goto txh_done;
}
+ CALL_TXH(ieee80211_tx_h_fragment);
+
+ txh_done:
+ if (unlikely(res =3D=3D TX_DROP)) {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop);
+ if (tx->skb)
+ ieee80211_free_txskb(&tx->local->hw, tx->skb);
+ else
+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
+ return -1;
+ } else if (unlikely(res =3D=3D TX_QUEUED)) {
+ I802_DEBUG_INC(tx->local->tx_handlers_queued);
+ return -1;
+ }
=20
+ return 0;
+}
+
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
+{
+ ieee80211_tx_result res =3D TX_DROP;
+
+ /* late tx handlers must be aware of tx info fragmentation! */
+ CALL_TXH(ieee80211_tx_h_select_key);
CALL_TXH(ieee80211_tx_h_michael_mic_add);
CALL_TXH(ieee80211_tx_h_sequence);
- CALL_TXH(ieee80211_tx_h_fragment);
- /* handlers after fragment must be aware of tx info fragmentation! */
CALL_TXH(ieee80211_tx_h_stats);
CALL_TXH(ieee80211_tx_h_encrypt);
if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
@@ -1733,6 +1851,11 @@ static int invoke_tx_handlers(struct ieee80211_tx_=
data *tx)
return 0;
}
=20
+static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
+{
+ return invoke_tx_handlers_early(tx) || invoke_tx_handlers_late(tx);
+}
+
bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct sk_buff *skb,
int band, struct ieee80211_sta **sta)
@@ -1807,7 +1930,13 @@ static bool ieee80211_tx(struct ieee80211_sub_if_d=
ata *sdata,
info->hw_queue =3D
sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
=20
- if (!invoke_tx_handlers(&tx))
+ if (invoke_tx_handlers_early(&tx))
+ return false;
+
+ if (ieee80211_queue_frags(local, sdata, tx.sta, &tx.skbs))
+ return true;
+
+ if (!invoke_tx_handlers_late(&tx))
result =3D __ieee80211_tx(local, &tx.skbs, led_len,
tx.sta, txpending);
=20
@@ -3170,8 +3299,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_su=
b_if_data *sdata,
struct ethhdr eth;
struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr =3D (void *)fast_tx->hdr;
- struct ieee80211_tx_data tx;
- ieee80211_tx_result r;
struct tid_ampdu_tx *tid_tx =3D NULL;
u8 tid =3D IEEE80211_NUM_TIDS;
=20
@@ -3240,11 +3367,30 @@ static bool ieee80211_xmit_fast(struct ieee80211_=
sub_if_data *sdata,
info->flags =3D IEEE80211_TX_CTL_FIRST_FRAGMENT |
IEEE80211_TX_CTL_DONTFRAG |
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
+ info->control.flags =3D IEEE80211_TX_CTRL_FAST_XMIT;
+
+ if (ieee80211_queue_skb(local, sdata, &sta->sta, skb))
+ return true;
+
+ return ieee80211_xmit_fast_finish(sdata, sta, fast_tx, skb, true);
+}
+
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sda=
ta,
+ struct sta_info *sta,
+ struct ieee80211_fast_tx *fast_tx,
+ struct sk_buff *skb, bool xmit)
+{
+ struct ieee80211_local *local =3D sdata->local;
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr =3D (void *)skb->data;
+ struct ieee80211_tx_data tx;
+ ieee80211_tx_result r;
+ u8 tid =3D IEEE80211_NUM_TIDS;
=20
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+ tid =3D skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
*ieee80211_get_qos_ctl(hdr) =3D tid;
- if (!sta->sta.txq[0])
- hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, tid);
+ hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, tid);
} else {
info->flags |=3D IEEE80211_TX_CTL_ASSIGN_SEQ;
hdr->seq_ctrl =3D cpu_to_le16(sdata->sequence_number);
@@ -3309,12 +3455,15 @@ static bool ieee80211_xmit_fast(struct ieee80211_=
sub_if_data *sdata,
}
}
=20
- if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
- sdata =3D container_of(sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
+ if (xmit) {
+ if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
+ sdata =3D container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+
+ __skb_queue_tail(&tx.skbs, skb);
+ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
+ }
=20
- __skb_queue_tail(&tx.skbs, skb);
- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
return true;
}
=20
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index b48c1e1..71c479a 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -28,13 +28,13 @@
#include "wpa.h"
=20
ieee80211_tx_result
-ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
+ieee80211_tx_h_michael_mic_add_skb(struct ieee80211_tx_data *tx,
+ struct sk_buff *skb)
{
u8 *data, *key, *mic;
size_t data_len;
unsigned int hdrlen;
struct ieee80211_hdr *hdr;
- struct sk_buff *skb =3D tx->skb;
struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
int tail;
=20
@@ -83,6 +83,20 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_dat=
a *tx)
return TX_CONTINUE;
}
=20
+ieee80211_tx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
+{
+ struct sk_buff *skb;
+ ieee80211_tx_result r;
+
+ skb_queue_walk(&tx->skbs, skb) {
+ r =3D ieee80211_tx_h_michael_mic_add_skb(tx, skb);
+ if (r !=3D TX_CONTINUE)
+ return r;
+ }
+ return TX_CONTINUE;
+}
+
=20
ieee80211_rx_result
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
--=20
2.9.3
^ permalink raw reply related
* [PATCH] rtl_bt: Add firmware and config file for RTL8822BE
From: Larry Finger @ 2016-08-30 14:08 UTC (permalink / raw)
To: linux-firmware
Cc: linux-wireless, Larry Finger, netdev, 陆朱伟,
linux-bluetooth
This device is a new model from Realtek. Updates to driver btrtl will
soon be submitted to the kernel.
These files were provided by the Realtek developer.
Signed-off-by: 陆朱伟 <alex_lu@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: linux-bluetooth@vger.kernel.org
---
WHENCE | 3 +++
rtl_bt/rtl8822b_config.bin | Bin 0 -> 32 bytes
rtl_bt/rtl8822b_fw.bin | Bin 0 -> 51756 bytes
3 files changed, 3 insertions(+)
create mode 100644 rtl_bt/rtl8822b_config.bin
create mode 100644 rtl_bt/rtl8822b_fw.bin
diff --git a/WHENCE b/WHENCE
index d0bef0d..a9d7c97 100644
--- a/WHENCE
+++ b/WHENCE
@@ -2755,11 +2755,14 @@ File: rtl_bt/rtl8723b_fw.bin
File: rtl_bt/rtl8761a_fw.bin
File: rtl_bt/rtl8812ae_fw.bin
File: rtl_bt/rtl8821a_fw.bin
+File: rtl_bt/rtl8822e_fw.bin
+File: rtl_bt/rtl8822e_config.bin
Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.
Found in vendor driver, linux_bt_usb_2.11.20140423_8723be.rar
From https://github.com/troy-tan/driver_store
+Files rtl_bt/rtl8822e_* came directly from Realtek.
--------------------------------------------------------------------------
diff --git a/rtl_bt/rtl8822b_config.bin b/rtl_bt/rtl8822b_config.bin
new file mode 100644
index 0000000000000000000000000000000000000000..a691e7ca258b0e7dc4ff2bdbdc1d13f2a613526b
GIT binary patch
literal 32
ncmWGtt=ulfaGQbAX&)n#faGpQMq3vKHbEt07gmOw42=2!f)WPF
literal 0
HcmV?d00001
diff --git a/rtl_bt/rtl8822b_fw.bin b/rtl_bt/rtl8822b_fw.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b7d6d1229491314875b3d4a7266462c47998c0fb
GIT binary patch
literal 51756
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
Sr^9daZ&)c|i{*cO>VE-~#_dZ0
literal 0
HcmV?d00001
--
2.6.6
^ permalink raw reply related
* [PATCH] ath6kl: enable firmware crash dumps on the AR6004
From: engineering @ 2016-08-30 14:11 UTC (permalink / raw)
To: kvalo; +Cc: ath6kl, linux-wireless
From: Dan Kephart <dan.kephart@lairdtech.com>
The firmware crash dumps on the 6004 are the same as the 6003. Remove the
statement guarding it from dumping on the 6004. Renamed the
REG_DUMP_COUNT_AR6003 to reflect support on both chips.
Signed-off-by: Dan Kephart <dan.kephart@lairdtech.com>
---
drivers/net/wireless/ath/ath6kl/hif.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c
index 18c0708..d194253 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.c
+++ b/drivers/net/wireless/ath/ath6kl/hif.c
@@ -64,7 +64,7 @@ int ath6kl_hif_rw_comp_handler(void *context, int status)
}
EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler);
-#define REG_DUMP_COUNT_AR6003 60
+#define REGISTER_DUMP_COUNT 60
#define REGISTER_DUMP_LEN_MAX 60
static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
@@ -73,9 +73,6 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
u32 i, address, regdump_addr = 0;
int ret;
- if (ar->target_type != TARGET_TYPE_AR6003)
- return;
-
/* the reg dump pointer is copied to the host interest area */
address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
address = TARG_VTOP(ar->target_type, address);
@@ -95,7 +92,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
/* fetch register dump data */
ret = ath6kl_diag_read(ar, regdump_addr, (u8 *)®dump_val[0],
- REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
+ REGISTER_DUMP_COUNT * (sizeof(u32)));
if (ret) {
ath6kl_warn("failed to get register dump: %d\n", ret);
return;
@@ -105,9 +102,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
ath6kl_info("hw 0x%x fw %s\n", ar->wiphy->hw_version,
ar->wiphy->fw_version);
- BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4);
+ BUILD_BUG_ON(REGISTER_DUMP_COUNT % 4);
- for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) {
+ for (i = 0; i < REGISTER_DUMP_COUNT; i += 4) {
ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
i,
le32_to_cpu(regdump_val[i]),
--
2.4.10
^ permalink raw reply related
* Re: [PATCH] ath6kl: enable firmware crash dumps on the AR6004
From: Valo, Kalle @ 2016-08-30 14:19 UTC (permalink / raw)
To: engineering@keppy.com
Cc: ath6kl@lists.infradead.org, linux-wireless@vger.kernel.org
In-Reply-To: <1472566303-32613-1-git-send-email-dan.kephart@lairdtech.com>
engineering@keppy.com writes:
> From: Dan Kephart <dan.kephart@lairdtech.com>
>
> The firmware crash dumps on the 6004 are the same as the 6003. Remove the
> statement guarding it from dumping on the 6004. Renamed the
> REG_DUMP_COUNT_AR6003 to reflect support on both chips.
>
> Signed-off-by: Dan Kephart <dan.kephart@lairdtech.com>
I have a similar patch already on my queue:
https://patchwork.kernel.org/patch/9262289/
How does this differ from that? Please _always_ add a changelog so that
people know what has changed. Also remember to add "[PATCH v2]" to the
title.
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatc=
hes#subject_name
--=20
Kalle Valo=
^ permalink raw reply
* Re: [PATCH] ath6kl: enable firmware crash dumps on the AR6004
From: Dan Kephart @ 2016-08-30 14:33 UTC (permalink / raw)
To: Valo, Kalle, engineering@keppy.com
Cc: ath6kl@lists.infradead.org, linux-wireless@vger.kernel.org
In-Reply-To: <871t16e34f.fsf@qca.qualcomm.com>
U29ycnkgS2FsbGUsIEkgZGlkIG5vdCBpbnRlbmQgdG8gcmUtc2VuZCB0aGlzIHBhdGNoIHVwLCBp
dCBpcyB0aGUgc2FtZSBhcyB0aGUgcHJldmlvdXMgb25lLg0KDQoNCk9uIDgvMzAvMTYsIDEwOjE5
IEFNLCAibGludXgtd2lyZWxlc3Mtb3duZXJAdmdlci5rZXJuZWwub3JnIG9uIGJlaGFsZiBvZiBW
YWxvLCBLYWxsZSIgPGxpbnV4LXdpcmVsZXNzLW93bmVyQHZnZXIua2VybmVsLm9yZyBvbiBiZWhh
bGYgb2Yga3ZhbG9AcWNhLnF1YWxjb21tLmNvbT4gd3JvdGU6DQoNCiAgICBlbmdpbmVlcmluZ0Br
ZXBweS5jb20gd3JpdGVzOg0KICAgIA0KICAgID4gRnJvbTogRGFuIEtlcGhhcnQgPGRhbi5rZXBo
YXJ0QGxhaXJkdGVjaC5jb20+DQogICAgPg0KICAgID4gVGhlIGZpcm13YXJlIGNyYXNoIGR1bXBz
IG9uIHRoZSA2MDA0IGFyZSB0aGUgc2FtZSBhcyB0aGUgNjAwMy4gUmVtb3ZlIHRoZQ0KICAgID4g
c3RhdGVtZW50IGd1YXJkaW5nIGl0IGZyb20gZHVtcGluZyBvbiB0aGUgNjAwNC4gIFJlbmFtZWQg
dGhlDQogICAgPiBSRUdfRFVNUF9DT1VOVF9BUjYwMDMgdG8gcmVmbGVjdCBzdXBwb3J0IG9uIGJv
dGggY2hpcHMuDQogICAgPg0KICAgID4gU2lnbmVkLW9mZi1ieTogRGFuIEtlcGhhcnQgPGRhbi5r
ZXBoYXJ0QGxhaXJkdGVjaC5jb20+DQogICAgDQogICAgSSBoYXZlIGEgc2ltaWxhciBwYXRjaCBh
bHJlYWR5IG9uIG15IHF1ZXVlOg0KICAgIA0KICAgIGh0dHBzOi8vcGF0Y2h3b3JrLmtlcm5lbC5v
cmcvcGF0Y2gvOTI2MjI4OS8NCiAgICANCiAgICBIb3cgZG9lcyB0aGlzIGRpZmZlciBmcm9tIHRo
YXQ/IFBsZWFzZSBfYWx3YXlzXyBhZGQgYSBjaGFuZ2Vsb2cgc28gdGhhdA0KICAgIHBlb3BsZSBr
bm93IHdoYXQgaGFzIGNoYW5nZWQuIEFsc28gcmVtZW1iZXIgdG8gYWRkICJbUEFUQ0ggdjJdIiB0
byB0aGUNCiAgICB0aXRsZS4NCiAgICANCiAgICBodHRwczovL3dpcmVsZXNzLndpa2kua2VybmVs
Lm9yZy9lbi9kZXZlbG9wZXJzL2RvY3VtZW50YXRpb24vc3VibWl0dGluZ3BhdGNoZXMjc3ViamVj
dF9uYW1lDQogICAgDQogICAgLS0gDQogICAgS2FsbGUgVmFsbw0KDQoNCg==
^ permalink raw reply
* Re: [PATCH] rtl_bt: Add firmware and config file for RTL8822BE
From: Ben Hutchings @ 2016-08-30 14:51 UTC (permalink / raw)
To: Larry Finger, linux-firmware
Cc: linux-wireless, netdev, 陆朱伟, linux-bluetooth
In-Reply-To: <1472566081-1072-1-git-send-email-Larry.Finger@lwfinger.net>
[-- Attachment #1: Type: text/plain, Size: 1201 bytes --]
On Tue, 2016-08-30 at 09:08 -0500, Larry Finger wrote:
> This device is a new model from Realtek. Updates to driver btrtl will
> soon be submitted to the kernel.
>
> These files were provided by the Realtek developer.
>
> Signed-off-by: 陆朱伟 <alex_lu@realsil.com.cn>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: linux-bluetooth@vger.kernel.org
> ---
> WHENCE | 3 +++
> rtl_bt/rtl8822b_config.bin | Bin 0 -> 32 bytes
> rtl_bt/rtl8822b_fw.bin | Bin 0 -> 51756 bytes
> 3 files changed, 3 insertions(+)
> create mode 100644 rtl_bt/rtl8822b_config.bin
> create mode 100644 rtl_bt/rtl8822b_fw.bin
>
> diff --git a/WHENCE b/WHENCE
> index d0bef0d..a9d7c97 100644
> --- a/WHENCE
> +++ b/WHENCE
> @@ -2755,11 +2755,14 @@ File: rtl_bt/rtl8723b_fw.bin
> File: rtl_bt/rtl8761a_fw.bin
> File: rtl_bt/rtl8812ae_fw.bin
> File: rtl_bt/rtl8821a_fw.bin
> +File: rtl_bt/rtl8822e_fw.bin
> +File: rtl_bt/rtl8822e_config.bin
[...]
Should the filenames begin with "rtl822b" or "rtl822e"?
Ben.
--
Ben Hutchings
All the simple programs have been written, and all the good names
taken.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v4] brcmfmac: add missing header dependencies
From: Kalle Valo @ 2016-08-30 16:08 UTC (permalink / raw)
To: Baoyou Xie
Cc: Rafał Miłecki, Arend Van Spriel, Franky Lin,
Hante Meuleman, linux-wireless@vger.kernel.org,
open list:BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER,
Network Development, Linux Kernel Mailing List, Arnd Bergmann,
xie.baoyou
In-Reply-To: <CA+DQWkxpoScXLNhScNpwmLnaMhgVHoGLrH72dAm7OiOX2nW2vA@mail.gmail.com>
Baoyou Xie <baoyou.xie@linaro.org> writes:
> On 29 August 2016 at 23:31, Rafał Miłecki <zajec5@gmail.com> wrote:
>
> On 29 August 2016 at 14:39, Baoyou Xie <baoyou.xie@linaro.org> wrote:
> > We get 1 warning when build kernel with W=1:
> > drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c:23:6:
> warning: no previous prototype for '__brcmf_err' [-Wmissing-prototypes]
>
> building? I'm not native English, but I think so.
>
>
> > In fact, this function is declared in brcmfmac/debug.h, so this patch
> > add missing header dependencies.
>
> adds
>
>
> > Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> > Acked-by: Arnd Bergmann <arnd@arndb.de>
>
> Please don't resend patches just to add tags like that. This only
> increases a noise and patchwork handles this just fine, see:
> https://patchwork.kernel.org/patch/9303285/
> https://patchwork.kernel.org/patch/9303285/mbox/
>
>
> Do I need to resend a patch that fixes two typos(build/add)? or you modify them
> on your way?
I can fix those when I commit the patch.
--
Kalle Valo
^ permalink raw reply
* Re: iwlwifi errors (regression?) on 4.7.0
From: Andy Lutomirski @ 2016-08-30 19:02 UTC (permalink / raw)
To: Luca Coelho
Cc: Andy Lutomirski, Linux Wireless List, Intel Linux Wireless,
Emmanuel Grumbach, Johannes Berg
In-Reply-To: <1472110148.5024.123.camel@coelho.fi>
On Thu, Aug 25, 2016 at 12:29 AM, Luca Coelho <luca@coelho.fi> wrote:
> Hi Andy,
>
> Sorry for the really long delay in replying. :(
>
> On Sun, 2016-08-07 at 01:54 -0700, Andy Lutomirski wrote:
>> My Intel 7265 used to work flawlessly, but for the past week or two
>> it
>> has seemed to be very unreliable. It's also throwing errors. I see
>> problems on firmware versions 16 and 21, although I haven't gotten
>> the
>> warning and backtrace on firmware 16 yet.
>>
>> I have:
>>
>> iwlwifi 0000:3a:00.0: enabling device (0000 -> 0002)
>> iwlwifi 0000:3a:00.0: Unsupported splx structure
>> iwlwifi 0000:3a:00.0: loaded firmware version 21.302800.0 op_mode
>> iwlmvm
>> iwlwifi 0000:3a:00.0: Detected Intel(R) Dual Band Wireless AC 7265,
>> REV=0x210
>> iwlwifi 0000:3a:00.0: L1 Enabled - LTR Disabled
>> iwlwifi 0000:3a:00.0: L1 Enabled - LTR Disabled
>>
>>
>> I just got this error on 4.7.0:
>>
>> [324188.495734] wlp58s0: associated
>> [324281.259579] iwlwifi 0000:3a:00.0: Queue 16 stuck for 10000 ms.
>
> This seems to be a recurring error with the AC-7265. :( We even added
> an entry about it in our wiki:
>
> https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#about_platform_noise
Shouldn't that cause packet loss, not actual stuck queues? Or is the
problem that the device literally can't transmit at all for 10 seconds
and the driver eventually gets sick of waiting? Could the driver
learn to detect this more sensibly, drop the packets cleanly after
some timeout, and maybe log a message about extremely high noise?
>
>
>> > [324281.263732] iwlwifi 0000:3a:00.0: Start IWL Error Log Dump:
>> > [324281.263739] iwlwifi 0000:3a:00.0: Status: 0x00000000, count: 6
>> > [324281.263745] iwlwifi 0000:3a:00.0: Loaded firmware version: 21.302800.0
>> > [324281.263751] iwlwifi 0000:3a:00.0: 0x00000084 | NMI_INTERRUPT_UNKNOWN
>
> We have a bugzilla entry with the queue stuck + NMI trigger:
>
> https://bugzilla.kernel.org/show_bug.cgi?id=112931
>
> Unfortunately nothing was found out by our firmware team regarding this
> yet.
Sad :(
>
>
>> Earlier on the same boot I got:
>>
>> [266562.042662] ------------[ cut here ]------------
>> [266562.042693] WARNING: CPU: 2 PID: 994 at
>> drivers/net/wireless/intel/iwlwifi/mvm/tx.c:1377
>> iwl_mvm_rx_tx_cmd+0x665/0x870 [iwlmvm]
>
> We also have an open bugzilla entry with similar WARNING:
>
> https://bugzilla.kernel.org/show_bug.cgi?id=153381
>
>
> So, first I'd recommend that you follow the recommended workarounds in
> our wiki. If that doesn't help and you still want to try to help us
> debug this, please open a bugzilla so we can track it more easily.
I haven't seem any of these problems on 4.8-rc yet. I'll keep you
posted if I do.
^ permalink raw reply
* [PATCH v2] cfg80211: Remove deprecated create_singlethread_workqueue
From: Bhaktipriya Shridhar @ 2016-08-30 19:05 UTC (permalink / raw)
To: Johannes Berg, David S. Miller
Cc: Tejun Heo, linux-wireless, netdev, linux-kernel
The workqueue "cfg80211_wq" is involved in cleanup, scan and event related
works. It queues multiple work items &rdev->event_work,
&rdev->dfs_update_channels_wk,
&wiphy_to_rdev(request->wiphy)->scan_done_wk,
&wiphy_to_rdev(wiphy)->sched_scan_results_wk, which require strict
execution ordering.
Hence, an ordered dedicated workqueue has been used.
Since it's a wireless driver, WQ_MEM_RECLAIM has been set to ensure
forward progress under memory pressure.
Signed-off-by: Bhaktipriya Shridhar <bhaktipriya96@gmail.com>
---
net/wireless/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d25c82b..2cd4563 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1218,7 +1218,7 @@ static int __init cfg80211_init(void)
if (err)
goto out_fail_reg;
- cfg80211_wq = create_singlethread_workqueue("cfg80211");
+ cfg80211_wq = alloc_ordered_workqueue("cfg80211", WQ_MEM_RECLAIM);
if (!cfg80211_wq) {
err = -ENOMEM;
goto out_fail_wq;
--
2.1.4
^ permalink raw reply related
* Re: [PATCH] rtl_bt: Add firmware and config file for RTL8822BE
From: Larry Finger @ 2016-08-31 1:10 UTC (permalink / raw)
To: Ben Hutchings, linux-firmware
Cc: linux-wireless, netdev, 陆朱伟, linux-bluetooth
In-Reply-To: <1472568698.25374.9.camel@decadent.org.uk>
On 08/30/2016 09:51 AM, Ben Hutchings wrote:
> On Tue, 2016-08-30 at 09:08 -0500, Larry Finger wrote:
>> This device is a new model from Realtek. Updates to driver btrtl will
>> soon be submitted to the kernel.
>>
>> These files were provided by the Realtek developer.
>>
>> Signed-off-by: 陆朱伟 <alex_lu@realsil.com.cn>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> Cc: linux-bluetooth@vger.kernel.org
>> ---
>> WHENCE | 3 +++
>> rtl_bt/rtl8822b_config.bin | Bin 0 -> 32 bytes
>> rtl_bt/rtl8822b_fw.bin | Bin 0 -> 51756 bytes
>> 3 files changed, 3 insertions(+)
>> create mode 100644 rtl_bt/rtl8822b_config.bin
>> create mode 100644 rtl_bt/rtl8822b_fw.bin
>>
>> diff --git a/WHENCE b/WHENCE
>> index d0bef0d..a9d7c97 100644
>> --- a/WHENCE
>> +++ b/WHENCE
>> @@ -2755,11 +2755,14 @@ File: rtl_bt/rtl8723b_fw.bin
>> File: rtl_bt/rtl8761a_fw.bin
>> File: rtl_bt/rtl8812ae_fw.bin
>> File: rtl_bt/rtl8821a_fw.bin
>> +File: rtl_bt/rtl8822e_fw.bin
>> +File: rtl_bt/rtl8822e_config.bin
> [...]
>
> Should the filenames begin with "rtl822b" or "rtl822e"?
They should start with rtl8822b. V2 will be sent shortly.
Thanks,
Larry
^ permalink raw reply
* [PATCH V2] rtl_bt: Add firmware and config file for RTL8822BE
From: Larry Finger @ 2016-08-31 1:11 UTC (permalink / raw)
To: linux-firmware
Cc: linux-wireless, Larry Finger, netdev, 陆朱伟,
linux-bluetooth
This device is a new model from Realtek. Updates to driver btrtl will
soon be submitted to the kernel.
These files were provided by the Realtek developer.
Signed-off-by: 陆朱伟 <alex_lu@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: linux-bluetooth@vger.kernel.org
---
V2 - fix error in file names in WHENCE
---
WHENCE | 3 +++
rtl_bt/rtl8822b_config.bin | Bin 0 -> 32 bytes
rtl_bt/rtl8822b_fw.bin | Bin 0 -> 51756 bytes
3 files changed, 3 insertions(+)
create mode 100644 rtl_bt/rtl8822b_config.bin
create mode 100644 rtl_bt/rtl8822b_fw.bin
diff --git a/WHENCE b/WHENCE
index d0bef0d..a9d7c97 100644
--- a/WHENCE
+++ b/WHENCE
@@ -2755,11 +2755,14 @@ File: rtl_bt/rtl8723b_fw.bin
File: rtl_bt/rtl8761a_fw.bin
File: rtl_bt/rtl8812ae_fw.bin
File: rtl_bt/rtl8821a_fw.bin
+File: rtl_bt/rtl8822b_fw.bin
+File: rtl_bt/rtl8822b_config.bin
Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.
Found in vendor driver, linux_bt_usb_2.11.20140423_8723be.rar
From https://github.com/troy-tan/driver_store
+Files rtl_bt/rtl8822e_* came directly from Realtek.
--------------------------------------------------------------------------
diff --git a/rtl_bt/rtl8822b_config.bin b/rtl_bt/rtl8822b_config.bin
new file mode 100644
index 0000000000000000000000000000000000000000..a691e7ca258b0e7dc4ff2bdbdc1d13f2a613526b
GIT binary patch
literal 32
ncmWGtt=ulfaGQbAX&)n#faGpQMq3vKHbEt07gmOw42=2!f)WPF
literal 0
HcmV?d00001
diff --git a/rtl_bt/rtl8822b_fw.bin b/rtl_bt/rtl8822b_fw.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b7d6d1229491314875b3d4a7266462c47998c0fb
GIT binary patch
literal 51756
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
Sr^9daZ&)c|i{*cO>VE-~#_dZ0
literal 0
HcmV?d00001
--
2.6.6
^ permalink raw reply related
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