2017-02-08 11:28:26

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 00/17] iwlwifi: updates intended for v4.11 2017-02-08

From: Luca Coelho <[email protected]>

Hi,

This is the third and final pull-request before 4.11's merge window.
This time I concentrated in bugfixes:

* Fix 802.11w, which was failing to due an IGTK bug;
* A few more bugzilla bug fixes;
* A channel-switch race condition fix;
* Some fixes related to suspend/resume with new HW;
* The RF-kill saga continues;
* And some other fixes here and there...

As usual, I'm pushing this to a pending branch, for kbuild bot, and
will send a pull-request later.

Please review.

Cheers,
Luca.


Avraham Stern (1):
iwlwifi: mvm: Fix CSA received immediately after association

Emmanuel Grumbach (5):
iwlwifi: mvm: use the PROBE_RESP_QUEUE to send deauth to unknown
station
iwlwifi: pcie: don't increment / decrement a bool
iwlwifi: make RTPM depend on EXPERT
iwlwifi: dvm: don't call << operator with a negative value
iwlwifi: mvm: don't call << operator with a negative value

Golan Ben Ami (2):
iwlwifi: pcie: Re-configure IVAR table after stop device
iwlwifi: pcie: set STATUS_RFKILL immediately after interrupt

Golan Ben-Ami (1):
iwlwifi: mvm: avoid exceeding the allowed print length

Goodstein, Mordechay (1):
iwlwifi: mvm: avoid race condition in ADD_STA.

Gregory Greenman (1):
iwlwifi: mvm: fix a print of NSS for HT rate

Haim Dreyfuss (3):
iwlwifi: pcie: move msix conf functions above other functions
iwlwifi: pcie: separate between SW and HW MSIX configuration
iwlwifi: pcie: re-configure IVAR table after suspend-resume

Ilan Peer (1):
iwlwifi: mvm: Fix removal of IGTK

Sara Sharon (2):
iwlwifi: mvm: fix references to first_agg_queue in DQA mode
iwlwifi: mvm: fix reorder timer re-arming

drivers/net/wireless/intel/iwlwifi/Kconfig | 7 +-
drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 5 +-
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 20 +-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 15 +-
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 6 +-
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 +-
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 17 +-
drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 8 +-
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 243 ++++++++++++---------
11 files changed, 188 insertions(+), 145 deletions(-)

--
2.11.0


2017-02-08 11:28:59

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 05/17] iwlwifi: mvm: fix a print of NSS for HT rate

From: Gregory Greenman <[email protected]>

Handling of the number of space time streams was missing for HT rate in
rate printing function. Fix it.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 80f99c365b6a..13be9a5b83ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -3616,6 +3616,8 @@ int rs_pretty_print_rate(char *buf, const u32 rate)
} else if (rate & RATE_MCS_HT_MSK) {
type = "HT";
mcs = rate & RATE_HT_MCS_INDEX_MSK;
+ nss = ((rate & RATE_HT_MCS_NSS_MSK)
+ >> RATE_HT_MCS_NSS_POS) + 1;
} else {
type = "Unknown"; /* shouldn't happen */
}
--
2.11.0

2017-02-08 11:28:41

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 03/17] iwlwifi: pcie: re-configure IVAR table after suspend-resume

From: Haim Dreyfuss <[email protected]>

During the suspend/resume flow some HW blocks are reset. This causes
the IVAR table to be completely erased. This table is where interrupt
causes are bound to specific IRQs. When the table is empty the
interrupt handlers are not called correctly. Fix this by reconfiguring
the IVAR table after resume.

Fixes: 2e5d4a8f61dc ("iwlwifi: pcie: Add new configuration to enable MSIX")
Signed-off-by: Haim Dreyfuss <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index e7a26f594386..bb2a9a151957 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1152,13 +1152,19 @@ static void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie)
struct iwl_trans *trans = trans_pcie->trans;

if (!trans_pcie->msix_enabled) {
- if (trans->cfg->mq_rx_supported)
+ if (trans->cfg->mq_rx_supported &&
+ test_bit(STATUS_DEVICE_ENABLED, &trans->status))
iwl_write_prph(trans, UREG_CHICK,
UREG_CHICK_MSI_ENABLE);
return;
}
-
- iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);
+ /*
+ * The IVAR table needs to be configured again after reset,
+ * but if the device is disabled, we can't write to
+ * prph.
+ */
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+ iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);

/*
* Each cause from the causes list above and the RX causes is
@@ -1457,6 +1463,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
enum iwl_d3_status *status,
bool test, bool reset)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 val;
int ret;

@@ -1469,11 +1476,15 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
iwl_pcie_enable_rx_wake(trans, true);

/*
- * Also enables interrupts - none will happen as the device doesn't
- * know we're waking it up, only when the opmode actually tells it
- * after this call.
+ * Reconfigure IVAR table in case of MSIX or reset ict table in
+ * MSI mode since HW reset erased it.
+ * Also enables interrupts - none will happen as
+ * the device doesn't know we're waking it up, only when
+ * the opmode actually tells it after this call.
*/
- iwl_pcie_reset_ict(trans);
+ iwl_pcie_conf_msix_hw(trans_pcie);
+ if (!trans_pcie->msix_enabled)
+ iwl_pcie_reset_ict(trans);
iwl_enable_interrupts(trans);

iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
--
2.11.0

2017-02-08 11:28:48

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 07/17] iwlwifi: mvm: fix reorder timer re-arming

From: Sara Sharon <[email protected]>

When NSSN is behind the reorder buffer due to timeout
the reorder timer isn't getting re-armed until NSSN
catches up. Fix it.

Fixes: 0690405fef29 ("iwlwifi: mvm: add reorder timeout per frame")

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index c154ab42c80d..d79e9c2a2654 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -418,7 +418,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,

/* ignore nssn smaller than head sn - this can happen due to timeout */
if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
- return;
+ goto set_timer;

while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) {
int index = ssn % reorder_buf->buf_size;
@@ -441,6 +441,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
}
reorder_buf->head_sn = nssn;

+set_timer:
if (reorder_buf->num_stored && !reorder_buf->removed) {
u16 index = reorder_buf->head_sn % reorder_buf->buf_size;

--
2.11.0

2017-02-08 14:35:12

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 00/17] iwlwifi: updates intended for v4.11 2017-02-08

T24gV2VkLCAyMDE3LTAyLTA4IGF0IDE2OjI5ICswMjAwLCBLYWxsZSBWYWxvIHdyb3RlOg0KPiBM
dWNhIENvZWxobyA8bHVjYUBjb2VsaG8uZmk+IHdyaXRlczoNCj4gDQo+ID4gVGhpcyBpcyB0aGUg
dGhpcmQgYW5kIGZpbmFsIHB1bGwtcmVxdWVzdCBiZWZvcmUgNC4xMSdzIG1lcmdlIHdpbmRvdy4N
Cj4gPiBUaGlzIHRpbWUgSSBjb25jZW50cmF0ZWQgaW4gYnVnZml4ZXM6DQo+ID4gDQo+ID4gKiBG
aXggODAyLjExdywgd2hpY2ggd2FzIGZhaWxpbmcgdG8gZHVlIGFuIElHVEsgYnVnOw0KPiA+ICog
QSBmZXcgbW9yZSBidWd6aWxsYSBidWcgZml4ZXM7DQo+ID4gKiBBIGNoYW5uZWwtc3dpdGNoIHJh
Y2UgY29uZGl0aW9uIGZpeDsNCj4gPiAqIFNvbWUgZml4ZXMgcmVsYXRlZCB0byBzdXNwZW5kL3Jl
c3VtZSB3aXRoIG5ldyBIVzsNCj4gPiAqIFRoZSBSRi1raWxsIHNhZ2EgY29udGludWVzOw0KPiA+
ICogQW5kIHNvbWUgb3RoZXIgZml4ZXMgaGVyZSBhbmQgdGhlcmUuLi4NCj4gPiANCj4gPiBBcyB1
c3VhbCwgSSdtIHB1c2hpbmcgdGhpcyB0byBhIHBlbmRpbmcgYnJhbmNoLCBmb3Iga2J1aWxkIGJv
dCwgYW5kDQo+ID4gd2lsbCBzZW5kIGEgcHVsbC1yZXF1ZXN0IGxhdGVyLg0KPiA+IA0KPiA+IFBs
ZWFzZSByZXZpZXcuDQo+IA0KPiBJIG9ubHkgc2VlIHBhdGNoZXMgMS04IGluIHRoZSBtYWlsaW5n
IGxpc3Qgb3IgaW4gbXkgaW5ib3gsIHdoYXQgaGFwcGVuZWQNCj4gdG8gdGhlIHJlc3Q/DQoNCk5v
dCBzdXJlLCBtYXliZSB0aGV5IGFyZSBzdGlsbCBxdWV1ZWQgaW4gbXkgc2VydmVyPyBMZXQgbWUg
Y2hlY2suDQoNCi0tDQpMdWNhLg==

2017-02-08 11:28:34

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 08/17] iwlwifi: mvm: use the PROBE_RESP_QUEUE to send deauth to unknown station

From: Emmanuel Grumbach <[email protected]>

When we send a deauth to a station we don't know about, we
need to use the PROBE_RESP queue. This can happen when we
send a deauth to a station that is not associated to us.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 1d147599cca9..dd2b4a300819 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -506,15 +506,17 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
switch (info->control.vif->type) {
case NL80211_IFTYPE_AP:
/*
- * handle legacy hostapd as well, where station may be added
- * only after assoc.
+ * Handle legacy hostapd as well, where station may be added
+ * only after assoc. Take care of the case where we send a
+ * deauth to a station that we don't have.
*/
- if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc))
+ if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) ||
+ ieee80211_is_deauth(fc))
return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
if (info->hw_queue == info->control.vif->cab_queue)
return info->hw_queue;

- WARN_ON_ONCE(1);
+ WARN_ONCE(1, "fc=0x%02x", le16_to_cpu(fc));
return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
case NL80211_IFTYPE_P2P_DEVICE:
if (ieee80211_is_mgmt(fc))
--
2.11.0

2017-02-08 11:28:33

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 06/17] iwlwifi: mvm: fix references to first_agg_queue in DQA mode

From: Sara Sharon <[email protected]>

In DQA mode, first_agg_queue is initialized to
IWL_MVM_DQA_MIN_DATA_QUEUE. This causes two bugs in the tx response
flow:

1. When TX fails, we set IEEE80211_TX_STAT_AMPDU_NO_BACK regardless
if we actually have aggregation open on the queue. This causes
mac80211 to send a BAR frame even though there is no aggregation
open.
Fix that by simply checking the AMPDU flag that is set on by
mac80211 for AMPDU packets.

2. When reclaiming frames in aggregation mode, we reclaim based on
scheduler ssn and not the SN.
The reason is that scheduler ssn may be ahead of SN due to a hole
in the BA window that was filled.
However, if we have aggregations open on IWL_MVM_DQA_BSS_CLIENT_QUEUE
the reclaim flow will still go to the code of non-aggregation
instead of the aggregation code since IWL_MVM_DQA_BSS_CLIENT_QUEUE
is smaller than IWL_MVM_DQA_MIN_DATA_QUEUE, although it is a valid
aggregation queue.
Fix that by always using the aggregation reclaim code by default in
DQA mode (currently it is implicitly used by default for all queues
except the reserved BSS queue).

Fixes: cf961e16620f ("iwlwifi: mvm: support dqa-mode agg on non-shared queue")
Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 4ba639eda7a3..1d147599cca9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1274,8 +1274,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,

memset(&info->status, 0, sizeof(info->status));

- info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
/* inform mac80211 about what happened with the frame */
switch (status & TX_STATUS_MSK) {
case TX_STATUS_SUCCESS:
@@ -1298,10 +1296,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
(void *)(uintptr_t)le32_to_cpu(tx_resp->initial_rate);

/* Single frame failure in an AMPDU queue => send BAR */
- if (txq_id >= mvm->first_agg_queue &&
+ if (info->flags & IEEE80211_TX_CTL_AMPDU &&
!(info->flags & IEEE80211_TX_STAT_ACK) &&
!(info->flags & IEEE80211_TX_STAT_TX_FILTERED))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;

/* W/A FW bug: seq_ctl is wrong when the status isn't success */
if (status != TX_STATUS_SUCCESS) {
@@ -1336,7 +1335,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
ieee80211_tx_status(mvm->hw, skb);
}

- if (txq_id >= mvm->first_agg_queue) {
+ if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) {
/* If this is an aggregation queue, we use the ssn since:
* ssn = wifi seq_num % 256.
* The seq_ctl is the sequence control of the packet to which
--
2.11.0

2017-02-08 11:28:23

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 04/17] iwlwifi: pcie: Re-configure IVAR table after stop device

From: Golan Ben Ami <[email protected]>

When getting RF_KILL and disabling radio, the device gets stopped
and reset. This erases the IVAR table that matches the interrupt
to its cause, and is essential for MSIX proper functionality.
Till now, the table wasn't re-configured after the reset, and
therefore the interrupt that enabled radio didn't fire on the
right irq, and the driver didn't handle it correctly.

To fix this, configure the IVAR table again after resetting the
device.

Signed-off-by: Golan Ben-Ami <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index bb2a9a151957..7f05fc56587a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1246,6 +1246,15 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
usleep_range(1000, 2000);

/*
+ * Upon stop, the IVAR table gets erased, so msi-x won't
+ * work. This causes a bug in RF-KILL flows, since the interrupt
+ * that enables radio won't fire on the correct irq, and the
+ * driver won't be able to handle the interrupt.
+ * Configure the IVAR table again after reset.
+ */
+ iwl_pcie_conf_msix_hw(trans_pcie);
+
+ /*
* Upon stop, the APM issues an interrupt if HW RF kill is set.
* This is a bug in certain verions of the hardware.
* Certain devices also keep sending HW RF kill interrupt all
--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 09/17] iwlwifi: pcie: don't increment / decrement a bool

From: Emmanuel Grumbach <[email protected]>

David reported that the code I added uses the decrement
and increment operator on a boolean variable.

Fix that.

Fixes: 0cd58eaab148 ("iwlwifi: pcie: allow the op_mode to block the tx queues")
Reported-by: David Binderman <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index cf5bda06042c..10937309641a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -279,7 +279,7 @@ struct iwl_txq {
bool frozen;
u8 active;
bool ampdu;
- bool block;
+ int block;
unsigned long wd_timeout;
struct sk_buff_head overflow_q;

--
2.11.0

2017-02-08 15:57:05

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 15/17] iwlwifi: mvm: avoid race condition in ADD_STA.

From: "Goodstein, Mordechay" <[email protected]>

The race happens when we send ADD_STA(auth->assoc) -> LQ_CMD
between the commands the FW sometimes loses the medium for AUX, and
sends a ndp to the AP and the flow becomes, ADD_STA -> send ndp -> LQ_CMD
the problem is that there's no rates yet defined for sending the ndp and
FW generates an assert.

The fix: change the order of the commands to LQ_CMD -> ADD_STA

Signed-off-by: Mordechay Goodstein <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 7253b92792bf..d37b1695c64e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2627,11 +2627,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
mvmvif->ap_assoc_sta_count++;
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
}
+
+ iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
+ true);
ret = iwl_mvm_update_sta(mvm, vif, sta);
- if (ret == 0)
- iwl_mvm_rs_rate_init(mvm, sta,
- mvmvif->phy_ctxt->channel->band,
- true);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {

--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 14/17] iwlwifi: mvm: Fix CSA received immediately after association

From: Avraham Stern <[email protected]>

The session protection set for association is only removed when
BSS_CHANGED_BEACON_INFO is set and BSS_CHANGED_ASSOC is not set.

However, mac80211 may set both on association (in case a beacon was
already received). In this case, mac80211 will not set
BSS_CHANGED_BEACON_INFO on the next beacons because it has already
notified the beacon change, so the session protection is never removed
(until the session protection ends).

When a CSA is received within this time, the station will fail to
folllow the channel switch because it cannot schedule the time event.

Fix this by removing the session protection when
BSS_CHANGED_BEACON_INFO and BSS_CHANGED_ASSOC are both set.

Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 15ecd3aba71b..7253b92792bf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2008,16 +2008,16 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_UMAC_SCAN))
iwl_mvm_config_scan(mvm);
- } else if (changes & BSS_CHANGED_BEACON_INFO) {
+ }
+
+ if (changes & BSS_CHANGED_BEACON_INFO) {
/*
- * We received a beacon _after_ association so
+ * We received a beacon from the associated AP so
* remove the session protection.
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
- }

- if (changes & BSS_CHANGED_BEACON_INFO) {
iwl_mvm_sf_update(mvm, vif, false);
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
}
--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 12/17] iwlwifi: mvm: don't call << operator with a negative value

From: Emmanuel Grumbach <[email protected]>

In https://bugzilla.kernel.org/show_bug.cgi?id=177341 Bob
reported a UBSAN WARNING on rs.c in iwldvm.
Fix the same bug in iwlmvm.

This because
i = index - 1;
for (mask = (1 << i); i >= 0; i--, mask >>= 1)

is unsafe: i could be negative and hence we can call <<
on a negative value.
This bug doesn't have any real impact since the condition
of the for loop will prevent any usage of mask.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=177341
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 13be9a5b83ee..ce907c58ebf6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -972,7 +972,9 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,

/* Find the previous rate that is in the rate mask */
i = index - 1;
- for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (i >= 0)
+ mask = BIT(i);
+ for (; i >= 0; i--, mask >>= 1) {
if (rate_mask & mask) {
low = i;
break;
--
2.11.0

2017-02-08 11:28:28

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 02/17] iwlwifi: pcie: separate between SW and HW MSIX configuration

From: Haim Dreyfuss <[email protected]>

The MSIX configuration flow includes two different stages:
configuring the HW by writing to the IVAR table and configuring the SW
to reflect the HW configuration.
The HW configuration is needed on each HW reset,
whereas the SW configuration is only needed during the init flow.

Signed-off-by: Haim Dreyfuss <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index f795ebea4c4a..e7a26f594386 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1147,7 +1147,7 @@ static void iwl_pcie_map_rx_causes(struct iwl_trans *trans)
iwl_write8(trans, CSR_MSIX_RX_IVAR(1), val);
}

-static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
+static void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie)
{
struct iwl_trans *trans = trans_pcie->trans;

@@ -1170,12 +1170,20 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
iwl_pcie_map_rx_causes(trans);

iwl_pcie_map_non_rx_causes(trans);
+}
+
+static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
+{
+ struct iwl_trans *trans = trans_pcie->trans;
+
+ iwl_pcie_conf_msix_hw(trans_pcie);

- trans_pcie->fh_init_mask =
- ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD);
+ if (!trans_pcie->msix_enabled)
+ return;
+
+ trans_pcie->fh_init_mask = ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD);
trans_pcie->fh_mask = trans_pcie->fh_init_mask;
- trans_pcie->hw_init_mask =
- ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD);
+ trans_pcie->hw_init_mask = ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD);
trans_pcie->hw_mask = trans_pcie->hw_init_mask;
}

@@ -1675,6 +1683,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
iwl_pcie_apm_init(trans);

iwl_pcie_init_msix(trans_pcie);
+
/* From now on, the op_mode will be kept updated about RF kill state */
iwl_enable_rfkill_int(trans);

--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 10/17] iwlwifi: make RTPM depend on EXPERT

From: Emmanuel Grumbach <[email protected]>

Enabling the RTPM Kconfig option can be fairly risky.
Runtime PM must be validated against a specific platform
before it can be safely enabled. Hence, it makes no sense
for distros and other big OS vendors to enable it since
they ship code to various systems and unknown platform.

Make sure that this is hinted properly by making the
IWLWIFI_PCIE_RTPM Kconfig option depend on EXPERT.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=172411
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/Kconfig | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig
index b64db47b31bb..c5f2ddf9b0fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/Kconfig
+++ b/drivers/net/wireless/intel/iwlwifi/Kconfig
@@ -90,13 +90,16 @@ config IWLWIFI_BCAST_FILTERING

config IWLWIFI_PCIE_RTPM
bool "Enable runtime power management mode for PCIe devices"
- depends on IWLMVM && PM
+ depends on IWLMVM && PM && EXPERT
default false
help
Say Y here to enable runtime power management for PCIe
devices. If enabled, the device will go into low power mode
when idle for a short period of time, allowing for improved
- power saving during runtime.
+ power saving during runtime. Note that this feature requires
+ a tight integration with the platform. It is not recommended
+ to enable this feature without proper validation with the
+ specific target platform.

If unsure, say N.

--
2.11.0

2017-02-08 18:29:55

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 17/17] iwlwifi: mvm: avoid exceeding the allowed print length

From: Golan Ben-Ami <[email protected]>

Divide a mfuart related print so it won't exceed the allowed
MAX_MSG_LEN (110 bytes) per print.

Fixes: 19f63c531b85 ("iwlwifi: mvm: support v2 of mfuart load notification")
Signed-off-by: Golan Ben-Ami <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index c42ef8681b75..45cb4f476e76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1396,19 +1396,15 @@ void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data;

+ IWL_DEBUG_INFO(mvm,
+ "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n",
+ le32_to_cpu(mfuart_notif->installed_ver),
+ le32_to_cpu(mfuart_notif->external_ver),
+ le32_to_cpu(mfuart_notif->status),
+ le32_to_cpu(mfuart_notif->duration));
+
if (iwl_rx_packet_payload_len(pkt) == sizeof(*mfuart_notif))
IWL_DEBUG_INFO(mvm,
- "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x, image size: 0x%08x\n",
- le32_to_cpu(mfuart_notif->installed_ver),
- le32_to_cpu(mfuart_notif->external_ver),
- le32_to_cpu(mfuart_notif->status),
- le32_to_cpu(mfuart_notif->duration),
+ "MFUART: image size: 0x%08x\n",
le32_to_cpu(mfuart_notif->image_size));
- else
- IWL_DEBUG_INFO(mvm,
- "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n",
- le32_to_cpu(mfuart_notif->installed_ver),
- le32_to_cpu(mfuart_notif->external_ver),
- le32_to_cpu(mfuart_notif->status),
- le32_to_cpu(mfuart_notif->duration));
}
--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 13/17] iwlwifi: pcie: set STATUS_RFKILL immediately after interrupt

From: Golan Ben Ami <[email protected]>

Currently, when getting a RFKILL interrupt, the transport enters a flow
in which it stops the device, disables other interrupts, etc. After
stopping the device, the transport resets the hw, and sleeps. During
the sleep, a context switch occurs and host commands are sent by upper
layers (e.g. mvm) to the fw. This is possible since the op_mode layer
and the transport layer hold different mutexes.

Since the STATUS_RFKILL bit isn't set, the transport layer doesn't
recognize that RFKILL was toggled on, and no commands can actually be
sent, so it enqueues the command to the tx queue and sets a timer on
the queue.

After switching context back to stopping the device, STATUS_RFKILL is
set, and then the transport can't send the command to the fw.
This eventually results in a queue hang.

Fix this by setting STATUS_RFKILL immediately when
the interrupt is fired.

Signed-off-by: Golan Ben-Ami <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index e1bf6da20909..de94dfdf2ec9 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1609,6 +1609,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)

mutex_lock(&trans_pcie->mutex);
hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans->status);
+
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
hw_rfkill ? "disable radio" : "enable radio");

@@ -1617,7 +1620,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
mutex_unlock(&trans_pcie->mutex);
if (hw_rfkill) {
- set_bit(STATUS_RFKILL, &trans->status);
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
&trans->status))
IWL_DEBUG_RF_KILL(trans,
@@ -1954,6 +1956,9 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)

mutex_lock(&trans_pcie->mutex);
hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans->status);
+
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
hw_rfkill ? "disable radio" : "enable radio");

@@ -1962,7 +1967,6 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
mutex_unlock(&trans_pcie->mutex);
if (hw_rfkill) {
- set_bit(STATUS_RFKILL, &trans->status);
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
&trans->status))
IWL_DEBUG_RF_KILL(trans,
--
2.11.0

2017-02-08 11:28:30

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 01/17] iwlwifi: pcie: move msix conf functions above other functions

From: Haim Dreyfuss <[email protected]>

msix configuration functions should be called by other functions.
For example by pcie_d3_resume, move it above to enable it.

Signed-off-by: Haim Dreyfuss <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 206 ++++++++++++------------
1 file changed, 103 insertions(+), 103 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index b28d99f61a35..f795ebea4c4a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1076,6 +1076,109 @@ static bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans)
return hw_rfkill;
}

+struct iwl_causes_list {
+ u32 cause_num;
+ u32 mask_reg;
+ u8 addr;
+};
+
+static struct iwl_causes_list causes_list[] = {
+ {MSIX_FH_INT_CAUSES_D2S_CH0_NUM, CSR_MSIX_FH_INT_MASK_AD, 0},
+ {MSIX_FH_INT_CAUSES_D2S_CH1_NUM, CSR_MSIX_FH_INT_MASK_AD, 0x1},
+ {MSIX_FH_INT_CAUSES_S2D, CSR_MSIX_FH_INT_MASK_AD, 0x3},
+ {MSIX_FH_INT_CAUSES_FH_ERR, CSR_MSIX_FH_INT_MASK_AD, 0x5},
+ {MSIX_HW_INT_CAUSES_REG_ALIVE, CSR_MSIX_HW_INT_MASK_AD, 0x10},
+ {MSIX_HW_INT_CAUSES_REG_WAKEUP, CSR_MSIX_HW_INT_MASK_AD, 0x11},
+ {MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16},
+ {MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17},
+ {MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18},
+ {MSIX_HW_INT_CAUSES_REG_SW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x29},
+ {MSIX_HW_INT_CAUSES_REG_SCD, CSR_MSIX_HW_INT_MASK_AD, 0x2A},
+ {MSIX_HW_INT_CAUSES_REG_FH_TX, CSR_MSIX_HW_INT_MASK_AD, 0x2B},
+ {MSIX_HW_INT_CAUSES_REG_HW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x2D},
+ {MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E},
+};
+
+static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int val = trans_pcie->def_irq | MSIX_NON_AUTO_CLEAR_CAUSE;
+ int i;
+
+ /*
+ * Access all non RX causes and map them to the default irq.
+ * In case we are missing at least one interrupt vector,
+ * the first interrupt vector will serve non-RX and FBQ causes.
+ */
+ for (i = 0; i < ARRAY_SIZE(causes_list); i++) {
+ iwl_write8(trans, CSR_MSIX_IVAR(causes_list[i].addr), val);
+ iwl_clear_bit(trans, causes_list[i].mask_reg,
+ causes_list[i].cause_num);
+ }
+}
+
+static void iwl_pcie_map_rx_causes(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ u32 offset =
+ trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0;
+ u32 val, idx;
+
+ /*
+ * The first RX queue - fallback queue, which is designated for
+ * management frame, command responses etc, is always mapped to the
+ * first interrupt vector. The other RX queues are mapped to
+ * the other (N - 2) interrupt vectors.
+ */
+ val = BIT(MSIX_FH_INT_CAUSES_Q(0));
+ for (idx = 1; idx < trans->num_rx_queues; idx++) {
+ iwl_write8(trans, CSR_MSIX_RX_IVAR(idx),
+ MSIX_FH_INT_CAUSES_Q(idx - offset));
+ val |= BIT(MSIX_FH_INT_CAUSES_Q(idx));
+ }
+ iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~val);
+
+ val = MSIX_FH_INT_CAUSES_Q(0);
+ if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX)
+ val |= MSIX_NON_AUTO_CLEAR_CAUSE;
+ iwl_write8(trans, CSR_MSIX_RX_IVAR(0), val);
+
+ if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS)
+ iwl_write8(trans, CSR_MSIX_RX_IVAR(1), val);
+}
+
+static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
+{
+ struct iwl_trans *trans = trans_pcie->trans;
+
+ if (!trans_pcie->msix_enabled) {
+ if (trans->cfg->mq_rx_supported)
+ iwl_write_prph(trans, UREG_CHICK,
+ UREG_CHICK_MSI_ENABLE);
+ return;
+ }
+
+ iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);
+
+ /*
+ * Each cause from the causes list above and the RX causes is
+ * represented as a byte in the IVAR table. The first nibble
+ * represents the bound interrupt vector of the cause, the second
+ * represents no auto clear for this cause. This will be set if its
+ * interrupt vector is bound to serve other causes.
+ */
+ iwl_pcie_map_rx_causes(trans);
+
+ iwl_pcie_map_non_rx_causes(trans);
+
+ trans_pcie->fh_init_mask =
+ ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD);
+ trans_pcie->fh_mask = trans_pcie->fh_init_mask;
+ trans_pcie->hw_init_mask =
+ ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD);
+ trans_pcie->hw_mask = trans_pcie->hw_init_mask;
+}
+
static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1405,109 +1508,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
return 0;
}

-struct iwl_causes_list {
- u32 cause_num;
- u32 mask_reg;
- u8 addr;
-};
-
-static struct iwl_causes_list causes_list[] = {
- {MSIX_FH_INT_CAUSES_D2S_CH0_NUM, CSR_MSIX_FH_INT_MASK_AD, 0},
- {MSIX_FH_INT_CAUSES_D2S_CH1_NUM, CSR_MSIX_FH_INT_MASK_AD, 0x1},
- {MSIX_FH_INT_CAUSES_S2D, CSR_MSIX_FH_INT_MASK_AD, 0x3},
- {MSIX_FH_INT_CAUSES_FH_ERR, CSR_MSIX_FH_INT_MASK_AD, 0x5},
- {MSIX_HW_INT_CAUSES_REG_ALIVE, CSR_MSIX_HW_INT_MASK_AD, 0x10},
- {MSIX_HW_INT_CAUSES_REG_WAKEUP, CSR_MSIX_HW_INT_MASK_AD, 0x11},
- {MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16},
- {MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17},
- {MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18},
- {MSIX_HW_INT_CAUSES_REG_SW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x29},
- {MSIX_HW_INT_CAUSES_REG_SCD, CSR_MSIX_HW_INT_MASK_AD, 0x2A},
- {MSIX_HW_INT_CAUSES_REG_FH_TX, CSR_MSIX_HW_INT_MASK_AD, 0x2B},
- {MSIX_HW_INT_CAUSES_REG_HW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x2D},
- {MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E},
-};
-
-static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans)
-{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- int val = trans_pcie->def_irq | MSIX_NON_AUTO_CLEAR_CAUSE;
- int i;
-
- /*
- * Access all non RX causes and map them to the default irq.
- * In case we are missing at least one interrupt vector,
- * the first interrupt vector will serve non-RX and FBQ causes.
- */
- for (i = 0; i < ARRAY_SIZE(causes_list); i++) {
- iwl_write8(trans, CSR_MSIX_IVAR(causes_list[i].addr), val);
- iwl_clear_bit(trans, causes_list[i].mask_reg,
- causes_list[i].cause_num);
- }
-}
-
-static void iwl_pcie_map_rx_causes(struct iwl_trans *trans)
-{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u32 offset =
- trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS ? 1 : 0;
- u32 val, idx;
-
- /*
- * The first RX queue - fallback queue, which is designated for
- * management frame, command responses etc, is always mapped to the
- * first interrupt vector. The other RX queues are mapped to
- * the other (N - 2) interrupt vectors.
- */
- val = BIT(MSIX_FH_INT_CAUSES_Q(0));
- for (idx = 1; idx < trans->num_rx_queues; idx++) {
- iwl_write8(trans, CSR_MSIX_RX_IVAR(idx),
- MSIX_FH_INT_CAUSES_Q(idx - offset));
- val |= BIT(MSIX_FH_INT_CAUSES_Q(idx));
- }
- iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~val);
-
- val = MSIX_FH_INT_CAUSES_Q(0);
- if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX)
- val |= MSIX_NON_AUTO_CLEAR_CAUSE;
- iwl_write8(trans, CSR_MSIX_RX_IVAR(0), val);
-
- if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS)
- iwl_write8(trans, CSR_MSIX_RX_IVAR(1), val);
-}
-
-static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
-{
- struct iwl_trans *trans = trans_pcie->trans;
-
- if (!trans_pcie->msix_enabled) {
- if (trans->cfg->mq_rx_supported)
- iwl_write_prph(trans, UREG_CHICK,
- UREG_CHICK_MSI_ENABLE);
- return;
- }
-
- iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);
-
- /*
- * Each cause from the causes list above and the RX causes is
- * represented as a byte in the IVAR table. The first nibble
- * represents the bound interrupt vector of the cause, the second
- * represents no auto clear for this cause. This will be set if its
- * interrupt vector is bound to serve other causes.
- */
- iwl_pcie_map_rx_causes(trans);
-
- iwl_pcie_map_non_rx_causes(trans);
-
- trans_pcie->fh_init_mask =
- ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD);
- trans_pcie->fh_mask = trans_pcie->fh_init_mask;
- trans_pcie->hw_init_mask =
- ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD);
- trans_pcie->hw_mask = trans_pcie->hw_init_mask;
-}
-
static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev,
struct iwl_trans *trans)
{
--
2.11.0

2017-02-08 15:53:12

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 11/17] iwlwifi: dvm: don't call << operator with a negative value

From: Emmanuel Grumbach <[email protected]>

In https://bugzilla.kernel.org/show_bug.cgi?id=177341 Bob
reported a UBSAN WARNING on rs.c.

Undefined behaviour in drivers/net/wireless/intel/iwlwifi/dvm/rs.c:746:18

This because
i = index - 1;
for (mask = (1 << i); i >= 0; i--, mask >>= 1)

is unsafe: i could be negative and hence we can call <<
on a negative value.
This bug doesn't have any real impact since the condition
of the for loop will prevent any usage of mask.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=177341
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
index 710dbbefd551..ff44ebc5829d 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
@@ -740,7 +740,10 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,

/* Find the previous rate that is in the rate mask */
i = index - 1;
- for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (i >= 0)
+ mask = BIT(i);
+
+ for (; i >= 0; i--, mask >>= 1) {
if (rate_mask & mask) {
low = i;
break;
--
2.11.0

2017-02-08 14:30:55

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/17] iwlwifi: updates intended for v4.11 2017-02-08

Luca Coelho <[email protected]> writes:

> This is the third and final pull-request before 4.11's merge window.
> This time I concentrated in bugfixes:
>
> * Fix 802.11w, which was failing to due an IGTK bug;
> * A few more bugzilla bug fixes;
> * A channel-switch race condition fix;
> * Some fixes related to suspend/resume with new HW;
> * The RF-kill saga continues;
> * And some other fixes here and there...
>
> As usual, I'm pushing this to a pending branch, for kbuild bot, and
> will send a pull-request later.
>
> Please review.

I only see patches 1-8 in the mailing list or in my inbox, what happened
to the rest?

--
Kalle Valo

2017-02-08 16:23:10

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 16/17] iwlwifi: mvm: Fix removal of IGTK

From: Ilan Peer <[email protected]>

When removing an IGTK, iwl_mvm_send_sta_igtk() was
called before station ID was retrieved, so the function
was invoked with an invalid station ID. Fix this by first
getting the station ID.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=192411
Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 1bad933b3ad4..c35fabdf85da 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -3047,6 +3047,11 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,

/* Get the station from the mvm local station table */
mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
+ if (!mvm_sta) {
+ IWL_ERR(mvm, "Failed to find station\n");
+ return -EINVAL;
+ }
+ sta_id = mvm_sta->sta_id;

IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
keyconf->keyidx, sta_id);
@@ -3074,8 +3079,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
return 0;
}

- sta_id = mvm_sta->sta_id;
-
ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
if (ret)
return ret;
--
2.11.0