2015-03-01 19:29:51

by Grumbach, Emmanuel

[permalink] [raw]
Subject: pull request: iwlwifi-next 2015-03-01

SGkgS2FsbGUsDQoNClRoaXMgaXMgYSBwdWxsIHJlcXVlc3QgZm9yIDQuMS4gQXMgdXN1YWwgdGhl
IGRldGFpbHMgYXJlIGluIHRoZSB0YWcuDQpQbGVhc2Ugbm90ZSB0aGF0IEkgaGF2ZSBhbm90aGVy
IHNldCBvZiAzMC1pc2ggcGF0Y2ggYWxyZWFkeSBhZnRlciB0aGlzDQpwdWxsIHJlcXVlc3QuIEEg
ZGVwZW5kZW5jeSBpbiBtYWM4MDIxMSB3YXMgc29sdmVkLCBzbyBJIGNhbiBub3cgZmluYWxseQ0K
c2VuZCBsb3RzIG9mIHdvcmsgdGhhdCBoYXMgYmVlbiBtYWRlIGxvbmcgYWdvLiBCdXQgdGhhdCdz
IGZvciB0aGUgbmV4dA0KcHVsbCByZXF1ZXN0Lg0KDQpJIGFsc28gaGF2ZSBiaXRzIGZvciA0LjAg
YnV0IHRoYXQgd2lsbCB3YWl0IHNpbmNlIHlvdXIgdHJlZSBpc24ndCByZWFkeQ0KeWV0IGZvciBh
Y2NlcHRpbmcgcGF0Y2hlcyBmb3IgNC4wLg0KDQpUaGFua3MgYW5kIGxldCBtZSBrbm93IGlmIHlv
dSBoYXZlIGlzc3VlcyENCg0KDQpUaGUgZm9sbG93aW5nIGNoYW5nZXMgc2luY2UgY29tbWl0IGY1
YWYxOWQxMGQxNTFjNWEyYWZhZTMzMDY1NzhmNDg1YzI0NGRiMjU6DQoNCiAgTWVyZ2UgZ2l0Oi8v
Z2l0Lmtlcm5lbC5vcmcvcHViL3NjbS9saW51eC9rZXJuZWwvZ2l0L2RhdmVtL25ldCAoMjAxNS0w
Mi0xNyAxNzo0MToxOSAtMDgwMCkNCg0KYXJlIGF2YWlsYWJsZSBpbiB0aGUgZ2l0IHJlcG9zaXRv
cnkgYXQ6DQoNCg0KICBodHRwczovL2dpdC5rZXJuZWwub3JnL3B1Yi9zY20vbGludXgva2VybmVs
L2dpdC9pd2x3aWZpL2l3bHdpZmktbmV4dC5naXQgdGFncy9pd2x3aWZpLW5leHQtZm9yLWthbGxl
LTIwMTUtMDMtMDENCg0KZm9yIHlvdSB0byBmZXRjaCBjaGFuZ2VzIHVwIHRvIDI2ODg4MzlmMmJj
YzI1NmE1ZTRmNTg2ZmVmODRhNTYyNDIzYzQyY2E6DQoNCiAgaXdsd2lmaTogbXZtOiBkb24ndCBv
dmVycmlkZSBwYXNzaXZlIGR3ZWxsIGluIGNhc2Ugb2YgZnJhZ21lbnRlZCBzY2FuICgyMDE1LTAz
LTAxIDE3OjQzOjE3ICswMjAwKQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoqIGFkZCB0cmlnZ2VycyBmb3IgZmlybXdh
cmUgZHVtcCBjb2xsZWN0aW9uDQoqIHJlbW92ZSBzdXBwb3J0IGZvciAtOS51Y29kZQ0KKiBuZXcg
c3RhdGl0aWNzIEFQSQ0KKiByYXRlIGNvbnRyb2wgaW1wcm92ZW1lbnRzDQoNCi0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCkFy
aWsgTmVtdHNvdiAoMSk6DQogICAgICBpd2x3aWZpOiBtdm06IGNvbnNpZGVyIFRETFMgcXVldWVz
IGFzIHVzZWQgZHVyaW5nIGRyYWluDQoNCkRhdmlkIFNwaW5hZGVsICgyKToNCiAgICAgIGl3bHdp
Zmk6IG12bTogdXNlIG9ubHkgNDAgbXMgZm9yIGZyYWdtZW50ZWQgc2Nhbg0KICAgICAgaXdsd2lm
aTogbXZtOiBkb24ndCBvdmVycmlkZSBwYXNzaXZlIGR3ZWxsIGluIGNhc2Ugb2YgZnJhZ21lbnRl
ZCBzY2FuDQoNCkVtbWFudWVsIEdydW1iYWNoICgxMik6DQogICAgICBpd2x3aWZpOiBwY2llOiBh
cHBseSBkZXN0aW5hdGlvbiBiZWZvcmUgcmVsZWFzaW5nIHJlc2V0DQogICAgICBpd2x3aWZpOiBt
dm06IG5ldyBBbGl2ZSAvIGVycm9yIHRhYmxlIEFQSQ0KICAgICAgaXdsd2lmaTogYWRkIG5ldyBU
TFYgY2FwYWJpbGl0eSBmbGFnIGZvciBCVCBQTENSDQogICAgICBpd2x3aWZpOiBtdm06IGFsbG93
IHRvIGZvcmNlIHRoZSBSeCBjaGFpbnMgZnJvbSBkZWJ1Z2ZzDQogICAgICBpd2x3aWZpOiBtdm06
IGFkZCBmcmFtZXdvcmsgZm9yIHRyaWdnZXJzIGZvciBmdyBkdW1wDQogICAgICBpd2x3aWZpOiBt
dm06IGFkZCB0aGUgY2F1c2Ugb2YgdGhlIGZpcm13YXJlIGR1bXAgaW4gdGhlIGR1bXANCiAgICAg
IGl3bHdpZmk6IG12bTogYWRkIHRyaWdnZXIgZm9yIGZpcm13YXJlIGR1bXAgdXBvbiBtaXNzZWQg
YmVhY29ucw0KICAgICAgaXdsd2lmaTogbXZtOiBhZGQgdHJpZ2dlciBmb3IgZmlybXdhcmUgZHVt
cCB1cG9uIGNoYW5uZWwgc3dpdGNoDQogICAgICBpd2x3aWZpOiBtdm06IGFkZCB0cmlnZ2VyIGZv
ciBmaXJtd2FyZSBkdW1wIHVwb24gY29tbWFuZCByZXNwb25zZQ0KICAgICAgaXdsd2lmaTogbXZt
OiByZXN0YXJ0IGZpcm13YXJlIHJlY29yZGluZyB3aGVuIG5vIGNvbmZpZ3VyYXRpb24gaXMgc2V0
DQogICAgICBpd2x3aWZpOiBtdm06IGFkZCB0cmlnZ2VyIGZvciBmaXJtd2FyZSBkdW1wIHVwb24g
c3RhdGlzdGljcw0KICAgICAgaXdsd2lmaTogbXZtOiBhZGQgdHJpZ2dlciBmb3IgZmlybXdhcmUg
ZHVtcCB1cG9uIGxvdyBSU1NJDQoNCkVyYW4gSGFyYXJ5ICgyKToNCiAgICAgIGl3bHdpZmk6IG12
bTogaW5jcmVhc2UgdGhlIG51bWJlciBvZiBQQVBEIGNoYW5uZWwgZ3JvdXBzIHRvIDkNCiAgICAg
IGl3bHdpZmk6IG12bTogZG9uJ3Qgd3JpdGUgdG8gREJHQ19PVVRfQ1RSTCB3aGVuIHN0b3BwaW5n
IHRoZSByZWNvcmRpbmcNCg0KRXlhbCBTaGFwaXJhICg4KToNCiAgICAgIGl3bHdpZmk6IG12bTog
cnM6IGJldHRlciBtYXRjaCB0eCByZXNwb25zZSByYXRlIHRvIHRoZSBMUSB0YWJsZQ0KICAgICAg
aXdsd2lmaTogbXZtOiByczogZml4IEJUIENvZXggY2hlY2sgdG8gbG9vayBhdCB0aGUgY29ycmVj
dCBhbnQNCiAgICAgIGl3bHdpZmk6IG12bTogcnM6IGFkYXB0IHJhdGUgbWF0Y2hpbmcgdG8gbmV3
IFNUQkMvQkZFUg0KICAgICAgaXdsd2lmaTogbXZtOiByczogZGlzYWJsZSBNSU1PIGZvciBsb3cg
bGF0ZW5jeSBQMlANCiAgICAgIGl3bHdpZmk6IG12bTogcnM6IGF2b2lkIHNzX2ZvcmNlIGZyb20g
YmVpbmcgcmVzZXQgYWZ0ZXIgdHggaWRsZQ0KICAgICAgaXdsd2lmaTogbXZtOiByczogcHJpbnQg
c2luZ2xlIHN0cmVhbSBwYXJhbXMgdmlhIGRlYnVnZnMNCiAgICAgIGl3bHdpZmk6IG12bTogZml4
IEJUIGNvZXggc2hhcmVkIGFudGVubmEgYWN0aXZpdHkgY2hlY2sNCiAgICAgIGl3bHdpZmk6IG12
bTogcmVtb3ZlIHVudXNlZCBmdW5jdGlvbiBpbiBCVCBjb2V4DQoNCkpvaGFubmVzIEJlcmcgKDMp
Og0KICAgICAgaXdsd2lmaTogbXZtOiBhZGQgc3RhdGlzdGljcyBBUEkgdmVyc2lvbiAxMA0KICAg
ICAgaXdsd2lmaTogbXZtOiBzdXBwb3J0IHJhZGlvIHN0YXRpc3RpY3MgYXMgZ2xvYmFsIHN1cnZl
eQ0KICAgICAgaXdsd2lmaTogbXZtOiBzdXBwb3J0IGJlYWNvbiBzdGF0aXN0aWNzIGZvciBCU1Mg
Y2xpZW50DQoNCkx1Y2lhbm8gQ29lbGhvICgzKToNCiAgICAgIGl3bHdpZmk6IGRlcHJlY2F0ZSAt
OS51Y29kZSBmb3IgMzE2MCAvIDcyNjAgLyA3MjY1DQogICAgICBpd2x3aWZpOiBtdm06IHJlbW92
ZSBkZXByZWNhdGVkIHNjYW4gQVBJIGNvZGUNCiAgICAgIGl3bHdpZmk6IG12bTogZG9uJ3QgaXRl
cmF0ZSBpbnRlcmZhY2VzIHRvIGRpc2Nvbm5lY3QgaW4gbmV0LWRldGVjdA0KDQogZHJpdmVycy9u
ZXQvd2lyZWxlc3MvaXdsd2lmaS9kdm0vbWFpbi5jICAgICAgICAgIHwgICAyICstDQogZHJpdmVy
cy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wtNzAwMC5jICAgICAgICAgIHwgICA0ICstDQogZHJp
dmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wtODAwMC5jICAgICAgICAgIHwgICAyICstDQog
ZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wtZGV2dHJhY2UuaCAgICAgIHwgIDE4ICsr
Ky0tDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wtZHJ2LmMgICAgICAgICAgIHwg
IDY4ICsrKysrKysrKysrKysrKystDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wt
ZnctZXJyb3ItZHVtcC5oIHwgIDQ2ICsrKysrKysrKysrKw0KIGRyaXZlcnMvbmV0L3dpcmVsZXNz
L2l3bHdpZmkvaXdsLWZ3LWZpbGUuaCAgICAgICB8IDE1MSArKysrKysrKysrKysrKysrKysrKysr
KysrKysrKy0tLS0tLS0tDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9pd2wtZncuaCAg
ICAgICAgICAgIHwgIDUzICsrKysrLS0tLS0tLS0NCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3
aWZpL2l3bC1waHktZGIuYyAgICAgICAgfCAgIDIgKy0NCiBkcml2ZXJzL25ldC93aXJlbGVzcy9p
d2x3aWZpL2l3bC1wcnBoLmggICAgICAgICAgfCAgIDEgLQ0KIGRyaXZlcnMvbmV0L3dpcmVsZXNz
L2l3bHdpZmkvaXdsLXRyYW5zLmggICAgICAgICB8ICAgNCArLQ0KIGRyaXZlcnMvbmV0L3dpcmVs
ZXNzL2l3bHdpZmkvbXZtL2NvZXguYyAgICAgICAgICB8ICAgNCArLQ0KIGRyaXZlcnMvbmV0L3dp
cmVsZXNzL2l3bHdpZmkvbXZtL2NvZXhfbGVnYWN5LmMgICB8ICAxMiArLS0NCiBkcml2ZXJzL25l
dC93aXJlbGVzcy9pd2x3aWZpL212bS9kMy5jICAgICAgICAgICAgfCAgIDkgKystDQogZHJpdmVy
cy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9tdm0vZGVidWdmcy12aWYuYyAgIHwgIDU0ICsrKysrKysr
KysrKysrDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9tdm0vZGVidWdmcy5jICAgICAg
IHwgICA2ICstDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9tdm0vZnctYXBpLW1hYy5o
ICAgIHwgICAxICsNCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3aWZpL212bS9mdy1hcGktc2Nh
bi5oICAgfCAxOTEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0NCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3aWZpL212bS9mdy1hcGktc3RhdHMuaCAgfCAg
NjQgKysrKysrKysrKysrKy0tLQ0KIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL2Z3
LWFwaS5oICAgICAgICB8ICAyNyArKysrKystDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lm
aS9tdm0vZncuYyAgICAgICAgICAgIHwgMTMzICsrKysrKysrKysrKysrKysrKysrKysrKysrKyst
LS0tLQ0KIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL21hYy1jdHh0LmMgICAgICB8
ICAzNiArKysrKysrKysNCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3aWZpL212bS9tYWM4MDIx
MS5jICAgICAgfCAxODAgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKy0t
LS0tDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXdsd2lmaS9tdm0vbXZtLmggICAgICAgICAgIHwg
MTI1ICsrKysrKysrKysrKysrKysrKysrKysrKystLS0tLS0NCiBkcml2ZXJzL25ldC93aXJlbGVz
cy9pd2x3aWZpL212bS9vcHMuYyAgICAgICAgICAgfCAgNDQgKysrKysrKysrLS0NCiBkcml2ZXJz
L25ldC93aXJlbGVzcy9pd2x3aWZpL212bS9waHktY3R4dC5jICAgICAgfCAgIDIgKw0KIGRyaXZl
cnMvbmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL3JzLmMgICAgICAgICAgICB8IDIxNSArKysrKysr
KysrKysrKysrKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIGRyaXZlcnMv
bmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL3JzLmggICAgICAgICAgICB8ICAgNyArLQ0KIGRyaXZl
cnMvbmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL3J4LmMgICAgICAgICAgICB8IDE1MCArKysrKysr
KysrKysrKysrKysrKysrKysrKysrKystLS0tLS0tDQogZHJpdmVycy9uZXQvd2lyZWxlc3MvaXds
d2lmaS9tdm0vc2Nhbi5jICAgICAgICAgIHwgNjAwICsrKysrKy0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0NCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3aWZpL212bS90eC5jICAgICAgICAg
ICAgfCAgIDQgKw0KIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2l3bHdpZmkvbXZtL3V0aWxzLmMgICAg
ICAgICB8IDIwNyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrLS0t
LS0tLS0NCiBkcml2ZXJzL25ldC93aXJlbGVzcy9pd2x3aWZpL3BjaWUvdHJhbnMuYyAgICAgICAg
fCAgIDYgKy0NCiAzMyBmaWxlcyBjaGFuZ2VkLCAxMzI1IGluc2VydGlvbnMoKyksIDExMDMgZGVs
ZXRpb25zKC0pDQoNCg==


2015-03-01 19:31:57

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 04/31] iwlwifi: mvm: rs: disable MIMO for low latency P2P

From: Eyal Shapira <[email protected]>

Due to issues with Miracast adapters MIMO reception disable
use of MIMO when for low latency P2P traffic.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 37002cf..2bed577 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -160,6 +160,9 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_scale_tbl_info *tbl,
const struct rs_tx_column *next_col)
{
+ struct iwl_mvm_sta *mvmsta;
+ struct iwl_mvm_vif *mvmvif;
+
if (!sta->ht_cap.ht_supported)
return false;

@@ -172,6 +175,11 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
return false;

+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
+ if (iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p)
+ return false;
+
return true;
}

--
1.9.1


2015-03-01 19:32:18

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 14/31] iwlwifi: deprecate -9.ucode for 3160 / 7260 / 7265

From: Luciano Coelho <[email protected]>

This firmware is not supported anymore. Stop loading this firmware.

Signed-off-by: Luciano Coelho <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-7000.c | 4 ++--
drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 97e38d2..0597a9c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -77,8 +77,8 @@
#define IWL3160_UCODE_API_OK 10

/* Lowest firmware API version supported */
-#define IWL7260_UCODE_API_MIN 9
-#define IWL3160_UCODE_API_MIN 9
+#define IWL7260_UCODE_API_MIN 10
+#define IWL3160_UCODE_API_MIN 10

/* NVM versions */
#define IWL7260_NVM_VERSION 0x0a1d
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 2f7fe81..d8dfa6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -75,7 +75,7 @@
#define IWL8000_UCODE_API_OK 10

/* Lowest firmware API version supported */
-#define IWL8000_UCODE_API_MIN 9
+#define IWL8000_UCODE_API_MIN 10

/* NVM versions */
#define IWL8000_NVM_VERSION 0x0a1d
--
1.9.1


2015-03-01 19:32:50

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 31/31] iwlwifi: mvm: don't override passive dwell in case of fragmented scan

From: David Spinadel <[email protected]>

Currently scan params structure has only active or passive dwell time
fields, passive one is used for fragmented scans too. FW needs the
passive dwell time even when performing fragmented scan for calculating
time between channels. Add a separate parameter for fragmented dwell time
and pass both fragmented and passive to FW.

Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/scan.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index c8377e1..f0946b5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -82,6 +82,7 @@ struct iwl_mvm_scan_params {
struct _dwell {
u16 passive;
u16 active;
+ u16 fragmented;
} dwell[IEEE80211_NUM_BANDS];
};

@@ -263,10 +264,10 @@ not_bound:

for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
if (params->passive_fragmented)
- params->dwell[band].passive = frag_passive_dwell;
- else
- params->dwell[band].passive =
- iwl_mvm_get_passive_dwell(mvm, band);
+ params->dwell[band].fragmented = frag_passive_dwell;
+
+ params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm,
+ band);
params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
n_ssids);
}
@@ -768,7 +769,7 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
cmd->fragmented_dwell =
- params->dwell[IEEE80211_BAND_2GHZ].passive;
+ params->dwell[IEEE80211_BAND_2GHZ].fragmented;
cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
@@ -1214,7 +1215,7 @@ iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
cmd->fragmented_dwell =
- params->dwell[IEEE80211_BAND_2GHZ].passive;
+ params->dwell[IEEE80211_BAND_2GHZ].fragmented;
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
--
1.9.1


2015-03-01 19:31:59

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 05/31] iwlwifi: mvm: consider TDLS queues as used during drain

From: Arik Nemtsov <[email protected]>

When a TDLS station is being drained its Tx queues are still in use. Don't
allocate them to a different station in the meantime.

Signed-off-by: Arik Nemtsov <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 7bdc622..f2bfc15 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -244,6 +244,7 @@ static void iwl_mvm_mac_sta_hw_queues_iter(void *_data,
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *exclude_vif)
{
+ u8 sta_id;
struct iwl_mvm_hw_queues_iface_iterator_data data = {
.exclude_vif = exclude_vif,
.used_hw_queues =
@@ -264,6 +265,13 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
iwl_mvm_mac_sta_hw_queues_iter,
&data);

+ /*
+ * Some TDLS stations may be removed but are in the process of being
+ * drained. Don't touch their queues.
+ */
+ for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT)
+ data.used_hw_queues |= mvm->tfd_drained[sta_id];
+
return data.used_hw_queues;
}

--
1.9.1


2015-03-01 19:32:22

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 15/31] iwlwifi: mvm: remove deprecated scan API code

From: Luciano Coelho <[email protected]>

The legacy scan API is deprecated and not used anymore with 10 and
higher firmware versions. Since we deprecated firmware version 9, we
can remove a whole lot of unused code.

Signed-off-by: Luciano Coelho <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 -
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 191 --------
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 23 +-
drivers/net/wireless/iwlwifi/mvm/mvm.h | 16 -
drivers/net/wireless/iwlwifi/mvm/ops.c | 2 -
drivers/net/wireless/iwlwifi/mvm/scan.c | 585 +------------------------
drivers/net/wireless/iwlwifi/mvm/utils.c | 19 -
7 files changed, 20 insertions(+), 818 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 8b9040ef..be4393e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -237,7 +237,6 @@ enum iwl_ucode_tlv_flag {
* enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
- * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
* @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
* longer than the passive one, which is essential for fragmented scan.
@@ -255,7 +254,6 @@ enum iwl_ucode_tlv_flag {
enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
- IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index cfc0e65..a5fbbd6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -70,55 +70,10 @@

/* Scan Commands, Responses, Notifications */

-/* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_ACTIVE BIT(0)
-#define SCAN_CHANNEL_NARROW_BAND BIT(22)
-
/* Max number of IEs for direct SSID scans in a command */
#define PROBE_OPTION_MAX 20

/**
- * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
- * @channel: band is selected by iwl_scan_cmd "flags" field
- * @tx_gain: gain for analog radio
- * @dsp_atten: gain for DSP
- * @active_dwell: dwell time for active scan in TU, typically 5-50
- * @passive_dwell: dwell time for passive scan in TU, typically 20-500
- * @type: type is broken down to these bits:
- * bit 0: 0 = passive, 1 = active
- * bits 1-20: SSID direct bit map. If any of these bits is set then
- * the corresponding SSID IE is transmitted in probe request
- * (bit i adds IE in position i to the probe request)
- * bit 22: channel width, 0 = regular, 1 = TGj narrow channel
- *
- * @iteration_count:
- * @iteration_interval:
- * This struct is used once for each channel in the scan list.
- * Each channel can independently select:
- * 1) SSID for directed active scans
- * 2) Txpower setting (for rate specified within Tx command)
- * 3) How long to stay on-channel (behavior may be modified by quiet_time,
- * quiet_plcp_th, good_CRC_th)
- *
- * To avoid uCode errors, make sure the following are true (see comments
- * under struct iwl_scan_cmd about max_out_time and quiet_time):
- * 1) If using passive_dwell (i.e. passive_dwell != 0):
- * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
- * 2) quiet_time <= active_dwell
- * 3) If restricting off-channel time (i.e. max_out_time !=0):
- * passive_dwell < max_out_time
- * active_dwell < max_out_time
- */
-struct iwl_scan_channel {
- __le32 type;
- __le16 channel;
- __le16 iteration_count;
- __le32 iteration_interval;
- __le16 active_dwell;
- __le16 passive_dwell;
-} __packed; /* SCAN_CHANNEL_CONTROL_API_S_VER_1 */
-
-/**
* struct iwl_ssid_ie - directed scan network information element
*
* Up to 20 of these may appear in REPLY_SCAN_CMD,
@@ -132,152 +87,6 @@ struct iwl_ssid_ie {
u8 ssid[IEEE80211_MAX_SSID_LEN];
} __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */

-/**
- * iwl_scan_flags - masks for scan command flags
- *@SCAN_FLAGS_PERIODIC_SCAN:
- *@SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX:
- *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND:
- *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND:
- *@SCAN_FLAGS_FRAGMENTED_SCAN:
- *@SCAN_FLAGS_PASSIVE2ACTIVE: use active scan on channels that was active
- * in the past hour, even if they are marked as passive.
- */
-enum iwl_scan_flags {
- SCAN_FLAGS_PERIODIC_SCAN = BIT(0),
- SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX = BIT(1),
- SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2),
- SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3),
- SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4),
- SCAN_FLAGS_PASSIVE2ACTIVE = BIT(5),
-};
-
-/**
- * enum iwl_scan_type - Scan types for scan command
- * @SCAN_TYPE_FORCED:
- * @SCAN_TYPE_BACKGROUND:
- * @SCAN_TYPE_OS:
- * @SCAN_TYPE_ROAMING:
- * @SCAN_TYPE_ACTION:
- * @SCAN_TYPE_DISCOVERY:
- * @SCAN_TYPE_DISCOVERY_FORCED:
- */
-enum iwl_scan_type {
- SCAN_TYPE_FORCED = 0,
- SCAN_TYPE_BACKGROUND = 1,
- SCAN_TYPE_OS = 2,
- SCAN_TYPE_ROAMING = 3,
- SCAN_TYPE_ACTION = 4,
- SCAN_TYPE_DISCOVERY = 5,
- SCAN_TYPE_DISCOVERY_FORCED = 6,
-}; /* SCAN_ACTIVITY_TYPE_E_VER_1 */
-
-/**
- * struct iwl_scan_cmd - scan request command
- * ( SCAN_REQUEST_CMD = 0x80 )
- * @len: command length in bytes
- * @scan_flags: scan flags from SCAN_FLAGS_*
- * @channel_count: num of channels in channel list
- * (1 - ucode_capa.n_scan_channels)
- * @quiet_time: in msecs, dwell this time for active scan on quiet channels
- * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than
- * this number of packets were received (typically 1)
- * @passive2active: is auto switching from passive to active during scan allowed
- * @rxchain_sel_flags: RXON_RX_CHAIN_*
- * @max_out_time: in TUs, max out of serving channel time
- * @suspend_time: how long to pause scan when returning to service channel:
- * bits 0-19: beacon interal in TUs (suspend before executing)
- * bits 20-23: reserved
- * bits 24-31: number of beacons (suspend between channels)
- * @rxon_flags: RXON_FLG_*
- * @filter_flags: RXON_FILTER_*
- * @tx_cmd: for active scans (zero for passive), w/o payload,
- * no RS so specify TX rate
- * @direct_scan: direct scan SSIDs
- * @type: one of SCAN_TYPE_*
- * @repeats: how many time to repeat the scan
- */
-struct iwl_scan_cmd {
- __le16 len;
- u8 scan_flags;
- u8 channel_count;
- __le16 quiet_time;
- __le16 quiet_plcp_th;
- __le16 passive2active;
- __le16 rxchain_sel_flags;
- __le32 max_out_time;
- __le32 suspend_time;
- /* RX_ON_FLAGS_API_S_VER_1 */
- __le32 rxon_flags;
- __le32 filter_flags;
- struct iwl_tx_cmd tx_cmd;
- struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
- __le32 type;
- __le32 repeats;
-
- /*
- * Probe request frame, followed by channel list.
- *
- * Size of probe request frame is specified by byte count in tx_cmd.
- * Channel list follows immediately after probe request frame.
- * Number of channels in list is specified by channel_count.
- * Each channel in list is of type:
- *
- * struct iwl_scan_channel channels[0];
- *
- * NOTE: Only one band of channels can be scanned per pass. You
- * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
- * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
- * before requesting another scan.
- */
- u8 data[0];
-} __packed; /* SCAN_REQUEST_FIXED_PART_API_S_VER_5 */
-
-/* Response to scan request contains only status with one of these values */
-#define SCAN_RESPONSE_OK 0x1
-#define SCAN_RESPONSE_ERROR 0x2
-
-/*
- * SCAN_ABORT_CMD = 0x81
- * When scan abort is requested, the command has no fields except the common
- * header. The response contains only a status with one of these values.
- */
-#define SCAN_ABORT_POSSIBLE 0x1
-#define SCAN_ABORT_IGNORED 0x2 /* no pending scans */
-
-/* TODO: complete documentation */
-#define SCAN_OWNER_STATUS 0x1
-#define MEASURE_OWNER_STATUS 0x2
-
-/**
- * struct iwl_scan_start_notif - notifies start of scan in the device
- * ( SCAN_START_NOTIFICATION = 0x82 )
- * @tsf_low: TSF timer (lower half) in usecs
- * @tsf_high: TSF timer (higher half) in usecs
- * @beacon_timer: structured as follows:
- * bits 0:19 - beacon interval in usecs
- * bits 20:23 - reserved (0)
- * bits 24:31 - number of beacons
- * @channel: which channel is scanned
- * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
- * @status: one of *_OWNER_STATUS
- */
-struct iwl_scan_start_notif {
- __le32 tsf_low;
- __le32 tsf_high;
- __le32 beacon_timer;
- u8 channel;
- u8 band;
- u8 reserved[2];
- __le32 status;
-} __packed; /* SCAN_START_NTF_API_S_VER_1 */
-
-/* scan results probe_status first bit indicates success */
-#define SCAN_PROBE_STATUS_OK 0
-#define SCAN_PROBE_STATUS_TX_FAILED BIT(0)
-/* error statuses combined with TX_FAILED */
-#define SCAN_PROBE_STATUS_FAIL_TTL BIT(1)
-#define SCAN_PROBE_STATUS_FAIL_BT BIT(2)
-
/* How many statistics are gathered for each channel */
#define SCAN_RESULTS_STATISTICS 1

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 20e1e89..0f986d7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -339,13 +339,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
!iwlwifi_mod_params.sw_crypto)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;

- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
- mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
- hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
- hw->wiphy->features |=
- NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
- }
+ hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
+ hw->wiphy->features |=
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;

hw->sta_data_size = sizeof(struct iwl_mvm_sta);
hw->vif_data_size = sizeof(struct iwl_mvm_vif);
@@ -2204,10 +2201,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,

if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
ret = iwl_mvm_scan_umac(mvm, vif, hw_req);
- else if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
else
- ret = iwl_mvm_scan_request(mvm, vif, req);
+ ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);

if (ret)
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
@@ -2535,13 +2530,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,

mutex_lock(&mvm->mutex);

- /* Newest FW fixes sched scan while connected on another interface */
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
- if (!vif->bss_conf.idle) {
- ret = -EBUSY;
- goto out;
- }
- } else if (!iwl_mvm_is_idle(mvm)) {
+ if (!vif->bss_conf.idle) {
ret = -EBUSY;
goto out;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d4f3b84..90a1ea3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -1080,13 +1080,6 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,

/* Scanning */
int iwl_mvm_scan_size(struct iwl_mvm *mvm);
-int iwl_mvm_scan_request(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_scan_request *req);
-int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);

@@ -1097,14 +1090,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req);
-int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req);
int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
@@ -1359,9 +1346,6 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout);
}

-/* Assoc status */
-bool iwl_mvm_is_idle(struct iwl_mvm *mvm);
-
/* Thermal management and CT-kill */
void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp);
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 7a04533..1f64d23 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -237,8 +237,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {

RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),

- RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
- RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
RX_HANDLER(SCAN_ITERATION_COMPLETE,
iwl_mvm_rx_scan_offload_iter_complete_notif, false),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 7e9aa3c..ca3a187 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -191,101 +191,6 @@ static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm,
return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
}

-static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
- struct cfg80211_scan_request *req,
- bool basic_ssid,
- struct iwl_mvm_scan_params *params)
-{
- struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
- (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
- int i;
- int type = BIT(req->n_ssids) - 1;
- enum ieee80211_band band = req->channels[0]->band;
-
- if (!basic_ssid)
- type |= BIT(req->n_ssids);
-
- for (i = 0; i < cmd->channel_count; i++) {
- chan->channel = cpu_to_le16(req->channels[i]->hw_value);
- chan->type = cpu_to_le32(type);
- if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
- chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
- chan->active_dwell = cpu_to_le16(params->dwell[band].active);
- chan->passive_dwell = cpu_to_le16(params->dwell[band].passive);
- chan->iteration_count = cpu_to_le16(1);
- chan++;
- }
-}
-
-/*
- * Fill in probe request with the following parameters:
- * TA is our vif HW address, which mac80211 ensures we have.
- * Packet is broadcasted, so this is both SA and DA.
- * The probe request IE is made out of two: first comes the most prioritized
- * SSID if a directed scan is requested. Second comes whatever extra
- * information was given to us as the scan request IE.
- */
-static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
- int n_ssids, const u8 *ssid, int ssid_len,
- const u8 *band_ie, int band_ie_len,
- const u8 *common_ie, int common_ie_len,
- int left)
-{
- int len = 0;
- u8 *pos = NULL;
-
- /* Make sure there is enough space for the probe request,
- * two mandatory IEs and the data */
- left -= 24;
- if (left < 0)
- return 0;
-
- frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
- eth_broadcast_addr(frame->da);
- memcpy(frame->sa, ta, ETH_ALEN);
- eth_broadcast_addr(frame->bssid);
- frame->seq_ctrl = 0;
-
- len += 24;
-
- /* for passive scans, no need to fill anything */
- if (n_ssids == 0)
- return (u16)len;
-
- /* points to the payload of the request */
- pos = &frame->u.probe_req.variable[0];
-
- /* fill in our SSID IE */
- left -= ssid_len + 2;
- if (left < 0)
- return 0;
- *pos++ = WLAN_EID_SSID;
- *pos++ = ssid_len;
- if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
- memcpy(pos, ssid, ssid_len);
- pos += ssid_len;
- }
-
- len += ssid_len + 2;
-
- if (WARN_ON(left < band_ie_len + common_ie_len))
- return len;
-
- if (band_ie && band_ie_len) {
- memcpy(pos, band_ie, band_ie_len);
- pos += band_ie_len;
- len += band_ie_len;
- }
-
- if (common_ie && common_ie_len) {
- memcpy(pos, common_ie, common_ie_len);
- pos += common_ie_len;
- len += common_ie_len;
- }
-
- return (u16)len;
-}
-
static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -379,20 +284,11 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
{
int max_probe_len;

- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE;
- else
- max_probe_len = mvm->fw->ucode_capa.max_probe_length;
+ max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE;

/* we create the 802.11 header and SSID element */
max_probe_len -= 24 + 2;

- /* basic ssid is added only for hw_scan with and old api */
- if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) &&
- !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) &&
- !is_sched_scan)
- max_probe_len -= 32;
-
/* DS parameter set element is added on 2.4GHZ band if required */
if (iwl_mvm_rrm_scan_needed(mvm))
max_probe_len -= 3;
@@ -404,9 +300,6 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
{
int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);

- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN))
- return max_ie_len;
-
/* TODO: [BUG] This function should return the maximum allowed size of
* scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
* in the same command. So the correct implementation of this function
@@ -420,129 +313,6 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
return max_ie_len;
}

-int iwl_mvm_scan_request(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_scan_request *req)
-{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_REQUEST_CMD,
- .len = { 0, },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- struct iwl_scan_cmd *cmd = mvm->scan_cmd;
- int ret;
- u32 status;
- int ssid_len = 0;
- u8 *ssid = NULL;
- bool basic_ssid = !(mvm->fw->ucode_capa.flags &
- IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
- struct iwl_mvm_scan_params params = {};
-
- lockdep_assert_held(&mvm->mutex);
-
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
- mvm->scan_status = IWL_MVM_SCAN_OS;
- memset(cmd, 0, ksize(cmd));
-
- cmd->channel_count = (u8)req->n_channels;
- cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
- cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
- cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
-
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, &params);
- cmd->max_out_time = cpu_to_le32(params.max_out_time);
- cmd->suspend_time = cpu_to_le32(params.suspend_time);
- if (params.passive_fragmented)
- cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
-
- cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
- cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
- MAC_FILTER_IN_BEACON);
-
- if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
- cmd->type = cpu_to_le32(SCAN_TYPE_DISCOVERY_FORCED);
- else
- cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
-
- cmd->repeats = cpu_to_le32(1);
-
- /*
- * If the user asked for passive scan, don't change to active scan if
- * you see any activity on the channel - remain passive.
- */
- if (req->n_ssids > 0) {
- cmd->passive2active = cpu_to_le16(1);
- cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE;
- if (basic_ssid) {
- ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
- }
- } else {
- cmd->passive2active = 0;
- cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE;
- }
-
- iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->ssids, req->n_ssids,
- basic_ssid ? 1 : 0);
-
- cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
- 3 << TX_CMD_FLG_BT_PRIO_POS);
-
- cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
- cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
- cmd->tx_cmd.rate_n_flags =
- iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band,
- req->no_cck);
-
- cmd->tx_cmd.len =
- cpu_to_le16(iwl_mvm_fill_probe_req(
- (struct ieee80211_mgmt *)cmd->data,
- vif->addr,
- req->n_ssids, ssid, ssid_len,
- req->ie, req->ie_len, NULL, 0,
- mvm->fw->ucode_capa.max_probe_length));
-
- iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, &params);
-
- cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
- le16_to_cpu(cmd->tx_cmd.len) +
- (cmd->channel_count * sizeof(struct iwl_scan_channel)));
- hcmd.len[0] = le16_to_cpu(cmd->len);
-
- status = SCAN_RESPONSE_OK;
- ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
- if (!ret && status == SCAN_RESPONSE_OK) {
- IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n",
- status, ret);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ret = -EIO;
- }
- return ret;
-}
-
-int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_cmd_response *resp = (void *)pkt->data;
-
- IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n",
- le32_to_cpu(resp->status));
- return 0;
-}
-
int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
@@ -556,130 +326,25 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
return 0;
}

-int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_scan_complete_notif *notif = (void *)pkt->data;
-
- lockdep_assert_held(&mvm->mutex);
-
- IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
- notif->status, notif->scanned_channels);
-
- if (mvm->scan_status == IWL_MVM_SCAN_OS)
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
-
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-
- return 0;
-}
-
int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
- if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) &&
- !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
- struct iwl_sched_scan_results *notif = (void *)pkt->data;
-
- if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN))
- return 0;
- }
-
IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
ieee80211_sched_scan_results(mvm->hw);

return 0;
}

-static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
- struct iwl_rx_packet *pkt, void *data)
-{
- struct iwl_mvm *mvm =
- container_of(notif_wait, struct iwl_mvm, notif_wait);
- struct iwl_scan_complete_notif *notif;
- u32 *resp;
-
- switch (pkt->hdr.cmd) {
- case SCAN_ABORT_CMD:
- resp = (void *)pkt->data;
- if (*resp == CAN_ABORT_STATUS) {
- IWL_DEBUG_SCAN(mvm,
- "Scan can be aborted, wait until completion\n");
- return false;
- }
-
- /*
- * If scan cannot be aborted, it means that we had a
- * SCAN_COMPLETE_NOTIFICATION in the pipe and it called
- * ieee80211_scan_completed already.
- */
- IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n",
- *resp);
- return true;
-
- case SCAN_COMPLETE_NOTIFICATION:
- notif = (void *)pkt->data;
- IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n",
- notif->status);
- return true;
-
- default:
- WARN_ON(1);
- return false;
- };
-}
-
-static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm)
-{
- struct iwl_notification_wait wait_scan_abort;
- static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
- SCAN_COMPLETE_NOTIFICATION };
- int ret;
-
- iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
- scan_abort_notif,
- ARRAY_SIZE(scan_abort_notif),
- iwl_mvm_scan_abort_notif, NULL);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, 0, 0, NULL);
- if (ret) {
- IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
- /* mac80211's state will be cleaned in the nic_restart flow */
- goto out_remove_notif;
- }
-
- return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ);
-
-out_remove_notif:
- iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
- return ret;
-}
-
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- u8 status, ebs_status;
-
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
- struct iwl_periodic_scan_complete *scan_notif;
+ struct iwl_periodic_scan_complete *scan_notif;

- scan_notif = (void *)pkt->data;
- status = scan_notif->status;
- ebs_status = scan_notif->ebs_status;
- } else {
- struct iwl_scan_offload_complete *scan_notif;
+ scan_notif = (void *)pkt->data;

- scan_notif = (void *)pkt->data;
- status = scan_notif->status;
- ebs_status = scan_notif->ebs_status;
- }
/* scan status must be locked for proper checking */
lockdep_assert_held(&mvm->mutex);

@@ -687,9 +352,9 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
"%s completed, status %s, EBS status %s\n",
mvm->scan_status == IWL_MVM_SCAN_SCHED ?
"Scheduled scan" : "Scan",
- status == IWL_SCAN_OFFLOAD_COMPLETED ?
+ scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
"completed" : "aborted",
- ebs_status == IWL_SCAN_EBS_SUCCESS ?
+ scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
"success" : "failed");


@@ -700,64 +365,16 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
} else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
mvm->scan_status = IWL_MVM_SCAN_NONE;
ieee80211_scan_completed(mvm->hw,
- status == IWL_SCAN_OFFLOAD_ABORTED);
+ scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}

- if (ebs_status)
+ if (scan_notif->ebs_status)
mvm->last_ebs_successful = false;

return 0;
}

-static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_scan_ies *ies,
- enum ieee80211_band band,
- struct iwl_tx_cmd *cmd,
- u8 *data)
-{
- u16 cmd_len;
-
- cmd->tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
- cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
- cmd->sta_id = mvm->aux_sta.sta_id;
-
- cmd->rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, band, false);
-
- cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
- vif->addr,
- 1, NULL, 0,
- ies->ies[band], ies->len[band],
- ies->common_ies, ies->common_ie_len,
- SCAN_OFFLOAD_PROBE_REQ_SIZE);
- cmd->len = cpu_to_le16(cmd_len);
-}
-
-static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct iwl_scan_offload_cmd *scan,
- struct iwl_mvm_scan_params *params)
-{
- scan->channel_count = req->n_channels;
- scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
- scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
- scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
- scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
-
- scan->max_out_time = cpu_to_le32(params->max_out_time);
- scan->suspend_time = cpu_to_le32(params->suspend_time);
-
- scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
- MAC_FILTER_IN_BEACON);
- scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
- scan->rep_count = cpu_to_le32(1);
-
- if (params->passive_fragmented)
- scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
-}
-
static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
{
int i;
@@ -815,127 +432,6 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
}
}

-static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req,
- u8 *channels_buffer,
- enum ieee80211_band band,
- int *head,
- u32 ssid_bitmap,
- struct iwl_mvm_scan_params *params)
-{
- u32 n_channels = mvm->fw->ucode_capa.n_scan_channels;
- __le32 *type = (__le32 *)channels_buffer;
- __le16 *channel_number = (__le16 *)(type + n_channels);
- __le16 *iter_count = channel_number + n_channels;
- __le32 *iter_interval = (__le32 *)(iter_count + n_channels);
- u8 *active_dwell = (u8 *)(iter_interval + n_channels);
- u8 *passive_dwell = active_dwell + n_channels;
- int i, index = 0;
-
- for (i = 0; i < req->n_channels; i++) {
- struct ieee80211_channel *chan = req->channels[i];
-
- if (chan->band != band)
- continue;
-
- index = *head;
- (*head)++;
-
- channel_number[index] = cpu_to_le16(chan->hw_value);
- active_dwell[index] = params->dwell[band].active;
- passive_dwell[index] = params->dwell[band].passive;
-
- iter_count[index] = cpu_to_le16(1);
- iter_interval[index] = 0;
-
- if (!(chan->flags & IEEE80211_CHAN_NO_IR))
- type[index] |=
- cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
-
- type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL |
- IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
-
- if (chan->flags & IEEE80211_CHAN_NO_HT40)
- type[index] |=
- cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW);
-
- /* scan for all SSIDs from req->ssids */
- type[index] |= cpu_to_le32(ssid_bitmap);
- }
-}
-
-int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
-{
- int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
- int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
- int head = 0;
- u32 ssid_bitmap;
- int cmd_len;
- int ret;
- u8 *probes;
- bool basic_ssid = !(mvm->fw->ucode_capa.flags &
- IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
-
- struct iwl_scan_offload_cfg *scan_cfg;
- struct iwl_host_cmd cmd = {
- .id = SCAN_OFFLOAD_CONFIG_CMD,
- };
- struct iwl_mvm_scan_params params = {};
-
- lockdep_assert_held(&mvm->mutex);
-
- cmd_len = sizeof(struct iwl_scan_offload_cfg) +
- mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE +
- 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE;
-
- scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
- if (!scan_cfg)
- return -ENOMEM;
-
- probes = scan_cfg->data +
- mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE;
-
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
- iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params);
- scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
-
- iwl_scan_offload_build_ssid(req, scan_cfg->scan_cmd.direct_scan,
- &ssid_bitmap, basic_ssid);
- /* build tx frames for supported bands */
- if (band_2ghz) {
- iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
- IEEE80211_BAND_2GHZ,
- &scan_cfg->scan_cmd.tx_cmd[0],
- probes);
- iwl_build_channel_cfg(mvm, req, scan_cfg->data,
- IEEE80211_BAND_2GHZ, &head,
- ssid_bitmap, &params);
- }
- if (band_5ghz) {
- iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
- IEEE80211_BAND_5GHZ,
- &scan_cfg->scan_cmd.tx_cmd[1],
- probes +
- SCAN_OFFLOAD_PROBE_REQ_SIZE);
- iwl_build_channel_cfg(mvm, req, scan_cfg->data,
- IEEE80211_BAND_5GHZ, &head,
- ssid_bitmap, &params);
- }
-
- cmd.data[0] = scan_cfg;
- cmd.len[0] = cmd_len;
- cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-
- IWL_DEBUG_SCAN(mvm, "Sending scheduled scan config\n");
-
- ret = iwl_mvm_send_cmd(mvm, &cmd);
- kfree(scan_cfg);
- return ret;
-}
-
int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req)
{
@@ -1018,33 +514,6 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
return true;
}

-int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req)
-{
- struct iwl_scan_offload_req scan_req = {
- .watchdog = IWL_SCHED_SCAN_WATCHDOG,
-
- .schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS,
- .schedule_line[0].delay = cpu_to_le16(req->interval / 1000),
- .schedule_line[0].full_scan_mul = 1,
-
- .schedule_line[1].iterations = 0xff,
- .schedule_line[1].delay = cpu_to_le16(req->interval / 1000),
- .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER,
- };
-
- if (iwl_mvm_scan_pass_all(mvm, req))
- scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL);
-
- if (mvm->last_ebs_successful &&
- mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT)
- scan_req.flags |=
- cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE);
-
- return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, 0,
- sizeof(scan_req), &scan_req);
-}
-
int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
@@ -1057,21 +526,12 @@ int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
if (ret)
return ret;
ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
- } else if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
- mvm->scan_status = IWL_MVM_SCAN_SCHED;
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
- if (ret)
- return ret;
- ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
} else {
mvm->scan_status = IWL_MVM_SCAN_SCHED;
- ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
- if (ret)
- return ret;
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
if (ret)
return ret;
- ret = iwl_mvm_sched_scan_start(mvm, req);
+ ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
}

return ret;
@@ -1088,9 +548,7 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
/* Exit instantly with error when device is not ready
* to receive scan abort command or it does not perform
* scheduled scan currently */
- if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
- (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
- mvm->scan_status != IWL_MVM_SCAN_OS))
+ if (mvm->scan_status == IWL_MVM_SCAN_NONE)
return -EIO;

ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
@@ -1131,13 +589,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
if (iwl_mvm_is_radio_killed(mvm))
goto out;

- if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
- (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
- mvm->scan_status != IWL_MVM_SCAN_OS)) {
- IWL_DEBUG_SCAN(mvm, "No scan to stop\n");
- return 0;
- }
-
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
scan_done_notif,
ARRAY_SIZE(scan_done_notif),
@@ -1580,9 +1031,7 @@ int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
return 0;
}

- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- return iwl_mvm_scan_offload_stop(mvm, true);
- return iwl_mvm_cancel_regular_scan(mvm);
+ return iwl_mvm_scan_offload_stop(mvm, true);
}

/* UMAC scan API */
@@ -2159,14 +1608,8 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_req_umac_tail);

- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- return sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req);
-
- return sizeof(struct iwl_scan_cmd) +
- mvm->fw->ucode_capa.max_probe_length +
- mvm->fw->ucode_capa.n_scan_channels *
- sizeof(struct iwl_scan_channel);
+ return sizeof(struct iwl_scan_req_unified_lmac) +
+ sizeof(struct iwl_scan_channel_cfg_lmac) *
+ mvm->fw->ucode_capa.n_scan_channels +
+ sizeof(struct iwl_scan_probe_req);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 2b75a0d..8bdfb8b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -746,25 +746,6 @@ bool iwl_mvm_low_latency(struct iwl_mvm *mvm)
return result;
}

-static void iwl_mvm_idle_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
-{
- bool *idle = _data;
-
- if (!vif->bss_conf.idle)
- *idle = false;
-}
-
-bool iwl_mvm_is_idle(struct iwl_mvm *mvm)
-{
- bool idle = true;
-
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_idle_iter, &idle);
-
- return idle;
-}
-
struct iwl_bss_iter_data {
struct ieee80211_vif *vif;
bool error;
--
1.9.1


2015-03-01 19:32:17

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 13/31] iwlwifi: mvm: support radio statistics as global survey

From: Johannes Berg <[email protected]>

Export the radio statistics from the statistics v10 API (if the
firmware also has the capability to fill these statistics) using
the global survey data facility.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 +
drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | 17 ++++----
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 +
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 58 +++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/mvm/mvm.h | 14 ++++--
drivers/net/wireless/iwlwifi/mvm/ops.c | 1 +
drivers/net/wireless/iwlwifi/mvm/rx.c | 27 +++++++-----
drivers/net/wireless/iwlwifi/mvm/utils.c | 29 +++++++++++++
8 files changed, 127 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 4602e3c..8b9040ef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -286,6 +286,7 @@ enum iwl_ucode_tlv_api {
* which also implies support for the scheduler configuration command
* @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
* @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
+ * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
*/
enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
@@ -300,6 +301,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
};

/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
index 5a9dfe0..709e28d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
@@ -290,15 +290,7 @@ struct mvm_statistics_rx {
*
* By default, uCode issues this notification after receiving a beacon
* while associated. To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans. uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
+ * STATISTICS_CMD (0x9c), below.
*/

struct iwl_notif_statistics_v8 {
@@ -315,4 +307,11 @@ struct iwl_notif_statistics_v10 {
struct mvm_statistics_general_v8 general;
} __packed; /* STATISTICS_NTFY_API_S_VER_10 */

+#define IWL_STATISTICS_FLG_CLEAR 0x1
+#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2
+
+struct iwl_statistics_cmd {
+ __le32 flags;
+} __packed; /* STATISTICS_CMD_API_S_VER_1 */
+
#endif /* __fw_api_stats_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index b56154f..c43e5c2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -192,6 +192,7 @@ enum {
BEACON_NOTIFICATION = 0x90,
BEACON_TEMPLATE_CMD = 0x91,
TX_ANT_CONFIGURATION_CMD = 0x98,
+ STATISTICS_CMD = 0x9c,
STATISTICS_NOTIFICATION = 0x9d,
EOSP_NOTIFICATION = 0x9e,
REDUCE_TX_POWER_CMD = 0x9f,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 1ff7ec0..20e1e89 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1091,6 +1091,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)

mvm->vif_count = 0;
mvm->rx_ba_sessions = 0;
+
+ /* keep statistics ticking */
+ iwl_mvm_accu_radio_stats(mvm);
}

int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
@@ -1213,6 +1216,11 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
{
lockdep_assert_held(&mvm->mutex);

+ /* firmware counters are obviously reset now, but we shouldn't
+ * partially track so also clear the fw_reset_accu counters.
+ */
+ memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));
+
/*
* Disallow low power states when the FW is down by taking
* the UCODE_DOWN ref. in case of ongoing hw restart the
@@ -3581,6 +3589,55 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
}
}

+static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ memset(survey, 0, sizeof(*survey));
+
+ /* only support global statistics right now */
+ if (idx != 0)
+ return -ENOENT;
+
+ if (!(mvm->fw->ucode_capa.capa[0] &
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+ return -ENOENT;
+
+ mutex_lock(&mvm->mutex);
+
+ if (mvm->ucode_loaded) {
+ ret = iwl_mvm_request_statistics(mvm);
+ if (ret)
+ goto out;
+ }
+
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_TX |
+ SURVEY_INFO_TIME_SCAN;
+ survey->time = mvm->accu_radio_stats.on_time_rf +
+ mvm->radio_stats.on_time_rf;
+ do_div(survey->time, USEC_PER_MSEC);
+
+ survey->time_rx = mvm->accu_radio_stats.rx_time +
+ mvm->radio_stats.rx_time;
+ do_div(survey->time_rx, USEC_PER_MSEC);
+
+ survey->time_tx = mvm->accu_radio_stats.tx_time +
+ mvm->radio_stats.tx_time;
+ do_div(survey->time_tx, USEC_PER_MSEC);
+
+ survey->time_scan = mvm->accu_radio_stats.on_time_scan +
+ mvm->radio_stats.on_time_scan;
+ do_div(survey->time_scan, USEC_PER_MSEC);
+
+ out:
+ mutex_unlock(&mvm->mutex);
+ return ret;
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
@@ -3647,4 +3704,5 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
#endif
.set_default_unicast_key = iwl_mvm_set_default_unicast_key,
#endif
+ .get_survey = iwl_mvm_mac_get_survey,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 07b91d6..d4f3b84 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -593,6 +593,13 @@ struct iwl_mvm {

struct mvm_statistics_rx rx_stats;

+ struct {
+ u64 rx_time;
+ u64 tx_time;
+ u64 on_time_rf;
+ u64 on_time_scan;
+ } radio_stats, accu_radio_stats;
+
u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];

@@ -951,12 +958,13 @@ static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)
}

/* Statistics */
-int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
+void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt);
int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_request_statistics(struct iwl_mvm *mvm);
+void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);

/* NVM */
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 2dffc36..7a04533 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -311,6 +311,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(REPLY_RX_MPDU_CMD),
CMD(BEACON_NOTIFICATION),
CMD(BEACON_TEMPLATE_CMD),
+ CMD(STATISTICS_CMD),
CMD(STATISTICS_NOTIFICATION),
CMD(EOSP_NOTIFICATION),
CMD(REDUCE_TX_POWER_CMD),
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index fffd89d..2486931 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -496,16 +496,9 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
}
}

-/*
- * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler
- *
- * TODO: This handler is implemented partially.
- */
-int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
size_t v8_len = sizeof(struct iwl_notif_statistics_v8);
size_t v10_len = sizeof(struct iwl_notif_statistics_v10);
struct iwl_mvm_stat_data data = {
@@ -525,6 +518,13 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
stats->general.beacon_filter_average_energy;

iwl_mvm_update_rx_statistics(mvm, &stats->rx);
+
+ mvm->radio_stats.rx_time = le64_to_cpu(stats->general.rx_time);
+ mvm->radio_stats.tx_time = le64_to_cpu(stats->general.tx_time);
+ mvm->radio_stats.on_time_rf =
+ le64_to_cpu(stats->general.on_time_rf);
+ mvm->radio_stats.on_time_scan =
+ le64_to_cpu(stats->general.on_time_scan);
} else {
struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data;

@@ -549,9 +549,16 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_stat_iterator,
&data);
- return 0;
+ return;
invalid:
IWL_ERR(mvm, "received invalid statistics size (%d)!\n",
iwl_rx_packet_payload_len(pkt));
+}
+
+int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb));
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 8decf99..2b75a0d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -643,6 +643,35 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ieee80211_request_smps(vif, smps_mode);
}

+int iwl_mvm_request_statistics(struct iwl_mvm *mvm)
+{
+ struct iwl_statistics_cmd scmd = {};
+ struct iwl_host_cmd cmd = {
+ .id = STATISTICS_CMD,
+ .len[0] = sizeof(scmd),
+ .data[0] = &scmd,
+ .flags = CMD_WANT_SKB,
+ };
+ int ret;
+
+ ret = iwl_mvm_send_cmd(mvm, &cmd);
+ if (ret)
+ return ret;
+
+ iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt);
+ iwl_free_resp(&cmd);
+
+ return 0;
+}
+
+void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm)
+{
+ mvm->accu_radio_stats.rx_time += mvm->radio_stats.rx_time;
+ mvm->accu_radio_stats.tx_time += mvm->radio_stats.tx_time;
+ mvm->accu_radio_stats.on_time_rf += mvm->radio_stats.on_time_rf;
+ mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan;
+}
+
static void iwl_mvm_diversity_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
--
1.9.1


2015-03-01 19:32:35

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 22/31] iwlwifi: mvm: use only 40 ms for fragmented scan

From: David Spinadel <[email protected]>

20 ms fragments are no longer required by system.

Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/scan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index ca3a187..c8377e1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -230,7 +230,7 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
* If there is more than one active interface make
* passive scan more fragmented.
*/
- frag_passive_dwell = (global_cnt < 2) ? 40 : 20;
+ frag_passive_dwell = 40;
params->max_out_time = frag_passive_dwell;
} else {
params->suspend_time = 120;
--
1.9.1


2015-03-01 19:32:45

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 28/31] iwlwifi: mvm: restart firmware recording when no configuration is set

Sometimes the firmware will have a hard coded configuration.
In this case, the driver won't find any configuration
in the firmware file, and it will have to re-start
recording in case it has been stopped. This can't be done
by the configuration host command since there is no such
host command configured. Do that with the registers instead.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-prph.h | 1 -
drivers/net/wireless/iwlwifi/mvm/fw.c | 19 +++++++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 6221e4d..6095088 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -370,7 +370,6 @@ enum secure_load_status_reg {
#define MON_BUFF_CYCLE_CNT (0xa03c48)

#define DBGC_IN_SAMPLE (0xa03c00)
-#define DBGC_OUT_CTRL (0xa03c0c)

/* FW chicken bits */
#define LMPM_CHICK 0xA01FF8
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 64e9039..a81da4c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -544,6 +544,14 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
return 0;
}

+static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm)
+{
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+ iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+ else
+ iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1);
+}
+
int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
{
u8 *ptr;
@@ -554,6 +562,14 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
"Invalid configuration %d\n", conf_id))
return -EINVAL;

+ /* EARLY START - firmware's configuration is hard coded */
+ if ((!mvm->fw->dbg_conf_tlv[conf_id] ||
+ !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
+ conf_id == FW_DBG_START_FROM_ALIVE) {
+ iwl_mvm_restart_early_start(mvm);
+ return 0;
+ }
+
if (!mvm->fw->dbg_conf_tlv[conf_id])
return -EINVAL;

@@ -663,6 +679,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");

mvm->fw_dbg_conf = FW_DBG_INVALID;
+ /* if we have a destination, assume EARLY START */
+ if (mvm->fw->dbg_dest_tlv)
+ mvm->fw_dbg_conf = FW_DBG_START_FROM_ALIVE;
iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_START_FROM_ALIVE);

ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
--
1.9.1


2015-03-01 19:32:46

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 29/31] iwlwifi: mvm: add trigger for firmware dump upon statistics

It can be very useful to monitor the statistics and trigger
a firmware dump when a certain value hits a certain offset.
Since the statistics are huge, add a generic trigger. When
the DWORD at offset X reaches value Y.

Since there is another trigger before this one I can't add
right now because of a dependency on mac80211, add a
reserved entry to keep the enum in place.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 14 +++++++++++
drivers/net/wireless/iwlwifi/mvm/rx.c | 30 ++++++++++++++++++++++++
3 files changed, 48 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 1d5195b..95bef17 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -246,6 +246,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch.
* @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a
* command response or a notification.
+ * @FW_DB_TRIGGER_RESERVED: reserved
+ * @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -254,6 +256,8 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_MISSED_BEACONS,
FW_DBG_TRIGGER_CHANNEL_SWITCH,
FW_DBG_TRIGGER_FW_NOTIF,
+ FW_DB_TRIGGER_RESERVED,
+ FW_DBG_TRIGGER_STATS,

/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 49388c2..de0e96d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -552,6 +552,20 @@ struct iwl_fw_dbg_trigger_cmd {
} __packed;

/**
+ * iwl_fw_dbg_trigger_stats - configures trigger for statistics
+ * @stop_offset: the offset of the value to be monitored
+ * @stop_threshold: the threshold above which to collect
+ * @start_offset: the offset of the value to be monitored
+ * @start_threshold: the threshold above which to start recording
+ */
+struct iwl_fw_dbg_trigger_stats {
+ __le32 stop_offset;
+ __le32 stop_threshold;
+ __le32 start_offset;
+ __le32 start_threshold;
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index b86ff66..9b2c537 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -508,6 +508,34 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
}
}

+static inline void
+iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_stats *trig_stats;
+ u32 trig_offset, trig_thold;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_STATS))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_STATS);
+ trig_stats = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+ return;
+
+ trig_offset = le32_to_cpu(trig_stats->stop_offset);
+ trig_thold = le32_to_cpu(trig_stats->stop_threshold);
+
+ if (WARN_ON_ONCE(trig_offset >= iwl_rx_packet_payload_len(pkt)))
+ return;
+
+ if (le32_to_cpup((__le32 *) (pkt->data + trig_offset)) < trig_thold)
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL, 0);
+}
+
void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt)
{
@@ -553,6 +581,8 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
iwl_mvm_update_rx_statistics(mvm, &stats->rx);
}

+ iwl_mvm_rx_stats_check_trigger(mvm, pkt);
+
/* Only handle rx statistics temperature changes if async temp
* notifications are not supported
*/
--
1.9.1


2015-03-01 19:32:29

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 19/31] iwlwifi: mvm: don't iterate interfaces to disconnect in net-detect

From: Luciano Coelho <[email protected]>

We shouldn't call iwl_mvm_d3_disconnect_iter() on the running
interfaces when we are woken up due to net-detect, because it doesn't
make sense. Additionally, this seems to set the
IEEE80211_SDATA_DISCONNECT_RESUME flag that will cause a disconnection
on the next resume (if a normal WoWLAN is used).

To solve this, skip the iteration loop when net-detect is set.

Reported-by: Samuel Tan <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/d3.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 14e8fd6..9bdfa95 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -1876,25 +1876,28 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)

if (mvm->net_detect) {
iwl_mvm_query_netdetect_reasons(mvm, vif);
+ /* has unlocked the mutex, so skip that */
+ goto out;
} else {
keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (keep)
mvm->keep_vif = vif;
+ /* has unlocked the mutex, so skip that */
+ goto out_iterate;
#endif
}
- /* has unlocked the mutex, so skip that */
- goto out;

out_unlock:
mutex_unlock(&mvm->mutex);

- out:
+out_iterate:
if (!test)
ieee80211_iterate_active_interfaces_rtnl(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);

+out:
/* return 1 to reconfigure the device */
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
--
1.9.1


2015-03-01 19:32:40

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 25/31] iwlwifi: mvm: add trigger for firmware dump upon missed beacons

Missing beacons is a good indication that something is going
wrong in the firmware. Add a trigger to be able to collect
data when we start missing beacons with a configurable
threshold.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 3 +++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 18 +++++++++++++++
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 28 ++++++++++++++++++++++++
3 files changed, 49 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index b733c58..7d74126 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -241,11 +241,14 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* driver should set to indicate that the trigger was initiated by the
* user.
* @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts
+ * @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are
+ * missed.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
FW_DBG_TRIGGER_USER,
FW_DBG_TRIGGER_FW_ASSERT,
+ FW_DBG_TRIGGER_MISSED_BEACONS,

/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index d2c4d21..85745dc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -523,6 +523,24 @@ struct iwl_fw_dbg_trigger_tlv {
#define FW_DBG_INVALID 0xff

/**
+ * struct iwl_fw_dbg_trigger_missed_bcon - configures trigger for missed beacons
+ * @stop_consec_missed_bcon: stop recording if threshold is crossed.
+ * @stop_consec_missed_bcon_since_rx: stop recording if threshold is crossed.
+ * @start_consec_missed_bcon: start recording if threshold is crossed.
+ * @start_consec_missed_bcon_since_rx: start recording if threshold is crossed.
+ * @reserved1: reserved
+ * @reserved2: reserved
+ */
+struct iwl_fw_dbg_trigger_missed_bcon {
+ __le32 stop_consec_missed_bcon;
+ __le32 stop_consec_missed_bcon_since_rx;
+ __le32 reserved2[2];
+ __le32 start_consec_missed_bcon;
+ __le32 start_consec_missed_bcon_since_rx;
+ __le32 reserved1[2];
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index f2bfc15..581b3b8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -1375,10 +1375,18 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
{
struct iwl_missed_beacons_notif *missed_beacons = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ struct iwl_fw_dbg_trigger_missed_bcon *bcon_trig;
+ struct iwl_fw_dbg_trigger_tlv *trigger;
+ u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx;
+ u32 rx_missed_bcon, rx_missed_bcon_since_rx;

if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id))
return;

+ rx_missed_bcon = le32_to_cpu(missed_beacons->consec_missed_beacons);
+ rx_missed_bcon_since_rx =
+ le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx);
/*
* TODO: the threshold should be adjusted based on latency conditions,
* and/or in case of a CS flow on one of the other AP vifs.
@@ -1386,6 +1394,26 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) >
IWL_MVM_MISSED_BEACONS_THRESHOLD)
ieee80211_beacon_loss(vif);
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw,
+ FW_DBG_TRIGGER_MISSED_BEACONS))
+ return;
+
+ trigger = iwl_fw_dbg_get_trigger(mvm->fw,
+ FW_DBG_TRIGGER_MISSED_BEACONS);
+ bcon_trig = (void *)trigger->data;
+ stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon);
+ stop_trig_missed_bcon_since_rx =
+ le32_to_cpu(bcon_trig->stop_consec_missed_bcon_since_rx);
+
+ /* TODO: implement start trigger */
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
+ return;
+
+ if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx ||
+ rx_missed_bcon >= stop_trig_missed_bcon)
+ iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL, 0);
}

int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
--
1.9.1


2015-03-01 22:22:12

by Julian Calaby

[permalink] [raw]
Subject: Re: [PATCH 05/31] iwlwifi: mvm: consider TDLS queues as used during drain

Hi Emmanuel,

On Mon, Mar 2, 2015 at 6:31 AM, Emmanuel Grumbach
<[email protected]> wrote:
> From: Arik Nemtsov <[email protected]>
>
> When a TDLS station is being drained its Tx queues are still in use. Don't
> allocate them to a different station in the meantime.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Reviewed-by: Johannes Berg <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>

Same here.

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2015-03-01 22:23:43

by Julian Calaby

[permalink] [raw]
Subject: Re: [PATCH 19/31] iwlwifi: mvm: don't iterate interfaces to disconnect in net-detect

Hi Emmanuel,

On Mon, Mar 2, 2015 at 6:31 AM, Emmanuel Grumbach
<[email protected]> wrote:
> From: Luciano Coelho <[email protected]>
>
> We shouldn't call iwl_mvm_d3_disconnect_iter() on the running
> interfaces when we are woken up due to net-detect, because it doesn't
> make sense. Additionally, this seems to set the
> IEEE80211_SDATA_DISCONNECT_RESUME flag that will cause a disconnection
> on the next resume (if a normal WoWLAN is used).
>
> To solve this, skip the iteration loop when net-detect is set.
>
> Reported-by: Samuel Tan <[email protected]>
> Reviewed-by: Johannes Berg <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>

Shouldn't this be signed off by Luciano too?

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2015-03-01 19:32:10

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 10/31] iwlwifi: mvm: remove unused function in BT coex

From: Eyal Shapira <[email protected]>

Cleanup unused code.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 6 ------
drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 -
2 files changed, 7 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index 85144d5..adfd1ec 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -1167,12 +1167,6 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
return lut_type != BT_COEX_LOOSE_LUT;
}

-bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant)
-{
- u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
- return ag < BT_HIGH_TRAFFIC;
-}
-
bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
{
u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 6c69d05..07b91d6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -1238,7 +1238,6 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_tx_info *info, u8 ac);

-bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant);
bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm);
void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm);
int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm);
--
1.9.1


2015-03-01 19:32:27

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 18/31] iwlwifi: mvm: new Alive / error table API

The new API slightly changes the layout of the version of
the firmware - prepare for that.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/main.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-devtrace.h | 18 ++--
drivers/net/wireless/iwlwifi/iwl-drv.c | 22 +++-
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 6 +-
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 26 ++++-
drivers/net/wireless/iwlwifi/mvm/fw.c | 49 +++++++--
drivers/net/wireless/iwlwifi/mvm/utils.c | 154 ++++++++++++++++++++++++++--
7 files changed, 245 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index c4d6dd7..234e30f 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1549,7 +1549,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
table.blink1, table.blink2, table.ilink1,
table.ilink2, table.bcon_time, table.gp1,
table.gp2, table.gp3, table.ucode_ver,
- table.hw_ver, table.brd_ver);
+ table.hw_ver, 0, table.brd_ver);
IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
desc_lookup(table.error_id));
IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 78bd41b..53555a0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -431,11 +431,11 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
TP_PROTO(const struct device *dev, u32 desc, u32 tsf_low,
u32 data1, u32 data2, u32 line, u32 blink1,
u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
- u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
+ u32 gp1, u32 gp2, u32 gp3, u32 major, u32 minor, u32 hw_ver,
u32 brd_ver),
TP_ARGS(dev, desc, tsf_low, data1, data2, line,
blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2,
- gp3, ucode_ver, hw_ver, brd_ver),
+ gp3, major, minor, hw_ver, brd_ver),
TP_STRUCT__entry(
DEV_ENTRY
__field(u32, desc)
@@ -451,7 +451,8 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__field(u32, gp1)
__field(u32, gp2)
__field(u32, gp3)
- __field(u32, ucode_ver)
+ __field(u32, major)
+ __field(u32, minor)
__field(u32, hw_ver)
__field(u32, brd_ver)
),
@@ -470,21 +471,22 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__entry->gp1 = gp1;
__entry->gp2 = gp2;
__entry->gp3 = gp3;
- __entry->ucode_ver = ucode_ver;
+ __entry->major = major;
+ __entry->minor = minor;
__entry->hw_ver = hw_ver;
__entry->brd_ver = brd_ver;
),
TP_printk("[%s] #%02d %010u data 0x%08X 0x%08X line %u, "
"blink 0x%05X 0x%05X ilink 0x%05X 0x%05X "
- "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X uCode 0x%08X "
- "hw 0x%08X brd 0x%08X",
+ "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X major 0x%08X "
+ "minor 0x%08X hw 0x%08X brd 0x%08X",
__get_str(dev), __entry->desc, __entry->tsf_low,
__entry->data1,
__entry->data2, __entry->line, __entry->blink1,
__entry->blink2, __entry->ilink1, __entry->ilink2,
__entry->bcon_time, __entry->gp1, __entry->gp2,
- __entry->gp3, __entry->ucode_ver, __entry->hw_ver,
- __entry->brd_ver)
+ __entry->gp3, __entry->major, __entry->minor,
+ __entry->hw_ver, __entry->brd_ver)
);

TRACE_EVENT(iwlwifi_dev_ucode_event,
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 996e7f1..b608114 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -842,6 +842,23 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
capa->n_scan_channels =
le32_to_cpup((__le32 *)tlv_data);
break;
+ case IWL_UCODE_TLV_FW_VERSION: {
+ __le32 *ptr = (void *)tlv_data;
+ u32 major, minor;
+ u8 local_comp;
+
+ if (tlv_len != sizeof(u32) * 3)
+ goto invalid_tlv_len;
+
+ major = le32_to_cpup(ptr++);
+ minor = le32_to_cpup(ptr++);
+ local_comp = le32_to_cpup(ptr);
+
+ snprintf(drv->fw.fw_version,
+ sizeof(drv->fw.fw_version), "%u.%u.%u",
+ major, minor, local_comp);
+ break;
+ }
case IWL_UCODE_TLV_FW_DBG_DEST: {
struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data;

@@ -1107,7 +1124,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
if (err)
goto try_again;

- api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
+ if (drv->fw.ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)
+ api_ver = drv->fw.ucode_ver;
+ else
+ api_ver = IWL_UCODE_API(drv->fw.ucode_ver);

/*
* api_ver should match the api version forming part of the
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index be4393e..3ec32e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -133,6 +133,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_N_SCAN_CHANNELS = 31,
IWL_UCODE_TLV_SEC_RT_USNIFFER = 34,
IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35,
+ IWL_UCODE_TLV_FW_VERSION = 36,
IWL_UCODE_TLV_FW_DBG_DEST = 38,
IWL_UCODE_TLV_FW_DBG_CONF = 39,
};
@@ -156,7 +157,8 @@ struct iwl_tlv_ucode_header {
__le32 zero;
__le32 magic;
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
- __le32 ver; /* major/minor/API/serial */
+ /* major/minor/API/serial or major in new format */
+ __le32 ver;
__le32 build;
__le64 ignore;
/*
@@ -250,6 +252,7 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported.
* @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
* @IWL_UCODE_TLV_API_STATS_V10: uCode supports/uses statistics API version 10
+ * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format
*/
enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
@@ -263,6 +266,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17),
IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18),
IWL_UCODE_TLV_API_STATS_V10 = BIT(19),
+ IWL_UCODE_TLV_API_NEW_VERSION = BIT(20),
};

/**
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index c43e5c2..d95b472 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -432,7 +432,7 @@ enum {

#define IWL_ALIVE_FLG_RFKILL BIT(0)

-struct mvm_alive_resp {
+struct mvm_alive_resp_ver1 {
__le16 status;
__le16 flags;
u8 ucode_minor;
@@ -483,6 +483,30 @@ struct mvm_alive_resp_ver2 {
__le32 dbg_print_buff_addr;
} __packed; /* ALIVE_RES_API_S_VER_2 */

+struct mvm_alive_resp {
+ __le16 status;
+ __le16 flags;
+ __le32 ucode_minor;
+ __le32 ucode_major;
+ u8 ver_subtype;
+ u8 ver_type;
+ u8 mac;
+ u8 opt;
+ __le32 timestamp;
+ __le32 error_event_table_ptr; /* SRAM address for error log */
+ __le32 log_event_table_ptr; /* SRAM address for LMAC event log */
+ __le32 cpu_register_ptr;
+ __le32 dbgm_config_ptr;
+ __le32 alive_counter_ptr;
+ __le32 scd_base_ptr; /* SRAM address for SCD */
+ __le32 st_fwrd_addr; /* pointer to Store and forward */
+ __le32 st_fwrd_size;
+ __le32 umac_minor; /* UMAC version: minor */
+ __le32 umac_major; /* UMAC version: major */
+ __le32 error_info_addr; /* SRAM address for UMAC error log */
+ __le32 dbg_print_buff_addr;
+} __packed; /* ALIVE_RES_API_S_VER_3 */
+
/* Error response/notification */
enum {
FW_ERR_UNKNOWN_CMD = 0x0,
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index ab81124..7426bb0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -112,25 +112,27 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
struct iwl_mvm *mvm =
container_of(notif_wait, struct iwl_mvm, notif_wait);
struct iwl_mvm_alive_data *alive_data = data;
- struct mvm_alive_resp *palive;
+ struct mvm_alive_resp_ver1 *palive1;
struct mvm_alive_resp_ver2 *palive2;
+ struct mvm_alive_resp *palive;

- if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
- palive = (void *)pkt->data;
+ if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive1)) {
+ palive1 = (void *)pkt->data;

mvm->support_umac_log = false;
mvm->error_event_table =
- le32_to_cpu(palive->error_event_table_ptr);
- mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
- alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+ le32_to_cpu(palive1->error_event_table_ptr);
+ mvm->log_event_table =
+ le32_to_cpu(palive1->log_event_table_ptr);
+ alive_data->scd_base_addr = le32_to_cpu(palive1->scd_base_ptr);

- alive_data->valid = le16_to_cpu(palive->status) ==
+ alive_data->valid = le16_to_cpu(palive1->status) ==
IWL_ALIVE_STATUS_OK;
IWL_DEBUG_FW(mvm,
"Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
- le16_to_cpu(palive->status), palive->ver_type,
- palive->ver_subtype, palive->flags);
- } else {
+ le16_to_cpu(palive1->status), palive1->ver_type,
+ palive1->ver_subtype, palive1->flags);
+ } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive2)) {
palive2 = (void *)pkt->data;

mvm->error_event_table =
@@ -156,6 +158,33 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
IWL_DEBUG_FW(mvm,
"UMAC version: Major - 0x%x, Minor - 0x%x\n",
palive2->umac_major, palive2->umac_minor);
+ } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
+ palive = (void *)pkt->data;
+
+ mvm->error_event_table =
+ le32_to_cpu(palive->error_event_table_ptr);
+ mvm->log_event_table =
+ le32_to_cpu(palive->log_event_table_ptr);
+ alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+ mvm->umac_error_event_table =
+ le32_to_cpu(palive->error_info_addr);
+ mvm->sf_space.addr = le32_to_cpu(palive->st_fwrd_addr);
+ mvm->sf_space.size = le32_to_cpu(palive->st_fwrd_size);
+
+ alive_data->valid = le16_to_cpu(palive->status) ==
+ IWL_ALIVE_STATUS_OK;
+ if (mvm->umac_error_event_table)
+ mvm->support_umac_log = true;
+
+ IWL_DEBUG_FW(mvm,
+ "Alive VER3 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+ le16_to_cpu(palive->status), palive->ver_type,
+ palive->ver_subtype, palive->flags);
+
+ IWL_DEBUG_FW(mvm,
+ "UMAC version: Major - 0x%x, Minor - 0x%x\n",
+ le32_to_cpu(palive->umac_major),
+ le32_to_cpu(palive->umac_minor));
}

return true;
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index a501223..2b9de63 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -332,7 +332,7 @@ static const char *desc_lookup(u32 num)
* read with u32-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
-struct iwl_error_event_table {
+struct iwl_error_event_table_v1 {
u32 valid; /* (nonzero) valid, (0) log is empty */
u32 error_id; /* type of error */
u32 pc; /* program counter */
@@ -377,7 +377,55 @@ struct iwl_error_event_table {
u32 u_timestamp; /* indicate when the date and time of the
* compilation */
u32 flow_handler; /* FH read/write pointers, RX credit */
-} __packed;
+} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */;
+
+struct iwl_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 pc; /* program counter */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 gp3; /* GP3 timer register */
+ u32 major; /* uCode version major */
+ u32 minor; /* uCode version minor */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0:
+ * rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1:
+ * host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2:
+ * enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3:
+ * time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4:
+ * wico interrupt */
+ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on
+ * (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the
+ * compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_2 */;

/*
* UMAC error struct - relevant starting from family 8000 chip.
@@ -396,11 +444,11 @@ struct iwl_umac_error_event_table {
u32 data1; /* error-specific data */
u32 data2; /* error-specific data */
u32 data3; /* error-specific data */
- u32 umac_fw_ver; /* UMAC version */
- u32 umac_fw_api_ver; /* UMAC FW API ver */
+ u32 umac_major;
+ u32 umac_minor;
u32 frame_pointer; /* core register 27*/
u32 stack_pointer; /* core register 28 */
- u32 cmd_header; /* latest host cmd sent to UMAC */
+ u32 cmd_header; /* latest host cmd sent to UMAC */
u32 nic_isr_pref; /* ISR status register */
} __packed;

@@ -441,18 +489,18 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
- IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver);
- IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver);
+ IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major);
+ IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor);
IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
}

-void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+static void iwl_mvm_dump_nic_error_log_old(struct iwl_mvm *mvm)
{
struct iwl_trans *trans = mvm->trans;
- struct iwl_error_event_table table;
+ struct iwl_error_event_table_v1 table;
u32 base;

base = mvm->error_event_table;
@@ -489,7 +537,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
table.data1, table.data2, table.data3,
table.blink1, table.blink2, table.ilink1,
table.ilink2, table.bcon_time, table.gp1,
- table.gp2, table.gp3, table.ucode_ver,
+ table.gp2, table.gp3, table.ucode_ver, 0,
table.hw_ver, table.brd_ver);
IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
desc_lookup(table.error_id));
@@ -530,6 +578,92 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
iwl_mvm_dump_umac_error_log(mvm);
}

+void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+{
+ struct iwl_trans *trans = mvm->trans;
+ struct iwl_error_event_table table;
+ u32 base;
+
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)) {
+ iwl_mvm_dump_nic_error_log_old(mvm);
+ return;
+ }
+
+ base = mvm->error_event_table;
+ if (mvm->cur_ucode == IWL_UCODE_INIT) {
+ if (!base)
+ base = mvm->fw->init_errlog_ptr;
+ } else {
+ if (!base)
+ base = mvm->fw->inst_errlog_ptr;
+ }
+
+ if (base < 0x800000) {
+ IWL_ERR(mvm,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (mvm->cur_ucode == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+ mvm->status, table.valid);
+ }
+
+ /* Do not change this output - scripts rely on it */
+
+ IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
+
+ trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+ table.data1, table.data2, table.data3,
+ table.blink1, table.blink2, table.ilink1,
+ table.ilink2, table.bcon_time, table.gp1,
+ table.gp2, table.gp3, table.major,
+ table.minor, table.hw_ver, table.brd_ver);
+ IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+ desc_lookup(table.error_id));
+ IWL_ERR(mvm, "0x%08X | uPc\n", table.pc);
+ IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1);
+ IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(mvm, "0x%08X | data1\n", table.data1);
+ IWL_ERR(mvm, "0x%08X | data2\n", table.data2);
+ IWL_ERR(mvm, "0x%08X | data3\n", table.data3);
+ IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3);
+ IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major);
+ IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor);
+ IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd);
+ IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0);
+ IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1);
+ IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2);
+ IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3);
+ IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4);
+ IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref);
+ IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event);
+ IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control);
+ IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration);
+ IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+ IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+ IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+ IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
+ IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
+
+ if (mvm->support_umac_log)
+ iwl_mvm_dump_umac_error_log(mvm);
+}
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout)
--
1.9.1


2015-03-01 19:32:44

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 27/31] iwlwifi: mvm: add trigger for firmware dump upon command response

This will allow to collect the data as soon the firmware
sends a specific notification of command response.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 3 +++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 11 ++++++++
drivers/net/wireless/iwlwifi/mvm/ops.c | 34 ++++++++++++++++++++++++
3 files changed, 48 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 1ee58b3..1d5195b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -244,6 +244,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are
* missed.
* @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch.
+ * @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a
+ * command response or a notification.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -251,6 +253,7 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_FW_ASSERT,
FW_DBG_TRIGGER_MISSED_BEACONS,
FW_DBG_TRIGGER_CHANNEL_SWITCH,
+ FW_DBG_TRIGGER_FW_NOTIF,

/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 85745dc..49388c2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -541,6 +541,17 @@ struct iwl_fw_dbg_trigger_missed_bcon {
} __packed;

/**
+ * struct iwl_fw_dbg_trigger_cmd - configures trigger for messages from FW.
+ * cmds: the list of commands to trigger the collection on
+ */
+struct iwl_fw_dbg_trigger_cmd {
+ struct cmd {
+ u8 cmd_id;
+ u8 group_id;
+ } __packed cmds[16];
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index f1c5751..fe40922 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -685,6 +685,38 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
mutex_unlock(&mvm->mutex);
}

+static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_cmd *cmds_trig;
+ char buf[32];
+ int i;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF);
+ cmds_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(cmds_trig->cmds); i++) {
+ /* don't collect on CMD 0 */
+ if (!cmds_trig->cmds[i].cmd_id)
+ break;
+
+ if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd)
+ continue;
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf), "CMD 0x%02x received", pkt->hdr.cmd);
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig, buf, sizeof(buf));
+ break;
+ }
+}
+
static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
@@ -693,6 +725,8 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u8 i;

+ iwl_mvm_rx_check_trigger(mvm, pkt);
+
/*
* Do the notification wait before RX handlers so
* even if the RX handler consumes the RXB we have
--
1.9.1


2015-03-01 19:32:14

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 12/31] iwlwifi: mvm: add statistics API version 10

From: Johannes Berg <[email protected]>

New firmware versions will report statistics using a new version 10
of the API, instead of the current version 8. Add support for this.
This enables getting beacon and radio statistics.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 +
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | 1 +
drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h | 47 +++++++++++++++++--
drivers/net/wireless/iwlwifi/mvm/rx.c | 62 +++++++++++++++++--------
4 files changed, 90 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 016d913..4602e3c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -250,6 +250,7 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too.
* @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported.
* @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
+ * @IWL_UCODE_TLV_API_STATS_V10: uCode supports/uses statistics API version 10
*/
enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
@@ -263,6 +264,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16),
IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17),
IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18),
+ IWL_UCODE_TLV_API_STATS_V10 = BIT(19),
};

/**
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
index c405cda..aabaedd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
@@ -70,6 +70,7 @@
#define MAC_INDEX_AUX 4
#define MAC_INDEX_MIN_DRIVER 0
#define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX
+#define NUM_MAC_INDEX (MAC_INDEX_AUX + 1)

enum iwl_ac {
AC_BK,
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
index 928168b..5a9dfe0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
@@ -65,6 +65,7 @@

#ifndef __fw_api_stats_h__
#define __fw_api_stats_h__
+#include "fw-api-mac.h"

struct mvm_statistics_dbg {
__le32 burst_check;
@@ -218,7 +219,7 @@ struct mvm_statistics_bt_activity {
__le32 lo_priority_rx_denied_cnt;
} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */

-struct mvm_statistics_general {
+struct mvm_statistics_general_v5 {
__le32 radio_temperature;
__le32 radio_voltage;
struct mvm_statistics_dbg dbg;
@@ -244,6 +245,39 @@ struct mvm_statistics_general {
struct mvm_statistics_bt_activity bt_activity;
} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */

+struct mvm_statistics_general_v8 {
+ __le32 radio_temperature;
+ __le32 radio_voltage;
+ struct mvm_statistics_dbg dbg;
+ __le32 sleep_time;
+ __le32 slots_out;
+ __le32 slots_idle;
+ __le32 ttl_timestamp;
+ struct mvm_statistics_div slow_div;
+ __le32 rx_enable_counter;
+ /*
+ * num_of_sos_states:
+ * count the number of times we have to re-tune
+ * in order to get out of bad PHY status
+ */
+ __le32 num_of_sos_states;
+ __le32 beacon_filtered;
+ __le32 missed_beacons;
+ __s8 beacon_filter_average_energy;
+ __s8 beacon_filter_reason;
+ __s8 beacon_filter_current_energy;
+ __s8 beacon_filter_reserved;
+ __le32 beacon_filter_delta_time;
+ struct mvm_statistics_bt_activity bt_activity;
+ __le64 rx_time;
+ __le64 on_time_rf;
+ __le64 on_time_scan;
+ __le64 tx_time;
+ __le32 beacon_counter[NUM_MAC_INDEX];
+ u8 beacon_average_energy[NUM_MAC_INDEX];
+ u8 reserved[4 - (NUM_MAC_INDEX % 4)];
+} __packed; /* STATISTICS_GENERAL_API_S_VER_8 */
+
struct mvm_statistics_rx {
struct mvm_statistics_rx_phy ofdm;
struct mvm_statistics_rx_phy cck;
@@ -267,11 +301,18 @@ struct mvm_statistics_rx {
* one channel that has just been scanned.
*/

-struct iwl_notif_statistics {
+struct iwl_notif_statistics_v8 {
__le32 flag;
struct mvm_statistics_rx rx;
struct mvm_statistics_tx tx;
- struct mvm_statistics_general general;
+ struct mvm_statistics_general_v5 general;
} __packed; /* STATISTICS_NTFY_API_S_VER_8 */

+struct iwl_notif_statistics_v10 {
+ __le32 flag;
+ struct mvm_statistics_rx rx;
+ struct mvm_statistics_tx tx;
+ struct mvm_statistics_general_v8 general;
+} __packed; /* STATISTICS_NTFY_API_S_VER_10 */
+
#endif /* __fw_api_stats_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index f922131..fffd89d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -416,33 +416,29 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
}

static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm,
- struct iwl_notif_statistics *stats)
+ struct mvm_statistics_rx *rx_stats)
{
- /*
- * NOTE FW aggregates the statistics - BUT the statistics are cleared
- * when the driver issues REPLY_STATISTICS_CMD 0x9c with CLEAR_STATS
- * bit set.
- */
lockdep_assert_held(&mvm->mutex);
- memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx));
+
+ mvm->rx_stats = *rx_stats;
}

struct iwl_mvm_stat_data {
- struct iwl_notif_statistics *stats;
struct iwl_mvm *mvm;
+ __le32 mac_id;
+ __s8 beacon_filter_average_energy;
};

static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_stat_data *data = _data;
- struct iwl_notif_statistics *stats = data->stats;
struct iwl_mvm *mvm = data->mvm;
- int sig = -stats->general.beacon_filter_average_energy;
+ int sig = -data->beacon_filter_average_energy;
int last_event;
int thold = vif->bss_conf.cqm_rssi_thold;
int hyst = vif->bss_conf.cqm_rssi_hyst;
- u16 id = le32_to_cpu(stats->rx.general.mac_id);
+ u16 id = le32_to_cpu(data->mac_id);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

if (mvmvif->id != id)
@@ -510,24 +506,52 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_notif_statistics *stats = (void *)&pkt->data;
+ size_t v8_len = sizeof(struct iwl_notif_statistics_v8);
+ size_t v10_len = sizeof(struct iwl_notif_statistics_v10);
struct iwl_mvm_stat_data data = {
- .stats = stats,
.mvm = mvm,
};
+ u32 temperature;
+
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_STATS_V10) {
+ struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data;
+
+ if (iwl_rx_packet_payload_len(pkt) != v10_len)
+ goto invalid;
+
+ temperature = le32_to_cpu(stats->general.radio_temperature);
+ data.mac_id = stats->rx.general.mac_id;
+ data.beacon_filter_average_energy =
+ stats->general.beacon_filter_average_energy;
+
+ iwl_mvm_update_rx_statistics(mvm, &stats->rx);
+ } else {
+ struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data;
+
+ if (iwl_rx_packet_payload_len(pkt) != v8_len)
+ goto invalid;
+
+ temperature = le32_to_cpu(stats->general.radio_temperature);
+ data.mac_id = stats->rx.general.mac_id;
+ data.beacon_filter_average_energy =
+ stats->general.beacon_filter_average_energy;
+
+ iwl_mvm_update_rx_statistics(mvm, &stats->rx);
+ }

/* Only handle rx statistics temperature changes if async temp
* notifications are not supported
*/
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM))
- iwl_mvm_tt_temp_changed(mvm,
- le32_to_cpu(stats->general.radio_temperature));
-
- iwl_mvm_update_rx_statistics(mvm, stats);
+ iwl_mvm_tt_temp_changed(mvm, temperature);

ieee80211_iterate_active_interfaces(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_stat_iterator,
&data);
return 0;
+ invalid:
+ IWL_ERR(mvm, "received invalid statistics size (%d)!\n",
+ iwl_rx_packet_payload_len(pkt));
+ return 0;
}
--
1.9.1


2015-03-01 22:21:10

by Julian Calaby

[permalink] [raw]
Subject: Re: [PATCH 08/31] iwlwifi: mvm: rs: print single stream params via debugfs

Hi Emmanuel,

On Mon, Mar 2, 2015 at 6:31 AM, Emmanuel Grumbach
<[email protected]> wrote:
> From: Eyal Shapira <[email protected]>
>
> Add this to the info printed when reading rate_scale_table.
> Useful for debugging.
>
> Signed-off-by: Eyal Shapira <[email protected]>
> Reviewed-by: Johannes Berg <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>

This signoff chain doesn't look right to me (however other people
might not care): Shouldn't Eyal have used their intel.com email
address in the author field?

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2015-03-01 19:31:52

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 02/31] iwlwifi: mvm: rs: fix BT Coex check to look at the correct ant

From: Eyal Shapira <[email protected]>

The check to avoid the shared antenna was passed the wrong
antenna parameter. It should have checked whether the antenna of
the next column we're considering is allowed and instead it was
passed the current antenna.
This could lead to a wrong choice of the next column in the rs
algorithm and non optimal performance.

Fixes: commit 219fb66b49fac64bb ("iwlwifi: mvm: rs - don't use the shared antenna when BT load is high")
Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 1e82434..2e45b81 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -134,9 +134,12 @@ enum rs_column_mode {
#define MAX_NEXT_COLUMNS 7
#define MAX_COLUMN_CHECKS 3

+struct rs_tx_column;
+
typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl);
+ struct iwl_scale_tbl_info *tbl,
+ const struct rs_tx_column *next_col);

struct rs_tx_column {
enum rs_column_mode mode;
@@ -147,13 +150,15 @@ struct rs_tx_column {
};

static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl)
+ struct iwl_scale_tbl_info *tbl,
+ const struct rs_tx_column *next_col)
{
- return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant);
+ return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
}

static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl)
+ struct iwl_scale_tbl_info *tbl,
+ const struct rs_tx_column *next_col)
{
if (!sta->ht_cap.ht_supported)
return false;
@@ -171,7 +176,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}

static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl)
+ struct iwl_scale_tbl_info *tbl,
+ const struct rs_tx_column *next_col)
{
if (!sta->ht_cap.ht_supported)
return false;
@@ -180,7 +186,8 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}

static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl)
+ struct iwl_scale_tbl_info *tbl,
+ const struct rs_tx_column *next_col)
{
struct rs_rate *rate = &tbl->rate;
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
@@ -1557,7 +1564,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,

for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
allow_func = next_col->checks[j];
- if (allow_func && !allow_func(mvm, sta, tbl))
+ if (allow_func && !allow_func(mvm, sta, tbl, next_col))
break;
}

--
1.9.1


2015-03-02 06:24:48

by Grumbach, Emmanuel

[permalink] [raw]
Subject: Re: [PATCH 19/31] iwlwifi: mvm: don't iterate interfaces to disconnect in net-detect

T24gTW9uLCAyMDE1LTAzLTAyIGF0IDA5OjIzICsxMTAwLCBKdWxpYW4gQ2FsYWJ5IHdyb3RlOg0K
PiBIaSBFbW1hbnVlbCwNCj4gDQo+IE9uIE1vbiwgTWFyIDIsIDIwMTUgYXQgNjozMSBBTSwgRW1t
YW51ZWwgR3J1bWJhY2gNCj4gPGVtbWFudWVsLmdydW1iYWNoQGludGVsLmNvbT4gd3JvdGU6DQo+
ID4gRnJvbTogTHVjaWFubyBDb2VsaG8gPGx1Y2lhbm8uY29lbGhvQGludGVsLmNvbT4NCj4gPg0K
PiA+IFdlIHNob3VsZG4ndCBjYWxsIGl3bF9tdm1fZDNfZGlzY29ubmVjdF9pdGVyKCkgb24gdGhl
IHJ1bm5pbmcNCj4gPiBpbnRlcmZhY2VzIHdoZW4gd2UgYXJlIHdva2VuIHVwIGR1ZSB0byBuZXQt
ZGV0ZWN0LCBiZWNhdXNlIGl0IGRvZXNuJ3QNCj4gPiBtYWtlIHNlbnNlLiAgQWRkaXRpb25hbGx5
LCB0aGlzIHNlZW1zIHRvIHNldCB0aGUNCj4gPiBJRUVFODAyMTFfU0RBVEFfRElTQ09OTkVDVF9S
RVNVTUUgZmxhZyB0aGF0IHdpbGwgY2F1c2UgYSBkaXNjb25uZWN0aW9uDQo+ID4gb24gdGhlIG5l
eHQgcmVzdW1lIChpZiBhIG5vcm1hbCBXb1dMQU4gaXMgdXNlZCkuDQo+ID4NCj4gPiBUbyBzb2x2
ZSB0aGlzLCBza2lwIHRoZSBpdGVyYXRpb24gbG9vcCB3aGVuIG5ldC1kZXRlY3QgaXMgc2V0Lg0K
PiA+DQo+ID4gUmVwb3J0ZWQtYnk6IFNhbXVlbCBUYW4gPHNhbXVlbHRhbkBjaHJvbWl1bS5vcmc+
DQo+ID4gUmV2aWV3ZWQtYnk6IEpvaGFubmVzIEJlcmcgPGpvaGFubmVzLmJlcmdAaW50ZWwuY29t
Pg0KPiA+IFNpZ25lZC1vZmYtYnk6IEVtbWFudWVsIEdydW1iYWNoIDxlbW1hbnVlbC5ncnVtYmFj
aEBpbnRlbC5jb20+DQo+IA0KPiBTaG91bGRuJ3QgdGhpcyBiZSBzaWduZWQgb2ZmIGJ5IEx1Y2lh
bm8gdG9vPw0KPiANCg0KUmlnaHQgLSBJIHJlbW92ZWQgaXQgYnkgbWlzdGFrZSB3aGlsZSByZW1v
dmluZyBvdGhlciB1bm5lZWRlZCBzdHVmZiBpbg0KdGhlIHNhbWUgYXJlYS4gSSB1cGRhdGVkIHRo
ZSB0cmVlIGFuZCB0aGUgdGFnLg0KVGhhbmtzLg0KDQo+IFRoYW5rcywNCj4gDQoNCg==

2015-03-02 08:46:45

by Eyal Shapira

[permalink] [raw]
Subject: Re: [PATCH 08/31] iwlwifi: mvm: rs: print single stream params via debugfs

On Sun, Mar 1, 2015 at 9:42 PM, Joe Perches <[email protected]> wrote:
> On Sun, 2015-03-01 at 21:31 +0200, Emmanuel Grumbach wrote:
>> From: Eyal Shapira <[email protected]>
>>
>> Add this to the info printed when reading rate_scale_table.
>> Useful for debugging.
> []
>> diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
> []
>> @@ -3369,6 +3370,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
>> lq_sta->lq.agg_frame_cnt_limit);
>>
>> desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc);
>> + ss_params = le32_to_cpu(lq_sta->lq.ss_params);
>> + desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
>> + (ss_params & LQ_SS_PARAMS_VALID) ?
>> + "VALID," : "INVALID",
>> + (ss_params & LQ_SS_BFER_ALLOWED) ?
>> + "BFER," : "",
>> + (ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
>> + "STBC," : "",
>> + (ss_params & LQ_SS_FORCE) ?
>> + "FORCE" : "");
>
> Are all things exclusive?

INVALID is exclusive to the other options so there's no real readability issue.
I like your version better though as it avoids the additional comma in the end.
Submitted to Emmanuel's internal tree.
Thanks

> If no, the output is not easily readable.
>
> It would probably be better to use:
> 12345678901234567890123456789012345678901234567890123456789012345678901234567890
> desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
> (ss_params & LQ_SS_PARAMS_VALID) ?
> "VALID" : "INVALID",
> (ss_params & LQ_SS_BFER_ALLOWED) ?
> ", BFER" : "",
> (ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
> ", STBC" : "",
> (ss_params & LQ_SS_FORCE) ?
> ", FORCE" : "");
>

2015-03-01 19:42:11

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH 08/31] iwlwifi: mvm: rs: print single stream params via debugfs

On Sun, 2015-03-01 at 21:31 +0200, Emmanuel Grumbach wrote:
> From: Eyal Shapira <[email protected]>
>
> Add this to the info printed when reading rate_scale_table.
> Useful for debugging.
[]
> diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
[]
> @@ -3369,6 +3370,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
> lq_sta->lq.agg_frame_cnt_limit);
>
> desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc);
> + ss_params = le32_to_cpu(lq_sta->lq.ss_params);
> + desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
> + (ss_params & LQ_SS_PARAMS_VALID) ?
> + "VALID," : "INVALID",
> + (ss_params & LQ_SS_BFER_ALLOWED) ?
> + "BFER," : "",
> + (ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
> + "STBC," : "",
> + (ss_params & LQ_SS_FORCE) ?
> + "FORCE" : "");

Are all things exclusive?
If no, the output is not easily readable.

It would probably be better to use:
12345678901234567890123456789012345678901234567890123456789012345678901234567890
desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
(ss_params & LQ_SS_PARAMS_VALID) ?
"VALID" : "INVALID",
(ss_params & LQ_SS_BFER_ALLOWED) ?
", BFER" : "",
(ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
", STBC" : "",
(ss_params & LQ_SS_FORCE) ?
", FORCE" : "");



2015-03-01 19:31:51

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 01/31] iwlwifi: mvm: rs: better match tx response rate to the LQ table

From: Eyal Shapira <[email protected]>

Currently rs uses the info in mac80211 tx status which is
a translation of the actual rate coming up from the FW in
the tx response. This is matched up against the LQ table first
rate to make sure this tx frame used the current LQ table.
Instead of using the translated mac80211 info it's easier and
cleaner to just pass the actual tx response rate in the driver
private data and use that for matching.
This becomes even more important once the FW begins to
decide on its own whether to use STBC/BFER/SISO.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 119 ++++++++++++----------------------
drivers/net/wireless/iwlwifi/mvm/tx.c | 4 ++
2 files changed, 47 insertions(+), 76 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 194bd1f..1e82434 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1001,10 +1001,19 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rs_get_lower_rate_in_column(lq_sta, rate);
}

-/* Simple function to compare two rate scale table types */
-static inline bool rs_rate_match(struct rs_rate *a,
+/* Check if both rates are identical */
+static inline bool rs_rate_equal(struct rs_rate *a,
struct rs_rate *b)
{
+ return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi) &&
+ (a->ldpc == b->ldpc) && (a->index == b->index) &&
+ (a->ant == b->ant);
+}
+
+/* Check if both rates share the same column */
+static inline bool rs_rate_column_match(struct rs_rate *a,
+ struct rs_rate *b)
+{
bool ant_match;

if (a->stbc)
@@ -1016,18 +1025,6 @@ static inline bool rs_rate_match(struct rs_rate *a,
&& ant_match;
}

-static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
-{
- if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- return RATE_MCS_CHAN_WIDTH_40;
- else if (flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- return RATE_MCS_CHAN_WIDTH_80;
- else if (flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
- return RATE_MCS_CHAN_WIDTH_160;
-
- return RATE_MCS_CHAN_WIDTH_20;
-}
-
static u8 rs_get_tid(struct ieee80211_hdr *hdr)
{
u8 tid = IWL_MAX_TID_COUNT;
@@ -1048,13 +1045,13 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
{
int legacy_success;
int retries;
- int mac_index, i;
+ int i;
struct iwl_lq_cmd *table;
- enum mac80211_rate_control_flags mac_flags;
- u32 ucode_rate;
- struct rs_rate rate;
+ u32 lq_hwrate;
+ struct rs_rate lq_rate, tx_resp_rate;
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0];
+ u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta;

@@ -1079,39 +1076,6 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;

- /*
- * Ignore this Tx frame response if its initial rate doesn't match
- * that of latest Link Quality command. There may be stragglers
- * from a previous Link Quality command, but we're no longer interested
- * in those; they're either from the "active" mode while we're trying
- * to check "search" mode, or a prior "search" mode after we've moved
- * to a new "search" mode (which might become the new "active" mode).
- */
- table = &lq_sta->lq;
- ucode_rate = le32_to_cpu(table->rs_table[0]);
- rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
- if (info->band == IEEE80211_BAND_5GHZ)
- rate.index -= IWL_FIRST_OFDM_RATE;
- mac_flags = info->status.rates[0].flags;
- mac_index = info->status.rates[0].idx;
- /* For HT packets, map MCS to PLCP */
- if (mac_flags & IEEE80211_TX_RC_MCS) {
- /* Remove # of streams */
- mac_index &= RATE_HT_MCS_RATE_CODE_MSK;
- if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
- mac_index++;
- /*
- * mac80211 HT index is always zero-indexed; we need to move
- * HT OFDM rates after CCK rates in 2.4 GHz band
- */
- if (info->band == IEEE80211_BAND_2GHZ)
- mac_index += IWL_FIRST_OFDM_RATE;
- } else if (mac_flags & IEEE80211_TX_RC_VHT_MCS) {
- mac_index &= RATE_VHT_MCS_RATE_CODE_MSK;
- if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
- mac_index++;
- }
-
if (time_after(jiffies,
(unsigned long)(lq_sta->last_tx +
(IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
@@ -1126,21 +1090,24 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
lq_sta->last_tx = jiffies;

+ /* Ignore this Tx frame response if its initial rate doesn't match
+ * that of latest Link Quality command. There may be stragglers
+ * from a previous Link Quality command, but we're no longer interested
+ * in those; they're either from the "active" mode while we're trying
+ * to check "search" mode, or a prior "search" mode after we've moved
+ * to a new "search" mode (which might become the new "active" mode).
+ */
+ table = &lq_sta->lq;
+ lq_hwrate = le32_to_cpu(table->rs_table[0]);
+ rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate);
+ rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate);
+
/* Here we actually compare this rate to the latest LQ command */
- if ((mac_index < 0) ||
- (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
- (rate.bw != rs_ch_width_from_mac_flags(mac_flags)) ||
- (rate.ant != info->status.antenna) ||
- (!!(ucode_rate & RATE_MCS_HT_MSK) !=
- !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
- (!!(ucode_rate & RATE_MCS_VHT_MSK) !=
- !!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) ||
- (!!(ucode_rate & RATE_HT_MCS_GF_MSK) !=
- !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
- (rate.index != mac_index)) {
+ if (!rs_rate_equal(&tx_resp_rate, &lq_rate)) {
IWL_DEBUG_RATE(mvm,
- "initial rate %d does not match %d (0x%x)\n",
- mac_index, rate.index, ucode_rate);
+ "initial tx resp rate 0x%x does not match 0x%x\n",
+ tx_resp_hwrate, lq_hwrate);
+
/*
* Since rates mis-match, the last LQ command may have failed.
* After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
@@ -1168,14 +1135,14 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
}

- if (WARN_ON_ONCE(!rs_rate_match(&rate, &curr_tbl->rate))) {
+ if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) {
IWL_DEBUG_RATE(mvm,
"Neither active nor search matches tx rate\n");
tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
- rs_dump_rate(mvm, &rate, "ACTUAL");
+ rs_dump_rate(mvm, &lq_rate, "ACTUAL");

/*
* no matching table found, let's by-pass the data collection
@@ -1200,9 +1167,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (info->status.ampdu_ack_len == 0)
info->status.ampdu_len = 1;

- ucode_rate = le32_to_cpu(table->rs_table[0]);
- rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
- rs_collect_tx_data(mvm, lq_sta, curr_tbl, rate.index,
+ rs_collect_tx_data(mvm, lq_sta, curr_tbl, lq_rate.index,
info->status.ampdu_len,
info->status.ampdu_ack_len,
reduced_txp);
@@ -1225,21 +1190,23 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
/* Collect data for each rate used during failed TX attempts */
for (i = 0; i <= retries; ++i) {
- ucode_rate = le32_to_cpu(table->rs_table[i]);
- rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
+ lq_hwrate = le32_to_cpu(table->rs_table[i]);
+ rs_rate_from_ucode_rate(lq_hwrate, info->band,
+ &lq_rate);
/*
* Only collect stats if retried rate is in the same RS
* table as active/search.
*/
- if (rs_rate_match(&rate, &curr_tbl->rate))
+ if (rs_rate_column_match(&lq_rate, &curr_tbl->rate))
tmp_tbl = curr_tbl;
- else if (rs_rate_match(&rate, &other_tbl->rate))
+ else if (rs_rate_column_match(&lq_rate,
+ &other_tbl->rate))
tmp_tbl = other_tbl;
else
continue;

- rs_collect_tx_data(mvm, lq_sta, tmp_tbl, rate.index, 1,
- i < retries ? 0 : legacy_success,
+ rs_collect_tx_data(mvm, lq_sta, tmp_tbl, lq_rate.index,
+ 1, i < retries ? 0 : legacy_success,
reduced_txp);
}

@@ -1250,7 +1217,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
}
/* The last TX rate is cached in lq_sta; it's set in if/else above */
- lq_sta->last_rate_n_flags = ucode_rate;
+ lq_sta->last_rate_n_flags = lq_hwrate;
IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
done:
/* See if there's a better rate or modulation mode to try. */
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 07304e1..7906b97 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -664,6 +664,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
info->status.rates[0].count = tx_resp->failure_frame + 1;
iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
info);
+ info->status.status_driver_data[1] =
+ (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 &&
@@ -909,6 +911,8 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,
info->status.tx_time = tid_data->tx_time;
info->status.status_driver_data[0] =
(void *)(uintptr_t)tid_data->reduced_tpc;
+ info->status.status_driver_data[1] =
+ (void *)(uintptr_t)tid_data->rate_n_flags;
}

int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
--
1.9.1


2015-03-01 19:32:12

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 11/31] iwlwifi: pcie: apply destination before releasing reset

This allows to use the firmware debugging system even when
the configuration values are set hard coded in the firmware.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/pcie/trans.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 69935aa..f31a941 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -898,6 +898,9 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
IWL_DEBUG_FW(trans, "working with %s CPU\n",
image->is_dual_cpus ? "Dual" : "Single");

+ if (trans->dbg_dest_tlv)
+ iwl_pcie_apply_destination(trans);
+
/* configure the ucode to be ready to get the secured image */
/* release CPU reset */
iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT);
@@ -914,9 +917,6 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
if (ret)
return ret;

- if (trans->dbg_dest_tlv)
- iwl_pcie_apply_destination(trans);
-
/* wait for image verification to complete */
ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0,
LMPM_SECURE_BOOT_STATUS_SUCCESS,
--
1.9.1


2015-03-01 19:32:03

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 07/31] iwlwifi: mvm: rs: avoid ss_force from being reset after tx idle

From: Eyal Shapira <[email protected]>

ss_force is a debugging option to force a certain single stream
tx mode. It's not useful if it gets reset after tx idle. Fix that.
While at it also make sure any code touching ss_force will only
get compiled if debugfs support is configured.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 21 ++++++++++++---------
drivers/net/wireless/iwlwifi/mvm/rs.h | 6 +++---
2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 2bed577..43f807f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -2545,6 +2545,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->pers.dbg_fixed_rate = 0;
lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID;
+ lq_sta->pers.ss_force = RS_SS_FORCE_NONE;
#endif
lq_sta->pers.chains = 0;
memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
@@ -3067,19 +3068,21 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
goto out;

+#ifdef CONFIG_MAC80211_DEBUGFS
/* Check if forcing the decision is configured.
* Note that SISO is forced by not allowing STBC or BFER
*/
- if (lq_sta->ss_force == RS_SS_FORCE_STBC)
+ if (lq_sta->pers.ss_force == RS_SS_FORCE_STBC)
ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE);
- else if (lq_sta->ss_force == RS_SS_FORCE_BFER)
+ else if (lq_sta->pers.ss_force == RS_SS_FORCE_BFER)
ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE);

- if (lq_sta->ss_force != RS_SS_FORCE_NONE) {
+ if (lq_sta->pers.ss_force != RS_SS_FORCE_NONE) {
IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n",
- lq_sta->ss_force);
+ lq_sta->pers.ss_force);
goto out;
}
+#endif

if (lq_sta->stbc_capable)
ss_params |= LQ_SS_STBC_1SS_ALLOWED;
@@ -3542,7 +3545,7 @@ static ssize_t iwl_dbgfs_ss_force_read(struct file *file,
};

pos += scnprintf(buf+pos, bufsz-pos, "%s\n",
- ss_force_name[lq_sta->ss_force]);
+ ss_force_name[lq_sta->pers.ss_force]);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}

@@ -3553,12 +3556,12 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
int ret = 0;

if (!strncmp("none", buf, 4)) {
- lq_sta->ss_force = RS_SS_FORCE_NONE;
+ lq_sta->pers.ss_force = RS_SS_FORCE_NONE;
} else if (!strncmp("siso", buf, 4)) {
- lq_sta->ss_force = RS_SS_FORCE_SISO;
+ lq_sta->pers.ss_force = RS_SS_FORCE_SISO;
} else if (!strncmp("stbc", buf, 4)) {
if (lq_sta->stbc_capable) {
- lq_sta->ss_force = RS_SS_FORCE_STBC;
+ lq_sta->pers.ss_force = RS_SS_FORCE_STBC;
} else {
IWL_ERR(mvm,
"can't force STBC. peer doesn't support\n");
@@ -3566,7 +3569,7 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
}
} else if (!strncmp("bfer", buf, 4)) {
if (lq_sta->bfer_capable) {
- lq_sta->ss_force = RS_SS_FORCE_BFER;
+ lq_sta->pers.ss_force = RS_SS_FORCE_BFER;
} else {
IWL_ERR(mvm,
"can't force BFER. peer doesn't support\n");
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 4cb278f..e4aa934 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -332,14 +332,14 @@ struct iwl_lq_sta {
/* tx power reduce for this sta */
int tpc_reduce;

- /* force STBC/BFER/SISO for testing */
- enum rs_ss_force_opt ss_force;
-
/* persistent fields - initialized only once - keep last! */
struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
u32 dbg_fixed_rate;
u8 dbg_fixed_txp_reduction;
+
+ /* force STBC/BFER/SISO for testing */
+ enum rs_ss_force_opt ss_force;
#endif
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
--
1.9.1


2015-03-01 19:31:54

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 03/31] iwlwifi: mvm: rs: adapt rate matching to new STBC/BFER

From: Eyal Shapira <[email protected]>

Once the FW supports autonomous decision between STBC/BFER/SISO
we no longer set the STBC bit and ANT_AB in the rate table.
However the FW rate in the tx response will have the STBC
or BFER bit set and the antennas set to ANT_AB in case these
were chosen by it. This will cause us to discard any such
response as unmatching the current LQ table and thus break
the rs search cycle completely.
Fix this by relaxing the rate matching in case we're working
with the new API and STBC/BFER are used.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 45 ++++++++++++++++++++++++++++-------
drivers/net/wireless/iwlwifi/mvm/rs.h | 1 +
2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 2e45b81..37002cf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -807,6 +807,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
rate->ldpc = true;
if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
rate->stbc = true;
+ if (ucode_rate & RATE_MCS_BF_MSK)
+ rate->bfer = true;

rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;

@@ -816,7 +818,9 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,

if (nss == 1) {
rate->type = LQ_HT_SISO;
- WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
+ WARN_ONCE(!rate->stbc && !rate->bfer && num_of_ant != 1,
+ "stbc %d bfer %d",
+ rate->stbc, rate->bfer);
} else if (nss == 2) {
rate->type = LQ_HT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2);
@@ -829,7 +833,9 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,

if (nss == 1) {
rate->type = LQ_VHT_SISO;
- WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
+ WARN_ONCE(!rate->stbc && !rate->bfer && num_of_ant != 1,
+ "stbc %d bfer %d",
+ rate->stbc, rate->bfer);
} else if (nss == 2) {
rate->type = LQ_VHT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2);
@@ -1008,13 +1014,32 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rs_get_lower_rate_in_column(lq_sta, rate);
}

-/* Check if both rates are identical */
+/* Check if both rates are identical
+ * allow_ant_mismatch enables matching a SISO rate on ANT_A or ANT_B
+ * with a rate indicating STBC/BFER and ANT_AB.
+ */
static inline bool rs_rate_equal(struct rs_rate *a,
- struct rs_rate *b)
-{
+ struct rs_rate *b,
+ bool allow_ant_mismatch)
+
+{
+ bool ant_match = (a->ant == b->ant) && (a->stbc == b->stbc) &&
+ (a->bfer == b->bfer);
+
+ if (allow_ant_mismatch) {
+ if (a->stbc || a->bfer) {
+ WARN_ONCE(a->ant != ANT_AB, "stbc %d bfer %d ant %d",
+ a->stbc, a->bfer, a->ant);
+ ant_match |= (b->ant == ANT_A || b->ant == ANT_B);
+ } else if (b->stbc || b->bfer) {
+ WARN_ONCE(b->ant != ANT_AB, "stbc %d bfer %d ant %d",
+ b->stbc, b->bfer, b->ant);
+ ant_match |= (a->ant == ANT_A || a->ant == ANT_B);
+ }
+ }
+
return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi) &&
- (a->ldpc == b->ldpc) && (a->index == b->index) &&
- (a->ant == b->ant);
+ (a->ldpc == b->ldpc) && (a->index == b->index) && ant_match;
}

/* Check if both rates share the same column */
@@ -1023,7 +1048,7 @@ static inline bool rs_rate_column_match(struct rs_rate *a,
{
bool ant_match;

- if (a->stbc)
+ if (a->stbc || a->bfer)
ant_match = (b->ant == ANT_A || b->ant == ANT_B);
else
ant_match = (a->ant == b->ant);
@@ -1061,6 +1086,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta;
+ bool allow_ant_mismatch = mvm->fw->ucode_capa.api[0] &
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS;

/* Treat uninitialized rate scaling data same as non-existing. */
if (!lq_sta) {
@@ -1110,7 +1137,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate);

/* Here we actually compare this rate to the latest LQ command */
- if (!rs_rate_equal(&tx_resp_rate, &lq_rate)) {
+ if (!rs_rate_equal(&tx_resp_rate, &lq_rate, allow_ant_mismatch)) {
IWL_DEBUG_RATE(mvm,
"initial tx resp rate 0x%x does not match 0x%x\n",
tx_resp_hwrate, lq_hwrate);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index dc4ef3d..4cb278f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -170,6 +170,7 @@ struct rs_rate {
bool sgi;
bool ldpc;
bool stbc;
+ bool bfer;
};


--
1.9.1


2015-03-01 19:32:01

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 06/31] iwlwifi: mvm: increase the number of PAPD channel groups to 9

From: Eran Harary <[email protected]>

Newer devices have more PAPD channel groups.

Signed-off-by: Eran Harary <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-phy-db.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
index d4fb5ca..e893c6e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
@@ -72,7 +72,7 @@
#include "iwl-trans.h"

#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */
-#define IWL_NUM_PAPD_CH_GROUPS 7
+#define IWL_NUM_PAPD_CH_GROUPS 9
#define IWL_NUM_TXP_CH_GROUPS 9

struct iwl_phy_db_entry {
--
1.9.1


2015-03-01 19:32:06

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 08/31] iwlwifi: mvm: rs: print single stream params via debugfs

From: Eyal Shapira <[email protected]>

Add this to the info printed when reading rate_scale_table.
Useful for debugging.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 43f807f..6578498 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -3323,6 +3323,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
struct iwl_mvm *mvm;
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
struct rs_rate *rate = &tbl->rate;
+ u32 ss_params;
mvm = lq_sta->pers.drv;
buff = kmalloc(2048, GFP_KERNEL);
if (!buff)
@@ -3369,6 +3370,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->lq.agg_frame_cnt_limit);

desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc);
+ ss_params = le32_to_cpu(lq_sta->lq.ss_params);
+ desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
+ (ss_params & LQ_SS_PARAMS_VALID) ?
+ "VALID," : "INVALID",
+ (ss_params & LQ_SS_BFER_ALLOWED) ?
+ "BFER," : "",
+ (ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
+ "STBC," : "",
+ (ss_params & LQ_SS_FORCE) ?
+ "FORCE" : "");
desc += sprintf(buff+desc,
"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
lq_sta->lq.initial_rate_index[0],
--
1.9.1


2015-03-01 19:32:48

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 30/31] iwlwifi: mvm: add trigger for firmware dump upon low RSSI

Lots of issues can be caught when the RSSI drops. Add the
ability to collect the firmware data at that point.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 3 +++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 8 ++++++++
drivers/net/wireless/iwlwifi/mvm/rx.c | 19 +++++++++++++++++++
3 files changed, 30 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 95bef17..37b38a5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -248,6 +248,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* command response or a notification.
* @FW_DB_TRIGGER_RESERVED: reserved
* @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold.
+ * @FW_DBG_TRIGGER_RSSI: trigger log collection when the rssi of the beacon
+ * goes below a threshold.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -258,6 +260,7 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_FW_NOTIF,
FW_DB_TRIGGER_RESERVED,
FW_DBG_TRIGGER_STATS,
+ FW_DBG_TRIGGER_RSSI,

/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index de0e96d..5ea3818 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -566,6 +566,14 @@ struct iwl_fw_dbg_trigger_stats {
} __packed;

/**
+ * struct iwl_fw_dbg_trigger_low_rssi - trigger for low beacon RSSI
+ * @rssi: RSSI value to trigger at
+ */
+struct iwl_fw_dbg_trigger_low_rssi {
+ __le32 rssi;
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 9b2c537..6177e24 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -345,6 +345,25 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_mvm_sta *mvmsta;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
+
+ if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
+ ieee80211_is_beacon(hdr->frame_control)) {
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
+ bool trig_check;
+ s32 rssi;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw,
+ FW_DBG_TRIGGER_RSSI);
+ rssi_trig = (void *)trig->data;
+ rssi = le32_to_cpu(rssi_trig->rssi);
+
+ trig_check =
+ iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif,
+ trig);
+ if (trig_check && rx_status->signal < rssi)
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL, 0);
+ }
}

rcu_read_unlock();
--
1.9.1


2015-03-01 19:32:32

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 20/31] iwlwifi: add new TLV capability flag for BT PLCR

Packet Level Co-Running is a BT Coex feature which is
supported on certain devices only, hence the need for
a TLV flag for it.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++
drivers/net/wireless/iwlwifi/mvm/coex.c | 4 ++--
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 4 ++--
drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 ++++++
4 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 3ec32e8..5970682 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -289,6 +289,7 @@ enum iwl_ucode_tlv_api {
* @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
* @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
* @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
+ * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
*/
enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
@@ -304,6 +305,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
+ IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28),
};

/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 1ec4d55..ce99572 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -611,7 +611,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
bt_cmd->enabled_modules |=
cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);

- if (IWL_MVM_BT_COEX_CORUNNING)
+ if (iwl_mvm_bt_is_plcr_supported(mvm))
bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);

if (IWL_MVM_BT_COEX_MPLUT) {
@@ -1234,7 +1234,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);

- if (!IWL_MVM_BT_COEX_CORUNNING)
+ if (!iwl_mvm_bt_is_plcr_supported(mvm))
return 0;

lockdep_assert_held(&mvm->mutex);
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index adfd1ec..9717ee6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -619,7 +619,7 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
if (IWL_MVM_BT_COEX_SYNC2SCO)
bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);

- if (IWL_MVM_BT_COEX_CORUNNING) {
+ if (iwl_mvm_bt_is_plcr_supported(mvm)) {
bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 |
BT_VALID_CORUN_LUT_40);
bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);
@@ -1207,7 +1207,7 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
};

- if (!IWL_MVM_BT_COEX_CORUNNING)
+ if (!iwl_mvm_bt_is_plcr_supported(mvm))
return 0;

lockdep_assert_held(&mvm->mutex);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 5e383db..f78a006 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -898,6 +898,12 @@ static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
}

+static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm)
+{
+ return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
+ IWL_MVM_BT_COEX_CORUNNING;
+}
+
extern const u8 iwl_mvm_ac_to_tx_fifo[];

struct iwl_rate_info {
--
1.9.1


2015-03-01 19:32:08

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 09/31] iwlwifi: mvm: fix BT coex shared antenna activity check

From: Eyal Shapira <[email protected]>

The shared antenna should be forbidden to use only if there's
high BT activity. Comparing to BT_OFF was effectively causing
us to always forbid using the shared antenna for SISO. This
leads to degraded performance in scenarios where the shared
antenna would have better performance.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index d530ef3..85144d5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -1176,7 +1176,7 @@ bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant)
bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
{
u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
- return ag == BT_OFF;
+ return ag < BT_HIGH_TRAFFIC;
}

bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,
--
1.9.1


2015-03-03 11:52:21

by Kalle Valo

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2015-03-01

"Grumbach, Emmanuel" <[email protected]> writes:

> Hi Kalle,
>
> This is a pull request for 4.1. As usual the details are in the tag.
> Please note that I have another set of 30-ish patch already after this
> pull request. A dependency in mac80211 was solved, so I can now finally
> send lots of work that has been made long ago. But that's for the next
> pull request.
>
> I also have bits for 4.0 but that will wait since your tree isn't ready
> yet for accepting patches for 4.0.
>
> Thanks and let me know if you have issues!
>
>
> The following changes since commit f5af19d10d151c5a2afae3306578f485c244db25:
>
> Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net (2015-02-17 17:41:19 -0800)
>
> are available in the git repository at:
>
>
> https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git tags/iwlwifi-next-for-kalle-2015-03-01

Thanks, pulled.

--
Kalle Valo

2015-03-01 19:32:26

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 17/31] iwlwifi: mvm: support beacon statistics for BSS client

From: Johannes Berg <[email protected]>

Report the average beacon signal and the number of received beacons as
measured by the firmware.

Since the firmware just counts, and doesn't reset the counter at all,
clear it in the firmware whenever we associate. However, accumulate it
over firmware restart.

Since clearing the statistics in the firmware will also clear the ones
for the radio statistics, add those to the accumulator when cleared.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 53 ++++++++++++++++++++++++++++-
drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 +++++-
drivers/net/wireless/iwlwifi/mvm/rx.c | 14 ++++++++
drivers/net/wireless/iwlwifi/mvm/utils.c | 9 +++--
4 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 0f986d7..ce5a5ff 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1322,6 +1322,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,

mutex_lock(&mvm->mutex);

+ /* make sure that beacon statistics don't go backwards with FW reset */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ mvmvif->beacon_stats.accu_num_beacons +=
+ mvmvif->beacon_stats.num_beacons;
+
/* Allocate resources for the MAC context, and add it to the fw */
ret = iwl_mvm_mac_ctxt_init(mvm, vif);
if (ret)
@@ -1815,6 +1820,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,

if (changes & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
+ /* clear statistics to get clean beacon counter */
+ iwl_mvm_request_statistics(mvm, true);
+ memset(&mvmvif->beacon_stats, 0,
+ sizeof(mvmvif->beacon_stats));
+
/* add quota for this interface */
ret = iwl_mvm_update_quotas(mvm, NULL);
if (ret) {
@@ -3597,7 +3607,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
mutex_lock(&mvm->mutex);

if (mvm->ucode_loaded) {
- ret = iwl_mvm_request_statistics(mvm);
+ ret = iwl_mvm_request_statistics(mvm, false);
if (ret)
goto out;
}
@@ -3627,6 +3637,46 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
return ret;
}

+static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ if (!(mvm->fw->ucode_capa.capa[0] &
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+ return;
+
+ /* if beacon filtering isn't on mac80211 does it anyway */
+ if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
+ return;
+
+ if (!vif->bss_conf.assoc)
+ return;
+
+ mutex_lock(&mvm->mutex);
+
+ if (mvmvif->ap_sta_id != mvmsta->sta_id)
+ goto unlock;
+
+ if (iwl_mvm_request_statistics(mvm, false))
+ goto unlock;
+
+ sinfo->rx_beacon = mvmvif->beacon_stats.num_beacons +
+ mvmvif->beacon_stats.accu_num_beacons;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX);
+ if (mvmvif->beacon_stats.avg_signal) {
+ /* firmware only reports a value after RXing a few beacons */
+ sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+ }
+ unlock:
+ mutex_unlock(&mvm->mutex);
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
@@ -3694,4 +3744,5 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.set_default_unicast_key = iwl_mvm_set_default_unicast_key,
#endif
.get_survey = iwl_mvm_mac_get_survey,
+ .sta_statistics = iwl_mvm_mac_sta_statistics,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 90a1ea3..5e383db 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -337,6 +337,9 @@ struct iwl_mvm_vif_bf_data {
* @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the SMPS requests of differents parts of the driver,
* combined on update to yield the overall request to mac80211.
+ * @beacon_stats: beacon statistics, containing the # of received beacons,
+ * # of received beacons accumulated over FW restart, and the current
+ * average signal of beacons retrieved from the firmware
*/
struct iwl_mvm_vif {
u16 id;
@@ -354,6 +357,11 @@ struct iwl_mvm_vif {
bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;

+ struct {
+ u32 num_beacons, accu_num_beacons;
+ u8 avg_signal;
+ } beacon_stats;
+
u32 ap_beacon_time;

enum iwl_tsf_id tsf_id;
@@ -963,7 +971,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-int iwl_mvm_request_statistics(struct iwl_mvm *mvm);
+int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear);
void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);

/* NVM */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 2486931..b86ff66 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -427,6 +427,7 @@ struct iwl_mvm_stat_data {
struct iwl_mvm *mvm;
__le32 mac_id;
__s8 beacon_filter_average_energy;
+ struct mvm_statistics_general_v8 *general;
};

static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
@@ -441,6 +442,17 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
u16 id = le32_to_cpu(data->mac_id);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);

+ /* This doesn't need the MAC ID check since it's not taking the
+ * data copied into the "data" struct, but rather the data from
+ * the notification directly.
+ */
+ if (data->general) {
+ mvmvif->beacon_stats.num_beacons =
+ le32_to_cpu(data->general->beacon_counter[mvmvif->id]);
+ mvmvif->beacon_stats.avg_signal =
+ -data->general->beacon_average_energy[mvmvif->id];
+ }
+
if (mvmvif->id != id)
return;

@@ -525,6 +537,8 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
le64_to_cpu(stats->general.on_time_rf);
mvm->radio_stats.on_time_scan =
le64_to_cpu(stats->general.on_time_scan);
+
+ data.general = &stats->general;
} else {
struct iwl_notif_statistics_v8 *stats = (void *)&pkt->data;

diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 8bdfb8b..a501223 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -643,9 +643,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ieee80211_request_smps(vif, smps_mode);
}

-int iwl_mvm_request_statistics(struct iwl_mvm *mvm)
+int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear)
{
- struct iwl_statistics_cmd scmd = {};
+ struct iwl_statistics_cmd scmd = {
+ .flags = clear ? cpu_to_le32(IWL_STATISTICS_FLG_CLEAR) : 0,
+ };
struct iwl_host_cmd cmd = {
.id = STATISTICS_CMD,
.len[0] = sizeof(scmd),
@@ -661,6 +663,9 @@ int iwl_mvm_request_statistics(struct iwl_mvm *mvm)
iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt);
iwl_free_resp(&cmd);

+ if (clear)
+ iwl_mvm_accu_radio_stats(mvm);
+
return 0;
}

--
1.9.1


2015-03-01 19:32:39

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 24/31] iwlwifi: mvm: add the cause of the firmware dump in the dump

Now that the firmware dump can be triggered by events in
the code and not only the user or an firmware ASSERT, we
need a way to know why the firmware dump was triggered.
Add a section in the dump file for that.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 13 ++++++++
drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +-
drivers/net/wireless/iwlwifi/mvm/fw.c | 35 ++++++++++++++++++---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 40 +++++++++++++++++++++++-
drivers/net/wireless/iwlwifi/mvm/mvm.h | 28 ++++++++++++++---
drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +-
6 files changed, 108 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index fabddd8..b733c58 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -82,6 +82,8 @@
* sections like this in a single file.
* @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers
* @IWL_FW_ERROR_DUMP_MEM: chunk of memory
+ * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump.
+ * Structured as &struct iwl_fw_error_dump_trigger_desc.
*/
enum iwl_fw_error_dump_type {
/* 0 is deprecated */
@@ -94,6 +96,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_TXF = 7,
IWL_FW_ERROR_DUMP_FH_REGS = 8,
IWL_FW_ERROR_DUMP_MEM = 9,
+ IWL_FW_ERROR_DUMP_ERROR_INFO = 10,

IWL_FW_ERROR_DUMP_MAX,
};
@@ -248,4 +251,14 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_MAX,
};

+/**
+ * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition
+ * @type: %enum iwl_fw_dbg_trigger
+ * @data: raw data about what happened
+ */
+struct iwl_fw_error_dump_trigger_desc {
+ __le32 type;
+ u8 data[];
+};
+
#endif /* __fw_error_dump_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index f890d5e..8cbe77d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -985,7 +985,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
if (ret)
return ret;

- iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, 0);
+ iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, 0);

iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);

diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 8d684d5..64e9039 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -479,13 +479,20 @@ exit:
iwl_free_resp(&cmd);
}

-int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
- unsigned int delay)
+int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
+ struct iwl_mvm_dump_desc *desc,
+ unsigned int delay)
{
if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))
return -EBUSY;

- IWL_WARN(mvm, "Collecting data: trigger %d fired.\n", trig);
+ if (WARN_ON(mvm->fw_dump_desc))
+ iwl_mvm_free_fw_dump_desc(mvm);
+
+ IWL_WARN(mvm, "Collecting data: trigger %d fired.\n",
+ le32_to_cpu(desc->trig_desc.type));
+
+ mvm->fw_dump_desc = desc;

/* stop recording */
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
@@ -501,8 +508,25 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
return 0;
}

+int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
+ const char *str, size_t len, unsigned int delay)
+{
+ struct iwl_mvm_dump_desc *desc;
+
+ desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->len = len;
+ desc->trig_desc.type = cpu_to_le32(trig);
+ memcpy(desc->trig_desc.data, str, len);
+
+ return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay);
+}
+
int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
- struct iwl_fw_dbg_trigger_tlv *trigger)
+ struct iwl_fw_dbg_trigger_tlv *trigger,
+ const char *str, size_t len)
{
unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
u16 occurrences = le16_to_cpu(trigger->occurrences);
@@ -511,7 +535,8 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
if (!occurrences)
return 0;

- ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), delay);
+ ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), str,
+ len, delay);
if (ret)
return ret;

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index a5261a4..3b6b9f6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -886,12 +886,23 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
iwl_trans_release_nic_access(mvm->trans, &flags);
}

+void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
+{
+ if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert ||
+ !mvm->fw_dump_desc)
+ return;
+
+ kfree(mvm->fw_dump_desc);
+ mvm->fw_dump_desc = NULL;
+}
+
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
struct iwl_fw_error_dump_mem *dump_mem;
+ struct iwl_fw_error_dump_trigger_desc *dump_trig;
struct iwl_mvm_dump_ptrs *fw_error_dump;
u32 sram_len, sram_ofs;
u32 file_len, fifo_data_len = 0;
@@ -961,6 +972,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
fifo_data_len +
sizeof(*dump_info);

+ if (mvm->fw_dump_desc)
+ file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
+ mvm->fw_dump_desc->len;
+
/* Make room for the SMEM, if it exists */
if (smem_len)
file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
@@ -972,6 +987,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_file = vzalloc(file_len);
if (!dump_file) {
kfree(fw_error_dump);
+ iwl_mvm_free_fw_dump_desc(mvm);
return;
}

@@ -1000,6 +1016,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
iwl_mvm_dump_fifos(mvm, &dump_data);

+ if (mvm->fw_dump_desc) {
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
+ dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
+ mvm->fw_dump_desc->len);
+ dump_trig = (void *)dump_data->data;
+ memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc,
+ sizeof(*dump_trig) + mvm->fw_dump_desc->len);
+
+ /* now we can free this copy */
+ iwl_mvm_free_fw_dump_desc(mvm);
+ dump_data = iwl_fw_error_next_data(dump_data);
+ }
+
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
dump_mem = (void *)dump_data->data;
@@ -1042,14 +1071,22 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
}

+struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = {
+ .trig_desc = {
+ .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
+ },
+};
+
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
/* clear the D3 reconfig, we only need it to avoid dumping a
* firmware coredump on reconfiguration, we shouldn't do that
* on D3->D0 transition
*/
- if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status))
+ if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) {
+ mvm->fw_dump_desc = &iwl_mvm_dump_desc_assert;
iwl_mvm_fw_error_dump(mvm);
+ }

/* cleanup all stale references (scan, roc), but keep the
* ucode_down ref until reconfig is complete
@@ -1261,6 +1298,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
cancel_delayed_work_sync(&mvm->fw_dump_wk);
+ iwl_mvm_free_fw_dump_desc(mvm);

mutex_lock(&mvm->mutex);
__iwl_mvm_mac_stop(mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 4068139..f4ecd1b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -146,6 +146,19 @@ struct iwl_mvm_dump_ptrs {
u32 op_mode_len;
};

+/**
+ * struct iwl_mvm_dump_desc - describes the dump
+ * @len: length of trig_desc->data
+ * @trig_desc: the description of the dump
+ */
+struct iwl_mvm_dump_desc {
+ size_t len;
+ /* must be last */
+ struct iwl_fw_error_dump_trigger_desc trig_desc;
+};
+
+extern struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert;
+
struct iwl_mvm_phy_ctxt {
u16 id;
u16 color;
@@ -706,6 +719,7 @@ struct iwl_mvm {
s8 restart_fw;
u8 fw_dbg_conf;
struct delayed_work fw_dump_wk;
+ struct iwl_mvm_dump_desc *fw_dump_desc;

#ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led;
@@ -1415,9 +1429,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);

int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
- unsigned int delay);
+ const char *str, size_t len, unsigned int delay);
+int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
+ struct iwl_mvm_dump_desc *desc,
+ unsigned int delay);
+void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
- struct iwl_fw_dbg_trigger_tlv *trigger);
+ struct iwl_fw_dbg_trigger_tlv *trigger,
+ const char *str, size_t len);

static inline bool
iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
@@ -1451,7 +1470,8 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
static inline void
iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- enum iwl_fw_dbg_trigger trig)
+ enum iwl_fw_dbg_trigger trig,
+ const char *str, size_t len)
{
struct iwl_fw_dbg_trigger_tlv *trigger;

@@ -1462,7 +1482,7 @@ iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
return;

- iwl_mvm_fw_dbg_collect_trig(mvm, trigger);
+ iwl_mvm_fw_dbg_collect_trig(mvm, trigger, str, len);
}

#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 96a4a15..f1c5751 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -879,7 +879,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
* can't recover this since we're already half suspended.
*/
if (!mvm->restart_fw && fw_error) {
- iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_FW_ASSERT, 0);
+ iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, 0);
} else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
struct iwl_mvm_reprobe *reprobe;
--
1.9.1


2015-03-01 19:32:42

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 26/31] iwlwifi: mvm: add trigger for firmware dump upon channel switch

We fire the trigger when the channel switch starts, but
the delay is configurable. That makes is easier to catch
channel switches that fail.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 2 ++
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +++
2 files changed, 5 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 7d74126..1ee58b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -243,12 +243,14 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts
* @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are
* missed.
+ * @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
FW_DBG_TRIGGER_USER,
FW_DBG_TRIGGER_FW_ASSERT,
FW_DBG_TRIGGER_MISSED_BEACONS,
+ FW_DBG_TRIGGER_CHANNEL_SWITCH,

/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 3b6b9f6..5a5d5c8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -3481,6 +3481,9 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n",
chsw->chandef.center_freq1);

+ iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH,
+ NULL, 0);
+
switch (vif->type) {
case NL80211_IFTYPE_AP:
csa_vif =
--
1.9.1


2015-03-01 19:32:33

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 21/31] iwlwifi: mvm: allow to force the Rx chains from debugfs

This is useful to debug weird antenna problems.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 54 ++++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 +
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 2 +
3 files changed, 57 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 5fe1459..7faad90 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -545,6 +545,57 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
return ret ? count : -EINVAL;
}

+static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct iwl_mvm_phy_ctxt *phy_ctxt;
+ u16 value;
+ int ret;
+
+ ret = kstrtou16(buf, 0, &value);
+ if (ret)
+ return ret;
+
+ mutex_lock(&mvm->mutex);
+ rcu_read_lock();
+
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ /* make sure the channel context is assigned */
+ if (!chanctx_conf) {
+ rcu_read_unlock();
+ mutex_unlock(&mvm->mutex);
+ return -EINVAL;
+ }
+
+ phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
+ rcu_read_unlock();
+
+ mvm->dbgfs_rx_phyinfo = value;
+
+ ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
+ chanctx_conf->rx_chains_static,
+ chanctx_conf->rx_chains_dynamic);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[8];
+
+ snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+}
+
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -560,6 +611,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);

void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
@@ -595,6 +647,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
+ S_IRUSR | S_IWUSR);

if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index f78a006..885d096 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -681,6 +681,7 @@ struct iwl_mvm {

struct iwl_mvm_frame_stats drv_rx_stats;
spinlock_t drv_stats_lock;
+ u16 dbgfs_rx_phyinfo;
#endif

struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 5b43616..1bd10ed 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -175,6 +175,8 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
+ if (unlikely(mvm->dbgfs_rx_phyinfo))
+ cmd->rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo);

cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
}
--
1.9.1


2015-03-01 19:32:37

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 23/31] iwlwifi: mvm: add framework for triggers for fw dump

Most of the time, the issues we want to debug with the
firmware dump mechanism are transient. It is then very
hard to stop the recording on time and get meaningful
data.
In order to solve this, I add here an infrastucture
of triggers. The user will supply a list of triggers
that will start / stop the recording. We have two types
of triggers: start and stop. Start triggers can start a
specific configuration. The stop triggers will be able to
kick the collection of the data with the currently running
configuration. These triggers are given to the driver by
the .ucode file - just like the configuration.

In the next patches, I'll add triggers in the code.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-drv.c | 46 ++++++++++++-
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 18 +++++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 88 ++++++++++++++++--------
drivers/net/wireless/iwlwifi/iwl-fw.h | 53 ++++++--------
drivers/net/wireless/iwlwifi/iwl-trans.h | 4 +-
drivers/net/wireless/iwlwifi/mvm/debugfs.c | 6 +-
drivers/net/wireless/iwlwifi/mvm/fw.c | 37 ++++++++--
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 +-
drivers/net/wireless/iwlwifi/mvm/mvm.h | 59 ++++++++++++++--
drivers/net/wireless/iwlwifi/mvm/ops.c | 7 +-
10 files changed, 243 insertions(+), 80 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index b608114..141331d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -175,6 +175,8 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
kfree(drv->fw.dbg_dest_tlv);
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++)
kfree(drv->fw.dbg_conf_tlv[i]);
+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
+ kfree(drv->fw.dbg_trigger_tlv[i]);

for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
iwl_free_fw_img(drv, drv->fw.img + i);
@@ -293,8 +295,10 @@ struct iwl_firmware_pieces {

/* FW debug data parsed for driver usage */
struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
- struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
- size_t dbg_conf_tlv_len[FW_DBG_MAX];
+ struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
+ size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
+ struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
+ size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
};

/*
@@ -914,6 +918,31 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
pieces->dbg_conf_tlv_len[conf->id] = tlv_len;
break;
}
+ case IWL_UCODE_TLV_FW_DBG_TRIGGER: {
+ struct iwl_fw_dbg_trigger_tlv *trigger =
+ (void *)tlv_data;
+ u32 trigger_id = le32_to_cpu(trigger->id);
+
+ if (trigger_id >= ARRAY_SIZE(drv->fw.dbg_trigger_tlv)) {
+ IWL_ERR(drv,
+ "Skip unknown trigger: %u\n",
+ trigger->id);
+ break;
+ }
+
+ if (pieces->dbg_trigger_tlv[trigger_id]) {
+ IWL_ERR(drv,
+ "Ignore duplicate dbg trigger %u\n",
+ trigger->id);
+ break;
+ }
+
+ IWL_INFO(drv, "Found debug trigger: %u\n", trigger->id);
+
+ pieces->dbg_trigger_tlv[trigger_id] = trigger;
+ pieces->dbg_trigger_tlv_len[trigger_id] = tlv_len;
+ break;
+ }
case IWL_UCODE_TLV_SEC_RT_USNIFFER:
usniffer_images = true;
iwl_store_ucode_sec(pieces, tlv_data,
@@ -1198,6 +1227,19 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
}
}

+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) {
+ if (pieces->dbg_trigger_tlv[i]) {
+ drv->fw.dbg_trigger_tlv_len[i] =
+ pieces->dbg_trigger_tlv_len[i];
+ drv->fw.dbg_trigger_tlv[i] =
+ kmemdup(pieces->dbg_trigger_tlv[i],
+ drv->fw.dbg_trigger_tlv_len[i],
+ GFP_KERNEL);
+ if (!drv->fw.dbg_trigger_tlv[i])
+ goto out_free_fw;
+ }
+ }
+
/* Now that we can no longer fail, copy information */

/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 919a254..fabddd8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -230,4 +230,22 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
return (void *)(data->data + le32_to_cpu(data->len));
}

+/**
+ * enum iwl_fw_dbg_trigger - triggers available
+ *
+ * @FW_DBG_TRIGGER_USER: trigger log collection by user
+ * This should not be defined as a trigger to the driver, but a value the
+ * driver should set to indicate that the trigger was initiated by the
+ * user.
+ * @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts
+ */
+enum iwl_fw_dbg_trigger {
+ FW_DBG_TRIGGER_INVALID = 0,
+ FW_DBG_TRIGGER_USER,
+ FW_DBG_TRIGGER_FW_ASSERT,
+
+ /* must be last */
+ FW_DBG_TRIGGER_MAX,
+};
+
#endif /* __fw_error_dump_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 5970682..d2c4d21 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -66,6 +66,7 @@
#define __iwl_fw_file_h__

#include <linux/netdevice.h>
+#include <linux/nl80211.h>

/* v1/v2 uCode file layout */
struct iwl_ucode_header {
@@ -136,6 +137,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_FW_VERSION = 36,
IWL_UCODE_TLV_FW_DBG_DEST = 38,
IWL_UCODE_TLV_FW_DBG_CONF = 39,
+ IWL_UCODE_TLV_FW_DBG_TRIGGER = 40,
};

struct iwl_ucode_tlv {
@@ -458,44 +460,78 @@ struct iwl_fw_dbg_conf_hcmd {
} __packed;

/**
- * struct iwl_fw_dbg_trigger - a TLV that describes a debug configuration
+ * enum iwl_fw_dbg_trigger_mode - triggers functionalities
*
- * @enabled: is this trigger enabled
- * @reserved:
- * @len: length, in bytes, of the %trigger field
- * @trigger: pointer to a trigger struct
+ * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism
+ * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data
*/
-struct iwl_fw_dbg_trigger {
- u8 enabled;
- u8 reserved;
- u8 len;
- u8 trigger[0];
-} __packed;
+enum iwl_fw_dbg_trigger_mode {
+ IWL_FW_DBG_TRIGGER_START = BIT(0),
+ IWL_FW_DBG_TRIGGER_STOP = BIT(1),
+};

/**
- * enum iwl_fw_dbg_conf - configurations available
- *
- * @FW_DBG_CUSTOM: take this configuration from alive
- * Note that the trigger is NO-OP for this configuration
+ * enum iwl_fw_dbg_trigger_vif_type - define the VIF type for a trigger
+ * @IWL_FW_DBG_CONF_VIF_ANY: any vif type
+ * @IWL_FW_DBG_CONF_VIF_IBSS: IBSS mode
+ * @IWL_FW_DBG_CONF_VIF_STATION: BSS mode
+ * @IWL_FW_DBG_CONF_VIF_AP: AP mode
+ * @IWL_FW_DBG_CONF_VIF_P2P_CLIENT: P2P Client mode
+ * @IWL_FW_DBG_CONF_VIF_P2P_GO: P2P GO mode
+ * @IWL_FW_DBG_CONF_VIF_P2P_DEVICE: P2P device
*/
-enum iwl_fw_dbg_conf {
- FW_DBG_CUSTOM = 0,
-
- /* must be last */
- FW_DBG_MAX,
- FW_DBG_INVALID = 0xff,
+enum iwl_fw_dbg_trigger_vif_type {
+ IWL_FW_DBG_CONF_VIF_ANY = NL80211_IFTYPE_UNSPECIFIED,
+ IWL_FW_DBG_CONF_VIF_IBSS = NL80211_IFTYPE_ADHOC,
+ IWL_FW_DBG_CONF_VIF_STATION = NL80211_IFTYPE_STATION,
+ IWL_FW_DBG_CONF_VIF_AP = NL80211_IFTYPE_AP,
+ IWL_FW_DBG_CONF_VIF_P2P_CLIENT = NL80211_IFTYPE_P2P_CLIENT,
+ IWL_FW_DBG_CONF_VIF_P2P_GO = NL80211_IFTYPE_P2P_GO,
+ IWL_FW_DBG_CONF_VIF_P2P_DEVICE = NL80211_IFTYPE_P2P_DEVICE,
};

/**
- * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration
- *
- * @id: %enum iwl_fw_dbg_conf
+ * struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger
+ * @id: %enum iwl_fw_dbg_trigger
+ * @vif_type: %enum iwl_fw_dbg_trigger_vif_type
+ * @stop_conf_ids: bitmap of configurations this trigger relates to.
+ * if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding
+ * to the currently running configuration is set, the data should be
+ * collected.
+ * @stop_delay: how many milliseconds to wait before collecting the data
+ * after the STOP trigger fires.
+ * @mode: %enum iwl_fw_dbg_trigger_mode - can be stop / start of both
+ * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what
+ * configuration should be applied when the triggers kicks in.
+ * @occurrences: number of occurrences. 0 means the trigger will never fire.
+ */
+struct iwl_fw_dbg_trigger_tlv {
+ __le32 id;
+ __le32 vif_type;
+ __le32 stop_conf_ids;
+ __le32 stop_delay;
+ u8 mode;
+ u8 start_conf_id;
+ __le16 occurrences;
+ __le32 reserved[2];
+
+ u8 data[0];
+} __packed;
+
+#define FW_DBG_START_FROM_ALIVE 0
+#define FW_DBG_CONF_MAX 32
+#define FW_DBG_INVALID 0xff
+
+/**
+ * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
+ * @id: conf id
* @usniffer: should the uSniffer image be used
* @num_of_hcmds: how many HCMDs to send are present here
* @hcmd: a variable length host command to be sent to apply the configuration.
* If there is more than one HCMD to send, they will appear one after the
* other and be sent in the order that they appear in.
- * This parses IWL_UCODE_TLV_FW_DBG_CONF
+ * This parses IWL_UCODE_TLV_FW_DBG_CONF. The user can add up-to
+ * %FW_DBG_CONF_MAX configuration per run.
*/
struct iwl_fw_dbg_conf_tlv {
u8 id;
@@ -503,8 +539,6 @@ struct iwl_fw_dbg_conf_tlv {
u8 reserved;
u8 num_of_hcmds;
struct iwl_fw_dbg_conf_hcmd hcmd;
-
- /* struct iwl_fw_dbg_trigger sits after all variable length hcmds */
} __packed;

#endif /* __iwl_fw_file_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index ffd785c..cf75baf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -68,6 +68,7 @@
#include <net/mac80211.h>

#include "iwl-fw-file.h"
+#include "iwl-fw-error-dump.h"

/**
* enum iwl_ucode_type
@@ -157,6 +158,8 @@ struct iwl_fw_cscheme_list {
* @dbg_dest_tlv: points to the destination TLV for debug
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
* @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries
+ * @dbg_trigger_tlv: array of pointers to triggers TLVs
+ * @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries
* @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
*/
struct iwl_fw {
@@ -186,9 +189,10 @@ struct iwl_fw {
u32 sdio_adma_addr;

struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
- struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
- size_t dbg_conf_tlv_len[FW_DBG_MAX];
-
+ struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
+ size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
+ struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
+ size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
u8 dbg_dest_reg_num;
};

@@ -206,46 +210,29 @@ static inline const char *get_fw_dbg_mode_string(int mode)
}
}

-static inline const struct iwl_fw_dbg_trigger *
-iwl_fw_dbg_conf_get_trigger(const struct iwl_fw *fw, u8 id)
+static inline bool
+iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id)
{
const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id];
- u8 *ptr;
- int i;

if (!conf_tlv)
- return NULL;
-
- ptr = (void *)&conf_tlv->hcmd;
- for (i = 0; i < conf_tlv->num_of_hcmds; i++) {
- ptr += sizeof(conf_tlv->hcmd);
- ptr += le16_to_cpu(conf_tlv->hcmd.len);
- }
-
- return (const struct iwl_fw_dbg_trigger *)ptr;
-}
-
-static inline bool
-iwl_fw_dbg_conf_enabled(const struct iwl_fw *fw, u8 id)
-{
- const struct iwl_fw_dbg_trigger *trigger =
- iwl_fw_dbg_conf_get_trigger(fw, id);
-
- if (!trigger)
return false;

- return trigger->enabled;
+ return conf_tlv->usniffer;
}

-static inline bool
-iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id)
-{
- const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id];
+#define iwl_fw_dbg_trigger_enabled(fw, id) ({ \
+ void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)]; \
+ unlikely(__dbg_trigger); \
+})

- if (!conf_tlv)
- return false;
+static inline struct iwl_fw_dbg_trigger_tlv*
+iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, u8 id)
+{
+ if (WARN_ON(id >= ARRAY_SIZE(fw->dbg_trigger_tlv)))
+ return NULL;

- return conf_tlv->usniffer;
+ return fw->dbg_trigger_tlv[id];
}

#endif /* __iwl_fw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index a96bd8d..542a681 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -595,6 +595,7 @@ enum iwl_d0i3_mode {
* @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
* @dbg_dest_tlv: points to the destination TLV for debug
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
+ * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug
* @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
*/
struct iwl_trans {
@@ -628,7 +629,8 @@ struct iwl_trans {
u64 dflt_pwr_limit;

const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
- const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
+ const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
+ struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
u8 dbg_dest_reg_num;

enum iwl_d0i3_mode d0i3_mode;
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 82c09d8..f890d5e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -942,7 +942,7 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
- enum iwl_fw_dbg_conf conf;
+ int conf;
char buf[8];
const size_t bufsz = sizeof(buf);
int pos = 0;
@@ -966,7 +966,7 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
if (ret)
return ret;

- if (WARN_ON(conf_id >= FW_DBG_MAX))
+ if (WARN_ON(conf_id >= FW_DBG_CONF_MAX))
return -EINVAL;

mutex_lock(&mvm->mutex);
@@ -985,7 +985,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
if (ret)
return ret;

- iwl_mvm_fw_dbg_collect(mvm);
+ iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, 0);

iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);

diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 7426bb0..8d684d5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -217,8 +217,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
struct iwl_sf_region st_fwrd_space;

if (ucode_type == IWL_UCODE_REGULAR &&
- iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_CUSTOM) &&
- iwl_fw_dbg_conf_enabled(mvm->fw, FW_DBG_CUSTOM))
+ iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE))
fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER);
else
fw = iwl_get_ucode_image(mvm, ucode_type);
@@ -480,8 +479,14 @@ exit:
iwl_free_resp(&cmd);
}

-void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
+ unsigned int delay)
{
+ if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))
+ return -EBUSY;
+
+ IWL_WARN(mvm, "Collecting data: trigger %d fired.\n", trig);
+
/* stop recording */
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
@@ -491,10 +496,30 @@ void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
udelay(100);
}

- schedule_work(&mvm->fw_error_dump_wk);
+ queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay);
+
+ return 0;
+}
+
+int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
+ struct iwl_fw_dbg_trigger_tlv *trigger)
+{
+ unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
+ u16 occurrences = le16_to_cpu(trigger->occurrences);
+ int ret;
+
+ if (!occurrences)
+ return 0;
+
+ ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), delay);
+ if (ret)
+ return ret;
+
+ trigger->occurrences = cpu_to_le16(occurrences - 1);
+ return 0;
}

-int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
{
u8 *ptr;
int ret;
@@ -613,7 +638,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");

mvm->fw_dbg_conf = FW_DBG_INVALID;
- iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM);
+ iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_START_FROM_ALIVE);

ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index ce5a5ff..a5261a4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1038,6 +1038,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)

dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
+
+ clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
}

static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
@@ -1088,6 +1090,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)

mvm->vif_count = 0;
mvm->rx_ba_sessions = 0;
+ mvm->fw_dbg_conf = FW_DBG_INVALID;

/* keep statistics ticking */
iwl_mvm_accu_radio_stats(mvm);
@@ -1257,7 +1260,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)

flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
- flush_work(&mvm->fw_error_dump_wk);
+ cancel_delayed_work_sync(&mvm->fw_dump_wk);

mutex_lock(&mvm->mutex);
__iwl_mvm_mac_stop(mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 885d096..4068139 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -75,6 +75,7 @@
#include "iwl-trans.h"
#include "iwl-notif-wait.h"
#include "iwl-eeprom-parse.h"
+#include "iwl-fw-file.h"
#include "sta.h"
#include "fw-api.h"
#include "constants.h"
@@ -703,8 +704,8 @@ struct iwl_mvm {

/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
- struct work_struct fw_error_dump_wk;
- enum iwl_fw_dbg_conf fw_dbg_conf;
+ u8 fw_dbg_conf;
+ struct delayed_work fw_dump_wk;

#ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led;
@@ -840,6 +841,7 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_IN_D0I3,
IWL_MVM_STATUS_ROC_AUX_RUNNING,
IWL_MVM_STATUS_D3_RECONFIG,
+ IWL_MVM_STATUS_DUMPING_FW_LOG,
};

static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
@@ -1411,7 +1413,56 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);

-int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id);
-void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm);
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);
+int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
+ unsigned int delay);
+int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
+ struct iwl_fw_dbg_trigger_tlv *trigger);
+
+static inline bool
+iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
+ struct ieee80211_vif *vif)
+{
+ u32 trig_vif = le32_to_cpu(trig->vif_type);
+
+ return trig_vif == IWL_FW_DBG_CONF_VIF_ANY || vif->type == trig_vif;
+}
+
+static inline bool
+iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm,
+ struct iwl_fw_dbg_trigger_tlv *trig)
+{
+ return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) &&
+ (mvm->fw_dbg_conf == FW_DBG_INVALID ||
+ (BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids))));
+}
+
+static inline bool
+iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_fw_dbg_trigger_tlv *trig)
+{
+ if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif))
+ return false;
+
+ return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig);
+}
+
+static inline void
+iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ enum iwl_fw_dbg_trigger trig)
+{
+ struct iwl_fw_dbg_trigger_tlv *trigger;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, trig))
+ return;
+
+ trigger = iwl_fw_dbg_get_trigger(mvm->fw, trig);
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trigger);
+}

#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 1f64d23..96a4a15 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -455,7 +455,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
- INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
+ INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk);
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);

spin_lock_init(&mvm->d0i3_tx_lock);
@@ -503,6 +503,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
sizeof(trans->dbg_conf_tlv));
+ trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv;

/* set up notification wait support */
iwl_notification_wait_init(&mvm->notif_wait);
@@ -826,7 +827,7 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
{
struct iwl_mvm *mvm =
- container_of(work, struct iwl_mvm, fw_error_dump_wk);
+ container_of(work, struct iwl_mvm, fw_dump_wk.work);

if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT))
return;
@@ -878,7 +879,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
* can't recover this since we're already half suspended.
*/
if (!mvm->restart_fw && fw_error) {
- schedule_work(&mvm->fw_error_dump_wk);
+ iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_FW_ASSERT, 0);
} else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
struct iwl_mvm_reprobe *reprobe;
--
1.9.1


2015-03-01 19:32:23

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 16/31] iwlwifi: mvm: don't write to DBGC_OUT_CTRL when stopping the recording

From: Eran Harary <[email protected]>

Due to HW bug in the DBGC when driver want to stop the dbg recording it
should wait 100us before collecting the data instead of write 0 to
DBGC_OUT_CTRL.

Signed-off-by: Eran Harary <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/fw.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index ca38e98..ab81124 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -458,7 +458,8 @@ void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
} else {
iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
- iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+ /* wait before we collect the data till the DBGC stop */
+ udelay(100);
}

schedule_work(&mvm->fw_error_dump_wk);
--
1.9.1