2016-03-09 17:45:57

by Grumbach, Emmanuel

[permalink] [raw]
Subject: pull request: iwlwifi-next 2016-03-09

Hi Kalle,

this is the very last pull request for 4.6. I hope it is not too late.
Most of it are fixes for code that is already in
wireless-drivers.next.git. There are a few other patches as well.
Let me know if you have issues!
Thank you.

The following changes since commit 53f09e742b0fdf14a2a2bfd2062ee96c9b3eedf0:

Merge branch 'fixes' into next (2016-03-02 09:35:38 +0200)

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-2016-03-09

for you to fetch changes up to 0831fcd67fc5bddd360bca51a3892bbd33048dbb:

iwlwifi: mvm: update GSCAN capabilities (2016-03-09 16:55:39 +0200)

----------------------------------------------------------------
* update GSCAN capabilities (Ayala)
* fix AES-CMAC in AP mode (Johannes)
* adapt prints to new firmware API
* rx path improvements (Sara and Gregory)
* fixes for the thermal / cooling device code (Chaya Rachel)
* fixes for GO uAPSD handling
* more code for the 9000 device family (Sara)
* infrastructure work for firmware notification (Chaya Rachel)
* improve association reliablity (Sara)
* runtime PM fixes
* fixes for ROC (HS2.0)

----------------------------------------------------------------
Ayala Beker (1):
iwlwifi: mvm: update GSCAN capabilities

Chaya Rachel Ivgi (4):
iwlwifi: mvm: fix unregistration of thermal in some error flows
iwlwifi: mvm: add ctdp operations to debugfs
iwlwifi: mvm: add support for async rx handler without hold the mutex
iwlwifi: mvm: return the cooling state index instead of the budget

Emmanuel Grumbach (4):
iwlwifi: mvm: avoid panics with thermal device usage
iwlwifi: mvm: don't let NDPs mess the packet tracking
iwlwifi: mvm: remove RRM advertisement
iwlwifi: mvm: adapt the firmware assert log to new firmware

Gregory Greenman (1):
iwlwifi: pcie: avoid restocks inside rx loop if not emergency

Johannes Berg (1):
iwlwifi: mvm: don't try to offload AES-CMAC in AP/IBSS modes

Luca Coelho (1):
iwlwifi: pcie: forbid RTPM on device removal

Matti Gottlieb (1):
iwlwifi: mvm: ROC: cleanup time event info on FW failure

Sara Sharon (8):
iwlwifi: pcie: refactor RXBs reclaiming code
iwlwifi: pcie: set RB chunk size back to 64
iwlwifi: refactor the code that reads the MAC address from the NVM
iwlwifi: mvm: set the correct amsdu enum values
iwlwifi: mvm: extend time event duration
iwlwifi: mvm: turn off AMSDU bit in QoS control for de-aggregated AMSDUs
iwlwifi: pcie: fine tune number of rxbs
iwlwifi: add support for getting HW address from CSR

drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 ++--
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +-
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +
drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 +++++
drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 27 ++++++------
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 38 ++++++++++-------
drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 9 ++--
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 11 +++++
drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 13 ++++++
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 146 ++++++++++++++++++++++++++++++++++++++++------------------------
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 +--
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 42 +++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 5 +--
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++----
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +--
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 11 +----
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 120 +++++++++++++++++++++++++++++++++--------------------
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 12 ++++++
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 15 ++-----
drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 175 ++++++++++++++++++++++++++++++++++++++++++-----------------------------------
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 +++++++++++--
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 28 ++++++-------
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 28 +++++++++++++
drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 148 ++++++++++++++++++++++++++++++++---------------------------------
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ---
27 files changed, 563 insertions(+), 351 deletions(-)



2016-03-09 17:46:37

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 21/21] iwlwifi: mvm: update GSCAN capabilities

From: Ayala Beker <[email protected]>

Gscan capabilities were updated with new capabilities supported
by the device. While at it, simplify the firmware support
conditional and move both conditions into the WARN() to make it
easier to undertand and use the unlikely() for both.

Signed-off-by: Ayala Beker <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 38 +++++++++++++++---------
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 11 +++++++
drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 13 ++++++++
3 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 184c0fe..f899666 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland 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
@@ -33,6 +34,7 @@
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -374,15 +376,12 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
return 0;
}

-static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data,
- const u32 len)
+static void iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data,
+ const u32 len)
{
struct iwl_fw_gscan_capabilities *fw_capa = (void *)data;
struct iwl_gscan_capabilities *capa = &fw->gscan_capa;

- if (len < sizeof(*fw_capa))
- return -EINVAL;
-
capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size);
capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets);
capa->max_ap_cache_per_scan =
@@ -395,7 +394,15 @@ static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data,
le32_to_cpu(fw_capa->max_significant_change_aps);
capa->max_bssid_history_entries =
le32_to_cpu(fw_capa->max_bssid_history_entries);
- return 0;
+ capa->max_hotlist_ssids = le32_to_cpu(fw_capa->max_hotlist_ssids);
+ capa->max_number_epno_networks =
+ le32_to_cpu(fw_capa->max_number_epno_networks);
+ capa->max_number_epno_networks_by_ssid =
+ le32_to_cpu(fw_capa->max_number_epno_networks_by_ssid);
+ capa->max_number_of_white_listed_ssid =
+ le32_to_cpu(fw_capa->max_number_of_white_listed_ssid);
+ capa->max_number_of_black_listed_ssid =
+ le32_to_cpu(fw_capa->max_number_of_black_listed_ssid);
}

/*
@@ -1023,8 +1030,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_FW_GSCAN_CAPA:
- if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len))
- goto invalid_tlv_len;
+ /*
+ * Don't return an error in case of a shorter tlv_len
+ * to enable loading of FW that has an old format
+ * of GSCAN capabilities TLV.
+ */
+ if (tlv_len < sizeof(struct iwl_fw_gscan_capabilities))
+ break;
+
+ iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len);
gscan_capa = true;
break;
default:
@@ -1046,12 +1060,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return -EINVAL;
}

- /*
- * If ucode advertises that it supports GSCAN but GSCAN
- * capabilities TLV is not present, warn and continue without GSCAN.
- */
- if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) &&
- WARN(!gscan_capa,
+ if (WARN(fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) &&
+ !gscan_capa,
"GSCAN is supported but capabilities TLV is unavailable\n"))
__clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT,
capa->_capa);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
index 5f69bf5..15ec4e2 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
@@ -809,6 +809,12 @@ struct iwl_fw_dbg_conf_tlv {
* change APs.
* @max_bssid_history_entries: number of BSSID/RSSI entries that the device can
* hold.
+ * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs.
+ * @max_number_epno_networks: max number of epno entries.
+ * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is
+ * specified.
+ * @max_number_of_white_listed_ssid: max number of white listed SSIDs.
+ * @max_number_of_black_listed_ssid: max number of black listed SSIDs.
*/
struct iwl_fw_gscan_capabilities {
__le32 max_scan_cache_size;
@@ -819,6 +825,11 @@ struct iwl_fw_gscan_capabilities {
__le32 max_hotlist_aps;
__le32 max_significant_change_aps;
__le32 max_bssid_history_entries;
+ __le32 max_hotlist_ssids;
+ __le32 max_number_epno_networks;
+ __le32 max_number_epno_networks_by_ssid;
+ __le32 max_number_of_white_listed_ssid;
+ __le32 max_number_of_black_listed_ssid;
} __packed;

#endif /* __iwl_fw_file_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
index 85d6d6d..2942571 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
@@ -7,6 +7,7 @@
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland 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
@@ -33,6 +34,7 @@
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,6 +207,12 @@ struct iwl_fw_cscheme_list {
* change APs.
* @max_bssid_history_entries: number of BSSID/RSSI entries that the device can
* hold.
+ * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs.
+ * @max_number_epno_networks: max number of epno entries.
+ * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is
+ * specified.
+ * @max_number_of_white_listed_ssid: max number of white listed SSIDs.
+ * @max_number_of_black_listed_ssid: max number of black listed SSIDs.
*/
struct iwl_gscan_capabilities {
u32 max_scan_cache_size;
@@ -215,6 +223,11 @@ struct iwl_gscan_capabilities {
u32 max_hotlist_aps;
u32 max_significant_change_aps;
u32 max_bssid_history_entries;
+ u32 max_hotlist_ssids;
+ u32 max_number_epno_networks;
+ u32 max_number_epno_networks_by_ssid;
+ u32 max_number_of_white_listed_ssid;
+ u32 max_number_of_black_listed_ssid;
};

/**
--
2.5.0


2016-03-09 17:46:26

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 16/21] iwlwifi: mvm: remove RRM advertisement

mac80211 advertises this feature for all its drivers.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 3590835..39b9c38 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -610,8 +610,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;

- wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_RRM);
-
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;

#ifdef CONFIG_PM_SLEEP
--
2.5.0


2016-03-09 19:12:35

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2016-03-09

On Wed, Mar 9, 2016 at 8:14 PM, Emmanuel Grumbach <[email protected]> wrote:
> Hi Kalle,
>
> On Wed, Mar 9, 2016 at 7:43 PM, Grumbach, Emmanuel
> <[email protected]> wrote:
>> Hi Kalle,
>>
>> this is the very last pull request for 4.6. I hope it is not too late.
>> Most of it are fixes for code that is already in
>> wireless-drivers.next.git. There are a few other patches as well.
>> Let me know if you have issues!
>> Thank you.
>
> As you saw, we have a compilation issue when THERMAL is not enabled.
> I'll respin.

Done: new tag is iwlwifi-next-for-kalle-2016-03-09_2.

$ git diff iwlwifi-next-for-kalle-2016-03-09 iwlwifi-next-for-kalle-2016-03-09_2
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index de3589a..f1f2825 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -557,7 +557,9 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32
op, u32 state)

switch (op) {
case CTDP_CMD_OPERATION_START:
+#ifdef CONFIG_THERMAL
mvm->cooling_dev.cur_state = state;
+#endif /* CONFIG_THERMAL */
break;
case CTDP_CMD_OPERATION_REPORT:
IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);


>
>>
>> The following changes since commit 53f09e742b0fdf14a2a2bfd2062ee96c9b3eedf0:
>>
>> Merge branch 'fixes' into next (2016-03-02 09:35:38 +0200)
>>
>> 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-2016-03-09
>>
>> for you to fetch changes up to 0831fcd67fc5bddd360bca51a3892bbd33048dbb:
>>
>> iwlwifi: mvm: update GSCAN capabilities (2016-03-09 16:55:39 +0200)
>>
>> ----------------------------------------------------------------
>> * update GSCAN capabilities (Ayala)
>> * fix AES-CMAC in AP mode (Johannes)
>> * adapt prints to new firmware API
>> * rx path improvements (Sara and Gregory)
>> * fixes for the thermal / cooling device code (Chaya Rachel)
>> * fixes for GO uAPSD handling
>> * more code for the 9000 device family (Sara)
>> * infrastructure work for firmware notification (Chaya Rachel)
>> * improve association reliablity (Sara)
>> * runtime PM fixes
>> * fixes for ROC (HS2.0)
>>
>> ----------------------------------------------------------------
>> Ayala Beker (1):
>> iwlwifi: mvm: update GSCAN capabilities
>>
>> Chaya Rachel Ivgi (4):
>> iwlwifi: mvm: fix unregistration of thermal in some error flows
>> iwlwifi: mvm: add ctdp operations to debugfs
>> iwlwifi: mvm: add support for async rx handler without hold the mutex
>> iwlwifi: mvm: return the cooling state index instead of the budget
>>
>> Emmanuel Grumbach (4):
>> iwlwifi: mvm: avoid panics with thermal device usage
>> iwlwifi: mvm: don't let NDPs mess the packet tracking
>> iwlwifi: mvm: remove RRM advertisement
>> iwlwifi: mvm: adapt the firmware assert log to new firmware
>>
>> Gregory Greenman (1):
>> iwlwifi: pcie: avoid restocks inside rx loop if not emergency
>>
>> Johannes Berg (1):
>> iwlwifi: mvm: don't try to offload AES-CMAC in AP/IBSS modes
>>
>> Luca Coelho (1):
>> iwlwifi: pcie: forbid RTPM on device removal
>>
>> Matti Gottlieb (1):
>> iwlwifi: mvm: ROC: cleanup time event info on FW failure
>>
>> Sara Sharon (8):
>> iwlwifi: pcie: refactor RXBs reclaiming code
>> iwlwifi: pcie: set RB chunk size back to 64
>> iwlwifi: refactor the code that reads the MAC address from the NVM
>> iwlwifi: mvm: set the correct amsdu enum values
>> iwlwifi: mvm: extend time event duration
>> iwlwifi: mvm: turn off AMSDU bit in QoS control for de-aggregated AMSDUs
>> iwlwifi: pcie: fine tune number of rxbs
>> iwlwifi: add support for getting HW address from CSR
>>
>> drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 ++--
>> drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +-
>> drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +
>> drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 +++++
>> drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 27 ++++++------
>> drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 38 ++++++++++-------
>> drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 9 ++--
>> drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 11 +++++
>> drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 13 ++++++
>> drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 146 ++++++++++++++++++++++++++++++++++++++++------------------------
>> drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 +--
>> drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 42 +++++++++++++++++++
>> drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 5 +--
>> drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++----
>> drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +--
>> drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 11 +----
>> drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 120 +++++++++++++++++++++++++++++++++--------------------
>> drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 12 ++++++
>> drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 15 ++-----
>> drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 2 +-
>> drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 175 ++++++++++++++++++++++++++++++++++++++++++-----------------------------------
>> drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 +++++++++++--
>> drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 28 ++++++-------
>> drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 28 +++++++++++++
>> drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
>> drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 148 ++++++++++++++++++++++++++++++++---------------------------------
>> drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ---
>> 27 files changed, 563 insertions(+), 351 deletions(-)
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html

2016-03-10 12:55:40

by Kalle Valo

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2016-03-09

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

> this is the very last pull request for 4.6. I hope it is not too late.
> Most of it are fixes for code that is already in
> wireless-drivers.next.git. There are a few other patches as well.
> Let me know if you have issues!
> Thank you.
>
> The following changes since commit 53f09e742b0fdf14a2a2bfd2062ee96c9b3eedf0:
>
> Merge branch 'fixes' into next (2016-03-02 09:35:38 +0200)
>
> 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-2016-03-09

Pulled iwlwifi-next-for-kalle-2016-03-09_2, thanks. I'm not sure if this
makes it to 4.6 but I'm going to try.

--
Kalle Valo

2016-03-09 17:46:14

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 10/21] iwlwifi: mvm: turn off AMSDU bit in QoS control for de-aggregated AMSDUs

From: Sara Sharon <[email protected]>

Our hardware de-aggregates AMSDUs but copies the mac header
as it to the de-aggregated MPDUs. We need to turn off the AMSDU
bit in the QoS control ourselves.

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

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index cd6ca37..9a54f2d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -519,6 +519,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rcu_read_unlock();
return;
}
+
+ /*
+ * Our hardware de-aggregates AMSDUs but copies the mac header
+ * as it to the de-aggregated MPDUs. We need to turn off the
+ * AMSDU bit in the QoS control ourselves.
+ */
+ if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) &&
+ !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+ *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ }
}

/*
--
2.5.0


2016-03-09 17:45:55

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 01/21] iwlwifi: pcie: forbid RTPM on device removal

From: Luca Coelho <[email protected]>

The pci driver keeps any unbound device in active state and forbids
runtime PM. When our driver gets probed, we take control of the
state. When the device is released (i.e. during unbind or module
removal), we should return the state to what it was before. To do so,
we need to forbid RTPM in the driver remove op.

Additionally, remove an unnecessary pm_runtime_disable() call, move
the initial ref_count setting to a better place and add some comments
explaining what is going on.

Signed-off-by: Luca Coelho <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 28 +++++++++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ------
2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index d33b6ba..05b9685 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -631,13 +631,31 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

/* if RTPM is in use, enable it in our device */
if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
+ /* We explicitly set the device to active here to
+ * clear contingent errors.
+ */
pm_runtime_set_active(&pdev->dev);
+
pm_runtime_set_autosuspend_delay(&pdev->dev,
iwlwifi_mod_params.d0i3_entry_delay);
pm_runtime_use_autosuspend(&pdev->dev);
+
+ /* We are not supposed to call pm_runtime_allow() by
+ * ourselves, but let userspace enable runtime PM via
+ * sysfs. However, since we don't enable this from
+ * userspace yet, we need to allow/forbid() ourselves.
+ */
pm_runtime_allow(&pdev->dev);
}

+ /* The PCI device starts with a reference taken and we are
+ * supposed to release it here. But to simplify the
+ * interaction with the opmode, we don't do it now, but let
+ * the opmode release it when it's ready. To account for this
+ * reference, we start with ref_count set to 1.
+ */
+ trans_pcie->ref_count = 1;
+
return 0;

out_free_drv:
@@ -652,7 +670,17 @@ static void iwl_pci_remove(struct pci_dev *pdev)
struct iwl_trans *trans = pci_get_drvdata(pdev);
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);

+ /* if RTPM was in use, restore it to the state before probe */
+ if (trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
+ /* We should not call forbid here, but we do for now.
+ * Check the comment to pm_runtime_allow() in
+ * iwl_pci_probe().
+ */
+ pm_runtime_forbid(trans->dev);
+ }
+
iwl_drv_stop(trans_pcie->drv);
+
iwl_trans_pcie_free(trans);
}

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index e67957d..eb39c7e 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1646,9 +1646,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans->command_groups = trans_cfg->command_groups;
trans->command_groups_size = trans_cfg->command_groups_size;

- /* init ref_count to 1 (should be cleared when ucode is loaded) */
- trans_pcie->ref_count = 1;
-
/* Initialize NAPI here - it should be before registering to mac80211
* in the opmode but after the HW struct is allocated.
* As this function may be called again in some corner cases don't
@@ -1663,9 +1660,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int i;

- /* TODO: check if this is really needed */
- pm_runtime_disable(trans->dev);
-
iwl_pcie_synchronize_irqs(trans);

iwl_pcie_tx_free(trans);
--
2.5.0


2016-03-09 17:46:05

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 06/21] iwlwifi: mvm: fix unregistration of thermal in some error flows

From: Chaya Rachel Ivgi <[email protected]>

The call to iwl_mvm_thermal_initialize() was too early in the
function.
Unregister will be performed when goto out_unregister is called,
but as the code was - out_free may be called and leave without
unregistering from thermal.

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

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 699a808..4322e8e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -611,9 +611,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
mvm->cfg->name, mvm->trans->hw_rev);

- min_backoff = calc_min_backoff(trans, cfg);
- iwl_mvm_thermal_initialize(mvm, min_backoff);
-
if (iwlwifi_mod_params.nvm_file)
mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
else
@@ -666,6 +663,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (err)
goto out_free;

+ min_backoff = calc_min_backoff(trans, cfg);
+ iwl_mvm_thermal_initialize(mvm, min_backoff);
+
err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir);
if (err)
goto out_unregister;
--
2.5.0


2016-03-09 17:46:18

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 12/21] iwlwifi: mvm: add support for async rx handler without hold the mutex

From: Chaya Rachel Ivgi <[email protected]>

When running async rx handler the framework holds the mvm->mutex
before starting the async handler, that might cause a deadlock in case
the handler calls to ops that lock the mutex as well.
Add support for running async rx handler without hold the mutex before
activating the handler.

Signed-off-by: Chaya Rachel Ivgi <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 114 +++++++++++++++++----------
1 file changed, 73 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 4322e8e..5e8ab79 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -205,79 +205,107 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
}

+/**
+ * enum iwl_rx_handler_context context for Rx handler
+ * @RX_HANDLER_SYNC : this means that it will be called in the Rx path
+ * which can't acquire mvm->mutex.
+ * @RX_HANDLER_ASYNC_LOCKED : If the handler needs to hold mvm->mutex
+ * (and only in this case!), it should be set as ASYNC. In that case,
+ * it will be called from a worker with mvm->mutex held.
+ * @RX_HANDLER_ASYNC_UNLOCKED : in case the handler needs to lock the
+ * mutex itself, it will be called from a worker without mvm->mutex held.
+ */
+enum iwl_rx_handler_context {
+ RX_HANDLER_SYNC,
+ RX_HANDLER_ASYNC_LOCKED,
+ RX_HANDLER_ASYNC_UNLOCKED,
+};
+
+/**
+ * struct iwl_rx_handlers handler for FW notification
+ * @cmd_id: command id
+ * @context: see &iwl_rx_handler_context
+ * @fn: the function is called when notification is received
+ */
struct iwl_rx_handlers {
u16 cmd_id;
- bool async;
+ enum iwl_rx_handler_context context;
void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
};

-#define RX_HANDLER(_cmd_id, _fn, _async) \
- { .cmd_id = _cmd_id , .fn = _fn , .async = _async }
-#define RX_HANDLER_GRP(_grp, _cmd, _fn, _async) \
- { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .async = _async }
+#define RX_HANDLER(_cmd_id, _fn, _context) \
+ { .cmd_id = _cmd_id, .fn = _fn, .context = _context }
+#define RX_HANDLER_GRP(_grp, _cmd, _fn, _context) \
+ { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .context = _context }

/*
* Handlers for fw notifications
* Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME
* This list should be in order of frequency for performance purposes.
*
- * The handler can be SYNC - this means that it will be called in the Rx path
- * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and
- * only in this case!), it should be set as ASYNC. In that case, it will be
- * called from a worker with mvm->mutex held.
+ * The handler can be one from three contexts, see &iwl_rx_handler_context
*/
static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
- RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
- RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
-
- RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
- RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, true),
- RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true),
+ RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, RX_HANDLER_SYNC),
+ RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, RX_HANDLER_SYNC),
+
+ RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif,
+ RX_HANDLER_ASYNC_LOCKED),
+ RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif,
+ RX_HANDLER_ASYNC_LOCKED),
+ RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics,
+ RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION,
- iwl_mvm_rx_ant_coupling_notif, true),
+ iwl_mvm_rx_ant_coupling_notif, RX_HANDLER_ASYNC_LOCKED),

RX_HANDLER(BA_WINDOW_STATUS_NOTIFICATION_ID,
- iwl_mvm_window_status_notif, false),
+ iwl_mvm_window_status_notif, RX_HANDLER_SYNC),

- RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
- RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true),
+ RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif,
+ RX_HANDLER_SYNC),
+ RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc,
+ RX_HANDLER_ASYNC_LOCKED),

- RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
+ RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, RX_HANDLER_SYNC),

RX_HANDLER(SCAN_ITERATION_COMPLETE,
- iwl_mvm_rx_lmac_scan_iter_complete_notif, false),
+ iwl_mvm_rx_lmac_scan_iter_complete_notif, RX_HANDLER_SYNC),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
- iwl_mvm_rx_lmac_scan_complete_notif, true),
+ iwl_mvm_rx_lmac_scan_complete_notif,
+ RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_match_found,
- false),
+ RX_HANDLER_SYNC),
RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
- true),
+ RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER(SCAN_ITERATION_COMPLETE_UMAC,
- iwl_mvm_rx_umac_scan_iter_complete_notif, false),
+ iwl_mvm_rx_umac_scan_iter_complete_notif, RX_HANDLER_SYNC),

- RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
+ RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif,
+ RX_HANDLER_SYNC),

RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif,
- false),
+ RX_HANDLER_SYNC),

- RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
+ RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, RX_HANDLER_SYNC),
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
- iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
- RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),
+ iwl_mvm_power_uapsd_misbehaving_ap_notif, RX_HANDLER_SYNC),
+ RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif,
+ RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER_GRP(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE,
- iwl_mvm_temp_notif, true),
+ iwl_mvm_temp_notif, RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER_GRP(PHY_OPS_GROUP, CT_KILL_NOTIFICATION,
- iwl_mvm_ct_kill_notif, false),
+ iwl_mvm_ct_kill_notif, RX_HANDLER_SYNC),

RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
- true),
- RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false),
- RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true),
+ RX_HANDLER_ASYNC_LOCKED),
+ RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif,
+ RX_HANDLER_SYNC),
+ RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler,
+ RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF,
- iwl_mvm_rx_stored_beacon_notif, false),
+ iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC),
RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF,
- iwl_mvm_mu_mimo_grp_notif, false),
-
+ iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC),
};
#undef RX_HANDLER
#undef RX_HANDLER_GRP
@@ -743,6 +771,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
struct iwl_async_handler_entry {
struct list_head list;
struct iwl_rx_cmd_buffer rxb;
+ enum iwl_rx_handler_context context;
void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
};

@@ -769,7 +798,6 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
INIT_LIST_HEAD(&local_list);

/* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */
- mutex_lock(&mvm->mutex);

/*
* Sync with Rx path with a lock. Remove all the entries from this list,
@@ -780,12 +808,15 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
spin_unlock_bh(&mvm->async_handlers_lock);

list_for_each_entry_safe(entry, tmp, &local_list, list) {
+ if (entry->context == RX_HANDLER_ASYNC_LOCKED)
+ mutex_lock(&mvm->mutex);
entry->fn(mvm, &entry->rxb);
iwl_free_rxb(&entry->rxb);
list_del(&entry->list);
+ if (entry->context == RX_HANDLER_ASYNC_LOCKED)
+ mutex_unlock(&mvm->mutex);
kfree(entry);
}
- mutex_unlock(&mvm->mutex);
}

static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
@@ -842,7 +873,7 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm,
if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd))
continue;

- if (!rx_h->async) {
+ if (rx_h->context == RX_HANDLER_SYNC) {
rx_h->fn(mvm, rxb);
return;
}
@@ -856,6 +887,7 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm,
entry->rxb._offset = rxb->_offset;
entry->rxb._rx_page_order = rxb->_rx_page_order;
entry->fn = rx_h->fn;
+ entry->context = rx_h->context;
spin_lock(&mvm->async_handlers_lock);
list_add_tail(&entry->list, &mvm->async_handlers_list);
spin_unlock(&mvm->async_handlers_lock);
--
2.5.0


2016-03-09 17:46:24

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 15/21] iwlwifi: mvm: don't let NDPs mess the packet tracking

We need to track the next packet that we will reclaim in
order to know when the Tx queues are empty. This is useful
when we open or tear down an A-MPDU session which requires
to switch queue.
The next packet being reclaimed is identified by its WiFi
sequence number and this is relevant only when we use QoS.
QoS NDPs do have a TID but have a meaningless sequence
number. The spec mandates the receiver to ignore the
sequence number in this case, allowing the transmitter to
put any sequence number. Our implementation leaves it 0.
When we reclaim a QoS NDP, we can't update the next_relcaim
counter since the sequence number of the QoS NDP itself is
invalid.
We used to update the next_reclaim based on the sequence
number of the QoS NDP which reset it to 1 (0 + 1) and
because of this, we never knew when the queue got empty.
This had to sad consequence to stuck the A-MPDU state
machine in a transient state.
To fix this, don't update next_reclaim when we reclaim
a QoS NDP.

Alesya saw this bug when testing u-APSD. Because the
A-MPDU state machine was stuck in EMPTYING_DELBA, we
updated mac80211 that we still have frames for that
station when it got back to sleep. mac80211 then wrongly
set the TIM bit in the beacon and requested to release
non-existent frames from the A-MPDU queue. This led to
a situation where the client was trying to poll frames
but we had no frames to send.

Reported-by: Alesya Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 271e8da..75870e6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland 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
@@ -963,6 +964,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
struct sk_buff_head skbs;
u8 skb_freed = 0;
u16 next_reclaimed, seq_ctl;
+ bool is_ndp = false;

__skb_queue_head_init(&skbs);

@@ -1016,6 +1018,20 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
seq_ctl = le16_to_cpu(hdr->seq_ctrl);
}

+ if (unlikely(!seq_ctl)) {
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+
+ /*
+ * If it is an NDP, we can't update next_reclaim since
+ * its sequence control is 0. Note that for that same
+ * reason, NDPs are never sent to A-MPDU'able queues
+ * so that we can never have more than one freed frame
+ * for a single Tx resonse (see WARN_ON below).
+ */
+ if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+ is_ndp = true;
+ }
+
/*
* TODO: this is not accurate if we are freeing more than one
* packet.
@@ -1079,9 +1095,16 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
bool send_eosp_ndp = false;

spin_lock_bh(&mvmsta->lock);
- tid_data->next_reclaimed = next_reclaimed;
- IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
- next_reclaimed);
+ if (!is_ndp) {
+ tid_data->next_reclaimed = next_reclaimed;
+ IWL_DEBUG_TX_REPLY(mvm,
+ "Next reclaimed packet:%d\n",
+ next_reclaimed);
+ } else {
+ IWL_DEBUG_TX_REPLY(mvm,
+ "NDP - don't update next_reclaimed\n");
+ }
+
iwl_mvm_check_ratid_empty(mvm, sta, tid);

if (mvmsta->sleep_tx_count) {
--
2.5.0


2016-03-09 17:46:22

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 14/21] iwlwifi: add support for getting HW address from CSR

From: Sara Sharon <[email protected]>

>From 9000 family on, we need to get HW address from host
CSR registers.
OEM can override it by fusing the override registers - read
those first, and if those are 0 - read the OTP registers instead.

In addition - bail out if no valid mac address is present. Make
it shared for all NICs.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +-
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +
drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 +++
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 75 ++++++++++++++++------
4 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index 8e32a57..318b1dc 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -140,7 +140,8 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.thermal_params = &iwl9000_tt_params, \
.apmg_not_supported = true, \
.mq_rx_supported = true, \
- .vht_mu_mimo_supported = true
+ .vht_mu_mimo_supported = true, \
+ .mac_addr_from_csr = true

const struct iwl_cfg iwl9260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9260",
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 4f2b57e..3e4d346 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff {
* @host_interrupt_operation_mode: device needs host interrupt operation
* mode set
* @nvm_hw_section_num: the ID of the HW NVM section
+ * @mac_addr_from_csr: read HW address from CSR registers
* @features: hw features, any combination of feature_whitelist
* @pwr_tx_backoffs: translation table between power limits and backoffs
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
@@ -345,6 +346,7 @@ struct iwl_cfg {
const bool host_interrupt_operation_mode;
bool high_temp;
u8 nvm_hw_section_num;
+ bool mac_addr_from_csr;
bool lp_xtal_workaround;
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
bool no_power_up_nic_in_init;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index a79c4f6..b978f6c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -598,4 +598,14 @@ enum msix_hw_int_causes {
#define MSIX_AUTO_CLEAR_CAUSE 0
#define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)

+/*****************************************************************************
+ * HW address related registers *
+ *****************************************************************************/
+
+#define CSR_ADDR_BASE (0x380)
+#define CSR_MAC_ADDR0_OTP (CSR_ADDR_BASE)
+#define CSR_MAC_ADDR1_OTP (CSR_ADDR_BASE + 4)
+#define CSR_MAC_ADDR0_STRAP (CSR_ADDR_BASE + 8)
+#define CSR_MAC_ADDR1_STRAP (CSR_ADDR_BASE + 0xC)
+
#endif /* !__iwl_csr_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 5e6b90d..93a6895 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -71,6 +71,8 @@
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "iwl-csr.h"

/* NVM offsets (in words) definitions */
enum wkp_nvm_offsets {
@@ -524,6 +526,36 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
}

+static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
+{
+ const u8 *hw_addr;
+
+ hw_addr = (const u8 *)&mac_addr0;
+ dest[0] = hw_addr[3];
+ dest[1] = hw_addr[2];
+ dest[2] = hw_addr[1];
+ dest[3] = hw_addr[0];
+
+ hw_addr = (const u8 *)&mac_addr1;
+ dest[4] = hw_addr[1];
+ dest[5] = hw_addr[0];
+}
+
+static void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
+ struct iwl_nvm_data *data)
+{
+ __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
+ __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
+
+ /* If OEM did not fuse address - get it from OTP */
+ if (!mac_addr0 && !mac_addr1) {
+ mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
+ mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
+ }
+
+ iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
+}
+
static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
@@ -564,21 +596,8 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
WFMP_MAC_ADDR_0));
__le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
WFMP_MAC_ADDR_1));
- /* read the MAC address from HW resisters */
- hw_addr = (const u8 *)&mac_addr0;
- data->hw_addr[0] = hw_addr[3];
- data->hw_addr[1] = hw_addr[2];
- data->hw_addr[2] = hw_addr[1];
- data->hw_addr[3] = hw_addr[0];
-
- hw_addr = (const u8 *)&mac_addr1;
- data->hw_addr[4] = hw_addr[1];
- data->hw_addr[5] = hw_addr[0];
-
- if (!is_valid_ether_addr(data->hw_addr))
- IWL_ERR(trans,
- "mac address (%pM) from hw section is not valid\n",
- data->hw_addr);
+
+ iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);

return;
}
@@ -586,12 +605,14 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
IWL_ERR(trans, "mac address is not found\n");
}

-static void iwl_set_hw_address(struct iwl_trans *trans,
- const struct iwl_cfg *cfg,
- struct iwl_nvm_data *data, const __le16 *nvm_hw,
- const __le16 *mac_override)
+static int iwl_set_hw_address(struct iwl_trans *trans,
+ const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data, const __le16 *nvm_hw,
+ const __le16 *mac_override)
{
- if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (cfg->mac_addr_from_csr) {
+ iwl_set_hw_address_from_csr(trans, data);
+ } else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);

/* The byte order is little endian 16 bit, meaning 214365 */
@@ -605,6 +626,13 @@ static void iwl_set_hw_address(struct iwl_trans *trans,
iwl_set_hw_address_family_8000(trans, cfg, data,
mac_override, nvm_hw);
}
+
+ if (!is_valid_ether_addr(data->hw_addr)) {
+ IWL_ERR(trans, "no valid mac address was found\n");
+ return -EINVAL;
+ }
+
+ return 0;
}

struct iwl_nvm_data *
@@ -680,7 +708,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
ch_section = regulatory;
}

- iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override);
+ /* If no valid mac address was found - bail out */
+ if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) {
+ kfree(data);
+ return NULL;
+ }
+
iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
lar_fw_supported && lar_enabled);
data->calib_version = 255;
--
2.5.0


2016-03-09 17:46:29

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 17/21] iwlwifi: mvm: return the cooling state index instead of the budget

From: Chaya Rachel Ivgi <[email protected]>

iwl_mvm_tcool_get_cur_state is the function that returns the
cooling state index to the sysfs handler. This function returns
mvm->cooling_dev.cur_state but that variable was set to the
budget and not the cooling state index. Fix that.
Add a missing blank line while at it.

Signed-off-by: Chaya Rachel Ivgi <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +-
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 56 ++++++++++++++--------------
2 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index b869db9..9abbc93 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -543,8 +543,8 @@ struct iwl_mvm_thermal_device {
};

/*
- * iwl_mvm_cooling_device
- * @cur_state: current state in milliwatts
+ * struct iwl_mvm_cooling_device
+ * @cur_state: current state
* @cdev: struct thermal cooling device
*/
struct iwl_mvm_cooling_device {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index a396549..de3589a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -510,11 +510,35 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = {
.support_tx_backoff = true,
};

-int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
+/* budget in mWatt */
+static const u32 iwl_mvm_cdev_budgets[] = {
+ 2000, /* cooling state 0 */
+ 1800, /* cooling state 1 */
+ 1600, /* cooling state 2 */
+ 1400, /* cooling state 3 */
+ 1200, /* cooling state 4 */
+ 1000, /* cooling state 5 */
+ 900, /* cooling state 6 */
+ 800, /* cooling state 7 */
+ 700, /* cooling state 8 */
+ 650, /* cooling state 9 */
+ 600, /* cooling state 10 */
+ 550, /* cooling state 11 */
+ 500, /* cooling state 12 */
+ 450, /* cooling state 13 */
+ 400, /* cooling state 14 */
+ 350, /* cooling state 15 */
+ 300, /* cooling state 16 */
+ 250, /* cooling state 17 */
+ 200, /* cooling state 18 */
+ 150, /* cooling state 19 */
+};
+
+int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)
{
struct iwl_mvm_ctdp_cmd cmd = {
.operation = cpu_to_le32(op),
- .budget = cpu_to_le32(budget),
+ .budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]),
.window_size = 0,
};
int ret;
@@ -533,7 +557,7 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)

switch (op) {
case CTDP_CMD_OPERATION_START:
- mvm->cooling_dev.cur_state = budget;
+ mvm->cooling_dev.cur_state = state;
break;
case CTDP_CMD_OPERATION_REPORT:
IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
@@ -757,29 +781,6 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
mvm->tz_device.temp_trips[i] = S16_MIN;
}

-static const u32 iwl_mvm_cdev_budgets[] = {
- 2000, /* cooling state 0 */
- 1800, /* cooling state 1 */
- 1600, /* cooling state 2 */
- 1400, /* cooling state 3 */
- 1200, /* cooling state 4 */
- 1000, /* cooling state 5 */
- 900, /* cooling state 6 */
- 800, /* cooling state 7 */
- 700, /* cooling state 8 */
- 650, /* cooling state 9 */
- 600, /* cooling state 10 */
- 550, /* cooling state 11 */
- 500, /* cooling state 12 */
- 450, /* cooling state 13 */
- 400, /* cooling state 14 */
- 350, /* cooling state 15 */
- 300, /* cooling state 16 */
- 250, /* cooling state 17 */
- 200, /* cooling state 18 */
- 150, /* cooling state 19 */
-};
-
static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
@@ -797,6 +798,7 @@ static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
return -EBUSY;

*state = mvm->cooling_dev.cur_state;
+
return 0;
}

@@ -820,7 +822,7 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
}

ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
- iwl_mvm_cdev_budgets[new_state]);
+ new_state);

unlock:
mutex_unlock(&mvm->mutex);
--
2.5.0


2016-03-09 17:46:16

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 11/21] iwlwifi: mvm: ROC: cleanup time event info on FW failure

From: Matti Gottlieb <[email protected]>

Currently when the FW sends start/stop aux roc time event
notification with an error status, the driver returns an
error value, but does not remove the time event, and does
not notify the stack above that the time event is over.

This causes problems that the stack above assumes we are still
in the middle of a time event, and therefore can block different
events, such as scanning.

On FW failure notification, cleanup the time event parameters and
notify the stack above that the time event is over.

Signed-off-by: Matti Gottlieb <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 924dd6a..2c12789 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -371,20 +371,13 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,

iwl_mvm_te_check_trigger(mvm, notif, te_data);

- if (!le32_to_cpu(notif->status)) {
- IWL_DEBUG_TE(mvm,
- "ERROR: Aux ROC Time Event %s notification failure\n",
- (le32_to_cpu(notif->action) &
- TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end");
- return -EINVAL;
- }
-
IWL_DEBUG_TE(mvm,
- "Aux ROC time event notification - UID = 0x%x action %d\n",
+ "Aux ROC time event notification - UID = 0x%x action %d (error = %d)\n",
le32_to_cpu(notif->unique_id),
- le32_to_cpu(notif->action));
+ le32_to_cpu(notif->action), le32_to_cpu(notif->status));

- if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
+ if (!le32_to_cpu(notif->status) ||
+ le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
/* End TE, notify mac80211 */
ieee80211_remain_on_channel_expired(mvm->hw);
iwl_mvm_roc_finished(mvm); /* flush aux queue */
--
2.5.0


2016-03-09 17:46:01

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 04/21] iwlwifi: mvm: avoid panics with thermal device usage

Thermal zone device registration can fail, and in this case
we don't want to remove WiFi functionality. This is why the
thermal zone registration function is void, and the flows
continue even if the thermal zone device registration failed.
Same applies for the cooling device.

This means that we at least need to remember that the thermal
zone device didn't register properly and take the minimal
precautions to avoid panic'ing when we access it.

This was missing.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 -
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 57 +++++++++++++++-------------
2 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index ab410b4..b869db9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1575,7 +1575,6 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp);
void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm);
-int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm);
int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget);

/* Location Aware Regulatory */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index 999bcb8..0a02e98 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -211,10 +211,14 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
* the firmware and hence to take the mutex.
* Avoid the deadlock by unlocking the mutex here.
*/
- mutex_unlock(&mvm->mutex);
- thermal_notify_framework(mvm->tz_device.tzone,
- mvm->tz_device.fw_trips_index[ths_crossed]);
- mutex_lock(&mvm->mutex);
+ if (mvm->tz_device.tzone) {
+ struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
+
+ mutex_unlock(&mvm->mutex);
+ thermal_notify_framework(tz_dev->tzone,
+ tz_dev->fw_trips_index[ths_crossed]);
+ mutex_lock(&mvm->mutex);
+ }
#endif /* CONFIG_THERMAL */
}

@@ -520,16 +524,20 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)

lockdep_assert_held(&mvm->mutex);

+ if (!mvm->tz_device.tzone)
+ return -EINVAL;
+
/* The driver holds array of temperature trips that are unsorted
* and uncompressed, the FW should get it compressed and sorted
*/

/* compress temp_trips to cmd array, remove uninitialized values*/
- for (i = 0; i < IWL_MAX_DTS_TRIPS; i++)
+ for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
if (mvm->tz_device.temp_trips[i] != S16_MIN) {
cmd.thresholds[idx++] =
cpu_to_le16(mvm->tz_device.temp_trips[i]);
}
+ }
cmd.num_temps = cpu_to_le32(idx);

if (!idx)
@@ -696,6 +704,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
IWL_DEBUG_TEMP(mvm,
"Failed to register to thermal zone (err = %ld)\n",
PTR_ERR(mvm->tz_device.tzone));
+ mvm->tz_device.tzone = NULL;
return;
}

@@ -750,6 +759,10 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
return ret;
}

+ /* can happen if the registration failed */
+ if (!mvm->cooling_dev.cdev)
+ return -EINVAL;
+
if (op == CTDP_CMD_OPERATION_START)
mvm->cooling_dev.cur_state = budget;

@@ -812,15 +825,12 @@ static struct thermal_cooling_device_ops tcooling_ops = {
.set_cur_state = iwl_mvm_tcool_set_cur_state,
};

-int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
+static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
{
char name[] = "iwlwifi";

- if (!iwl_mvm_is_ctdp_supported(mvm)) {
- mvm->cooling_dev.cdev = NULL;
-
- return 0;
- }
+ if (!iwl_mvm_is_ctdp_supported(mvm))
+ return;

BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);

@@ -833,34 +843,29 @@ int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
IWL_DEBUG_TEMP(mvm,
"Failed to register to cooling device (err = %ld)\n",
PTR_ERR(mvm->cooling_dev.cdev));
- return PTR_ERR(mvm->cooling_dev.cdev);
+ mvm->cooling_dev.cdev = NULL;
+ return;
}
-
- return 0;
}

static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
{
- if (!iwl_mvm_is_tt_in_fw(mvm))
+ if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
return;

- if (mvm->tz_device.tzone) {
- IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
- thermal_zone_device_unregister(mvm->tz_device.tzone);
- mvm->tz_device.tzone = NULL;
- }
+ IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
+ thermal_zone_device_unregister(mvm->tz_device.tzone);
+ mvm->tz_device.tzone = NULL;
}

static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
{
- if (!iwl_mvm_is_ctdp_supported(mvm))
+ if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
return;

- if (mvm->cooling_dev.cdev) {
- IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
- thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
- mvm->cooling_dev.cdev = NULL;
- }
+ IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
+ thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
+ mvm->cooling_dev.cdev = NULL;
}
#endif /* CONFIG_THERMAL */

--
2.5.0


2016-03-09 17:46:09

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 08/21] iwlwifi: mvm: extend time event duration

From: Sara Sharon <[email protected]>

Before authentication, we start a time event during
which we wait for a beacon in order to sync our timers.
If we didn't hear the beacon during this time - we abandon
the connection. However, in congested environment, it was
observed we might not hear beacons in that time slot.
Extend the time event to give the connection a better chance.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ++----
drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 2 +-
2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index ec6b072..3590835 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2556,10 +2556,8 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
- 200 + vif->bss_conf.beacon_int);
- u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
- 100 + vif->bss_conf.beacon_int);
+ u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
+ u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;

if (WARN_ON_ONCE(vif->bss_conf.assoc))
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
index 99d9a35..3d2e8b6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
@@ -115,7 +115,7 @@
* needed by the driver.
*/

-#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500
+#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 600
#define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400

/**
--
2.5.0


2016-03-09 17:46:31

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 18/21] iwlwifi: pcie: avoid restocks inside rx loop if not emergency

From: Gregory Greenman <[email protected]>

When trying to reach high Rx throughput of more than 500Mbps on
a device with a relatively weak CPU (Atom x5-Z8500), CPU utilization
may become a bottleneck. Analysis showed that we are looping in
iwl_pcie_rx_handle for very long periods which led to starvation
of other threads (iwl_pcie_rx_handle runs with _bh disabled).
We were handling Rx and allocating new buffers and the new buffers
were ready quickly enough to be available before we had finished
handling all the buffers available in the hardware. As a
consequence, we called iwl_pcie_rxq_restock to refill the hardware
with the new buffers, and start again handling new buffers without
exiting the function. Since we read the hardware pointer again when
we goto restart, new buffers were handled immediately instead of
exiting the function.

This patch avoids refilling RBs inside rx handling loop, unless an
emergency situation is reached. It also doesn't read the hardware
pointer again unless we are in an emergency (unlikely) case.
This significantly reduce the maximal time we spend in
iwl_pcie_rx_handle with _bh disabled.

Signed-off-by: Gregory Greenman <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 59 ++++++++++++++++------------
1 file changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 98524a0..4be3c35 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -231,6 +231,9 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
}
}

+/*
+ * iwl_pcie_rxq_mq_restock - restock implementation for multi-queue rx
+ */
static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
struct iwl_rxq *rxq)
{
@@ -277,17 +280,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
}

/*
- * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
+ * iwl_pcie_rxq_sq_restock - restock implementation for single queue rx
*/
-static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
+static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans,
+ struct iwl_rxq *rxq)
{
struct iwl_rx_mem_buffer *rxb;

@@ -332,6 +328,26 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
}

/*
+ * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static
+void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
+{
+ if (trans->cfg->mq_rx_supported)
+ iwl_pcie_rxq_mq_restock(trans, rxq);
+ else
+ iwl_pcie_rxq_sq_restock(trans, rxq);
+}
+
+/*
* iwl_pcie_rx_alloc_page - allocates and returns a page.
*
*/
@@ -907,7 +923,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
if (trans->cfg->mq_rx_supported) {
iwl_pcie_rx_mq_hw_init(trans);
} else {
- iwl_pcie_rxq_restock(trans, def_rxq);
+ iwl_pcie_rxq_sq_restock(trans, def_rxq);
iwl_pcie_rx_hw_init(trans, def_rxq);
}

@@ -1222,24 +1238,13 @@ restart:
count = 0;
if (rxq->used_count < rxq->queue_size / 3)
emergency = false;
+
+ rxq->read = i;
spin_unlock(&rxq->lock);
iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
- spin_lock(&rxq->lock);
- }
- }
- /* handle restock for three cases, can be all of them at once:
- * - we just pulled buffers from the allocator
- * - we have 8+ unstolen pages accumulated
- * - we are in emergency and allocated buffers
- */
- if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) {
- rxq->read = i;
- spin_unlock(&rxq->lock);
- if (trans->cfg->mq_rx_supported)
- iwl_pcie_rxq_mq_restock(trans, rxq);
- else
iwl_pcie_rxq_restock(trans, rxq);
- goto restart;
+ goto restart;
+ }
}
}
out:
@@ -1264,6 +1269,8 @@ out:

if (rxq->napi.poll)
napi_gro_flush(&rxq->napi, false);
+
+ iwl_pcie_rxq_restock(trans, rxq);
}

static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry)
--
2.5.0


2016-03-09 18:08:13

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 09/21] iwlwifi: mvm: add ctdp operations to debugfs

Hi Chaya,

[auto build test ERROR on wireless-drivers-next/master]
[also build test ERROR on next-20160309]
[cannot apply to v4.5-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Emmanuel-Grumbach/iwlwifi-pcie-forbid-RTPM-on-device-removal/20160310-014851
base: https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: sparc64-allmodconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=sparc64

All errors (new ones prefixed by >>):

drivers/net/wireless/intel/iwlwifi/mvm/tt.c: In function 'iwl_mvm_ctdp_command':
>> drivers/net/wireless/intel/iwlwifi/mvm/tt.c:536:6: error: 'struct iwl_mvm' has no member named 'cooling_dev'
mvm->cooling_dev.cur_state = budget;
^

vim +536 drivers/net/wireless/intel/iwlwifi/mvm/tt.c

530 IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
531 return ret;
532 }
533
534 switch (op) {
535 case CTDP_CMD_OPERATION_START:
> 536 mvm->cooling_dev.cur_state = budget;
537 break;
538 case CTDP_CMD_OPERATION_REPORT:
539 IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.57 kB)
.config.gz (43.83 kB)
Download all attachments

2016-03-09 17:46:07

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 07/21] iwlwifi: mvm: set the correct amsdu enum values

From: Sara Sharon <[email protected]>

The amsdu enum values are off by 1 bit. Fix it.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
index eb9b870..7a16e55 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
@@ -264,9 +264,8 @@ enum iwl_rx_mpdu_mac_flags2 {
};

enum iwl_rx_mpdu_amsdu_info {
- IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK = 0x3f,
- IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x40,
- /* 0x80 bit reserved for now */
+ IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK = 0x7f,
+ IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x80,
};

enum iwl_rx_l3l4_flags {
--
2.5.0


2016-03-09 17:45:56

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 02/21] iwlwifi: pcie: refactor RXBs reclaiming code

From: Sara Sharon <[email protected]>

Change the code to move rxbs directly from the allocator's
list to the queue's free list. This makes the code more
readable, saves the interim array and the double loop over
the free RBs.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 75 ++++++++++++----------------
1 file changed, 33 insertions(+), 42 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 489b07a..a310fd2 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -539,40 +539,46 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
}

/*
- * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages
+ * iwl_pcie_rx_allocator_get - returns the pre-allocated pages
.*
.* Called by queue when the queue posted allocation request and
* has freed 8 RBDs in order to restock itself.
+ * This function directly moves the allocated RBs to the queue's ownership
+ * and updates the relevant counters.
*/
-static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
- struct iwl_rx_mem_buffer
- *out[RX_CLAIM_REQ_ALLOC])
+static void iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
+ struct iwl_rxq *rxq)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rb_allocator *rba = &trans_pcie->rba;
int i;

+ lockdep_assert_held(&rxq->lock);
+
/*
* atomic_dec_if_positive returns req_ready - 1 for any scenario.
* If req_ready is 0 atomic_dec_if_positive will return -1 and this
- * function will return -ENOMEM, as there are no ready requests.
+ * function will return early, as there are no ready requests.
* atomic_dec_if_positive will perofrm the *actual* decrement only if
* req_ready > 0, i.e. - there are ready requests and the function
* hands one request to the caller.
*/
if (atomic_dec_if_positive(&rba->req_ready) < 0)
- return -ENOMEM;
+ return;

spin_lock(&rba->lock);
for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) {
/* Get next free Rx buffer, remove it from free list */
- out[i] = list_first_entry(&rba->rbd_allocated,
- struct iwl_rx_mem_buffer, list);
- list_del(&out[i]->list);
+ struct iwl_rx_mem_buffer *rxb =
+ list_first_entry(&rba->rbd_allocated,
+ struct iwl_rx_mem_buffer, list);
+
+ list_move(&rxb->list, &rxq->rx_free);
}
spin_unlock(&rba->lock);

- return 0;
+ rxq->used_count -= RX_CLAIM_REQ_ALLOC;
+ rxq->free_count += RX_CLAIM_REQ_ALLOC;
}

static void iwl_pcie_rx_allocator_work(struct work_struct *data)
@@ -1149,7 +1155,7 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq[queue];
- u32 r, i, j, count = 0;
+ u32 r, i, count = 0;
bool emergency = false;

restart:
@@ -1193,39 +1199,24 @@ restart:

i = (i + 1) & (rxq->queue_size - 1);

- /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
- * try to claim the pre-allocated buffers from the allocator */
- if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) {
+ /*
+ * If we have RX_CLAIM_REQ_ALLOC released rx buffers -
+ * try to claim the pre-allocated buffers from the allocator.
+ * If not ready - will try to reclaim next time.
+ * There is no need to reschedule work - allocator exits only
+ * on success
+ */
+ if (rxq->used_count >= RX_CLAIM_REQ_ALLOC)
+ iwl_pcie_rx_allocator_get(trans, rxq);
+
+ if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && !emergency) {
struct iwl_rb_allocator *rba = &trans_pcie->rba;
- struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC];
-
- if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 &&
- !emergency) {
- /* Add the remaining 6 empty RBDs
- * for allocator use
- */
- spin_lock(&rba->lock);
- list_splice_tail_init(&rxq->rx_used,
- &rba->rbd_empty);
- spin_unlock(&rba->lock);
- }

- /* If not ready - continue, will try to reclaim later.
- * No need to reschedule work - allocator exits only on
- * success */
- if (!iwl_pcie_rx_allocator_get(trans, out)) {
- /* If success - then RX_CLAIM_REQ_ALLOC
- * buffers were retrieved and should be added
- * to free list */
- rxq->used_count -= RX_CLAIM_REQ_ALLOC;
- for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) {
- list_add_tail(&out[j]->list,
- &rxq->rx_free);
- rxq->free_count++;
- }
- }
- }
- if (emergency) {
+ /* Add the remaining empty RBDs for allocator use */
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+ } else if (emergency) {
count++;
if (count == 8) {
count = 0;
--
2.5.0


2016-03-09 18:14:19

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2016-03-09

Hi Kalle,

On Wed, Mar 9, 2016 at 7:43 PM, Grumbach, Emmanuel
<[email protected]> wrote:
> Hi Kalle,
>
> this is the very last pull request for 4.6. I hope it is not too late.
> Most of it are fixes for code that is already in
> wireless-drivers.next.git. There are a few other patches as well.
> Let me know if you have issues!
> Thank you.

As you saw, we have a compilation issue when THERMAL is not enabled.
I'll respin.

>
> The following changes since commit 53f09e742b0fdf14a2a2bfd2062ee96c9b3eedf0:
>
> Merge branch 'fixes' into next (2016-03-02 09:35:38 +0200)
>
> 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-2016-03-09
>
> for you to fetch changes up to 0831fcd67fc5bddd360bca51a3892bbd33048dbb:
>
> iwlwifi: mvm: update GSCAN capabilities (2016-03-09 16:55:39 +0200)
>
> ----------------------------------------------------------------
> * update GSCAN capabilities (Ayala)
> * fix AES-CMAC in AP mode (Johannes)
> * adapt prints to new firmware API
> * rx path improvements (Sara and Gregory)
> * fixes for the thermal / cooling device code (Chaya Rachel)
> * fixes for GO uAPSD handling
> * more code for the 9000 device family (Sara)
> * infrastructure work for firmware notification (Chaya Rachel)
> * improve association reliablity (Sara)
> * runtime PM fixes
> * fixes for ROC (HS2.0)
>
> ----------------------------------------------------------------
> Ayala Beker (1):
> iwlwifi: mvm: update GSCAN capabilities
>
> Chaya Rachel Ivgi (4):
> iwlwifi: mvm: fix unregistration of thermal in some error flows
> iwlwifi: mvm: add ctdp operations to debugfs
> iwlwifi: mvm: add support for async rx handler without hold the mutex
> iwlwifi: mvm: return the cooling state index instead of the budget
>
> Emmanuel Grumbach (4):
> iwlwifi: mvm: avoid panics with thermal device usage
> iwlwifi: mvm: don't let NDPs mess the packet tracking
> iwlwifi: mvm: remove RRM advertisement
> iwlwifi: mvm: adapt the firmware assert log to new firmware
>
> Gregory Greenman (1):
> iwlwifi: pcie: avoid restocks inside rx loop if not emergency
>
> Johannes Berg (1):
> iwlwifi: mvm: don't try to offload AES-CMAC in AP/IBSS modes
>
> Luca Coelho (1):
> iwlwifi: pcie: forbid RTPM on device removal
>
> Matti Gottlieb (1):
> iwlwifi: mvm: ROC: cleanup time event info on FW failure
>
> Sara Sharon (8):
> iwlwifi: pcie: refactor RXBs reclaiming code
> iwlwifi: pcie: set RB chunk size back to 64
> iwlwifi: refactor the code that reads the MAC address from the NVM
> iwlwifi: mvm: set the correct amsdu enum values
> iwlwifi: mvm: extend time event duration
> iwlwifi: mvm: turn off AMSDU bit in QoS control for de-aggregated AMSDUs
> iwlwifi: pcie: fine tune number of rxbs
> iwlwifi: add support for getting HW address from CSR
>
> drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 ++--
> drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +-
> drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +
> drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 10 +++++
> drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 27 ++++++------
> drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 38 ++++++++++-------
> drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 9 ++--
> drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 11 +++++
> drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 13 ++++++
> drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 146 ++++++++++++++++++++++++++++++++++++++++------------------------
> drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 +--
> drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 42 +++++++++++++++++++
> drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 5 +--
> drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++----
> drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +--
> drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 11 +----
> drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 120 +++++++++++++++++++++++++++++++++--------------------
> drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 12 ++++++
> drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 15 ++-----
> drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 2 +-
> drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 175 ++++++++++++++++++++++++++++++++++++++++++-----------------------------------
> drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 +++++++++++--
> drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 28 ++++++-------
> drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 28 +++++++++++++
> drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
> drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 148 ++++++++++++++++++++++++++++++++---------------------------------
> drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ---
> 27 files changed, 563 insertions(+), 351 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2016-03-09 17:46:20

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 13/21] iwlwifi: pcie: fine tune number of rxbs

From: Sara Sharon <[email protected]>

We kick the allocator when we have 2 RBDs that don't have
attached RBs, and the allocator allocates 8 RBs meaning
that it needs another 6 RBDs to attach the RBs to.
The design is that allocator should always have enough RBDs
to fulfill requests, so we give in advance 6 RBDs to the
allocator so that when it is kicked, it gets additional 2 RBDs
and has enough RBDs.
These RBDs were taken from the Rx queue itself, meaning
that each Rx queue didn't have the maximal number of
RBDs, but MAX - 6.
Change initial number of RBDs in the system to include both
queue size and allocator reserves.
Note the multi-queue is always 511 instead of 512 to avoid a
full queue since we cannot detect this state easily enough in
the 9000 arch.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 9 ++++++---
drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +-
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 11 ++++++-----
3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
index 8af818b..582008a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
@@ -511,9 +511,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
*/
#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002)

-#define MQ_RX_TABLE_SIZE 512
-#define MQ_RX_TABLE_MASK (MQ_RX_TABLE_SIZE - 1)
-#define MQ_RX_POOL_SIZE MQ_RX_TABLE_MASK
+#define MQ_RX_TABLE_SIZE 512
+#define MQ_RX_TABLE_MASK (MQ_RX_TABLE_SIZE - 1)
+#define MQ_RX_NUM_RBDS (MQ_RX_TABLE_SIZE - 1)
+#define RX_POOL_SIZE (MQ_RX_NUM_RBDS + \
+ IWL_MAX_RX_HW_QUEUES * \
+ (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC))

#define RX_QUEUE_SIZE 256
#define RX_QUEUE_MASK 255
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 6677f31..dadafbd 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -347,7 +347,7 @@ struct iwl_tso_hdr_page {
*/
struct iwl_trans_pcie {
struct iwl_rxq *rxq;
- struct iwl_rx_mem_buffer rx_pool[MQ_RX_POOL_SIZE];
+ struct iwl_rx_mem_buffer rx_pool[RX_POOL_SIZE];
struct iwl_rx_mem_buffer *global_table[MQ_RX_TABLE_SIZE];
struct iwl_rb_allocator rba;
struct iwl_trans *trans;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 509f790..98524a0 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -434,7 +434,7 @@ static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int i;

- for (i = 0; i < MQ_RX_POOL_SIZE; i++) {
+ for (i = 0; i < RX_POOL_SIZE; i++) {
if (!trans_pcie->rx_pool[i].page)
continue;
dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma,
@@ -835,7 +835,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *def_rxq;
struct iwl_rb_allocator *rba = &trans_pcie->rba;
- int i, err, num_rbds, allocator_pool_size;
+ int i, err, queue_size, allocator_pool_size, num_alloc;

if (!trans_pcie->rxq) {
err = iwl_pcie_rx_alloc(trans);
@@ -887,11 +887,12 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
}

/* move the pool to the default queue and allocator ownerships */
- num_rbds = trans->cfg->mq_rx_supported ?
- MQ_RX_POOL_SIZE : RX_QUEUE_SIZE;
+ queue_size = trans->cfg->mq_rx_supported ?
+ MQ_RX_NUM_RBDS : RX_QUEUE_SIZE;
allocator_pool_size = trans->num_rx_queues *
(RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC);
- for (i = 0; i < num_rbds; i++) {
+ num_alloc = queue_size + allocator_pool_size;
+ for (i = 0; i < num_alloc; i++) {
struct iwl_rx_mem_buffer *rxb = &trans_pcie->rx_pool[i];

if (i < allocator_pool_size)
--
2.5.0


2016-03-09 17:46:12

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 09/21] iwlwifi: mvm: add ctdp operations to debugfs

From: Chaya Rachel Ivgi <[email protected]>

Add debugfs entries to get the ctdp budget average
and to stop ctdp.

Signed-off-by: Chaya Rachel Ivgi <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 42 +++++++++++++
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 76 +++++++++++++-----------
2 files changed, 84 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 56e6b0b..a43b392 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -73,6 +73,44 @@
#include "debugfs.h"
#include "iwl-fw-error-dump.h"

+static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ char buf[16];
+ int pos, budget;
+
+ if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+ return -EIO;
+
+ mutex_lock(&mvm->mutex);
+ budget = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_REPORT, 0);
+ mutex_unlock(&mvm->mutex);
+
+ if (budget < 0)
+ return budget;
+
+ pos = scnprintf(buf, sizeof(buf), "%d\n", budget);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+
+ if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+ return -EIO;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_STOP, 0);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
@@ -1493,6 +1531,8 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);

/* Device wide debugfs entries */
+MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget);
+MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8);
@@ -1542,6 +1582,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index 0a02e98..a396549 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -510,6 +510,48 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = {
.support_tx_backoff = true,
};

+int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
+{
+ struct iwl_mvm_ctdp_cmd cmd = {
+ .operation = cpu_to_le32(op),
+ .budget = cpu_to_le32(budget),
+ .window_size = 0,
+ };
+ int ret;
+ u32 status;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
+ CTDP_CONFIG_CMD),
+ sizeof(cmd), &cmd, &status);
+
+ if (ret) {
+ IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
+ return ret;
+ }
+
+ switch (op) {
+ case CTDP_CMD_OPERATION_START:
+ mvm->cooling_dev.cur_state = budget;
+ break;
+ case CTDP_CMD_OPERATION_REPORT:
+ IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
+ /* when the function is called with CTDP_CMD_OPERATION_REPORT
+ * option the function should return the average budget value
+ * that is received from the FW.
+ * The budget can't be less or equal to 0, so it's possible
+ * to distinguish between error values and budgets.
+ */
+ return status;
+ case CTDP_CMD_OPERATION_STOP:
+ IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n");
+ break;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_THERMAL
static int compare_temps(const void *a, const void *b)
{
@@ -738,40 +780,6 @@ static const u32 iwl_mvm_cdev_budgets[] = {
150, /* cooling state 19 */
};

-int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
-{
- struct iwl_mvm_ctdp_cmd cmd = {
- .operation = cpu_to_le32(op),
- .budget = cpu_to_le32(budget),
- .window_size = 0,
- };
- int ret;
- u32 status;
-
- lockdep_assert_held(&mvm->mutex);
-
- ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
- CTDP_CONFIG_CMD),
- sizeof(cmd), &cmd, &status);
-
- if (ret) {
- IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
- return ret;
- }
-
- /* can happen if the registration failed */
- if (!mvm->cooling_dev.cdev)
- return -EINVAL;
-
- if (op == CTDP_CMD_OPERATION_START)
- mvm->cooling_dev.cur_state = budget;
-
- else if (op == CTDP_CMD_OPERATION_REPORT)
- IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
-
- return 0;
-}
-
static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
--
2.5.0


2016-03-09 17:46:35

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 20/21] iwlwifi: mvm: don't try to offload AES-CMAC in AP/IBSS modes

From: Johannes Berg <[email protected]>

The firmware/hardware only supports checking AES-CMAC on RX, not
using it on TX. For station mode this is fine, since it's the only
thing it will ever do. For AP mode, it never receives such frames,
but must be able to transmit them. This is currently broken since
we try to enable them for hardware crypto (for RX only) and then
treat them as TX_CMD_SEC_EXT, leading to FIFO underruns during TX
so the frames never go out to the air.

To fix this, simply use software on TX in AP (and IBSS) mode.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 39b9c38..76e649c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2686,8 +2686,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
* GTK on AP interface is a TX-only key, return 0;
* on IBSS they're per-station and because we're lazy
* we don't support them for RX, so do the same.
+ * CMAC in AP/IBSS modes must be done in software.
*/
- ret = 0;
+ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ ret = -EOPNOTSUPP;
+ else
+ ret = 0;
key->hw_key_idx = STA_KEY_IDX_INVALID;
break;
}
--
2.5.0


2016-03-09 17:46:33

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 19/21] iwlwifi: mvm: adapt the firmware assert log to new firmware

Newer firmware versions put different data in the memory
which is read by the driver upon firmware crash. Just
change the variable names in the code and the name of the
data in the log that we print withouth any functional
change.
On older firmware, there will be a mismatch between the
names that are printed and the content itself, but that's
harmless.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 +++----
.../wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 27 ++++++++++-----------
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 28 +++++++++++-----------
3 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index f62c2d7..85628127 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1652,10 +1652,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)

trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
table.data1, table.data2, table.line,
- table.blink1, table.blink2, table.ilink1,
- table.ilink2, table.bcon_time, table.gp1,
- table.gp2, table.gp3, table.ucode_ver,
- table.hw_ver, 0, table.brd_ver);
+ table.blink2, table.ilink1, table.ilink2,
+ table.bcon_time, table.gp1, table.gp2,
+ table.gp3, table.ucode_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/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
index 2a0703f..f02e2c8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
@@ -2,6 +2,7 @@
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland 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
@@ -121,13 +122,12 @@ TRACE_EVENT(iwlwifi_dev_tx,

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 major, u32 minor, u32 hw_ver,
- u32 brd_ver),
+ u32 data1, u32 data2, u32 line, u32 blink2, u32 ilink1,
+ u32 ilink2, u32 bcon_time, u32 gp1, u32 gp2, u32 rev_type,
+ 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, major, minor, hw_ver, brd_ver),
+ blink2, ilink1, ilink2, bcon_time, gp1, gp2,
+ rev_type, major, minor, hw_ver, brd_ver),
TP_STRUCT__entry(
DEV_ENTRY
__field(u32, desc)
@@ -135,14 +135,13 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__field(u32, data1)
__field(u32, data2)
__field(u32, line)
- __field(u32, blink1)
__field(u32, blink2)
__field(u32, ilink1)
__field(u32, ilink2)
__field(u32, bcon_time)
__field(u32, gp1)
__field(u32, gp2)
- __field(u32, gp3)
+ __field(u32, rev_type)
__field(u32, major)
__field(u32, minor)
__field(u32, hw_ver)
@@ -155,29 +154,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__entry->data1 = data1;
__entry->data2 = data2;
__entry->line = line;
- __entry->blink1 = blink1;
__entry->blink2 = blink2;
__entry->ilink1 = ilink1;
__entry->ilink2 = ilink2;
__entry->bcon_time = bcon_time;
__entry->gp1 = gp1;
__entry->gp2 = gp2;
- __entry->gp3 = gp3;
+ __entry->rev_type = rev_type;
__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 major 0x%08X "
+ "blink2 0x%05X ilink 0x%05X 0x%05X "
+ "bcon_tm %010u gp 0x%08X 0x%08X rev_type 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->data1, __entry->data2, __entry->line,
__entry->blink2, __entry->ilink1, __entry->ilink2,
__entry->bcon_time, __entry->gp1, __entry->gp2,
- __entry->gp3, __entry->major, __entry->minor,
+ __entry->rev_type, __entry->major, __entry->minor,
__entry->hw_ver, __entry->brd_ver)
);

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 59453c1..53cdc57 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -376,8 +376,8 @@ struct iwl_error_event_table_v1 {
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 trm_hw_status0; /* TRM HW status */
+ u32 trm_hw_status1; /* TRM HW status */
u32 blink2; /* branch link */
u32 ilink1; /* interrupt link */
u32 ilink2; /* interrupt link */
@@ -389,7 +389,7 @@ struct iwl_error_event_table {
u32 tsf_hi; /* network timestamp function timer */
u32 gp1; /* GP1 timer register */
u32 gp2; /* GP2 timer register */
- u32 gp3; /* GP3 timer register */
+ u32 fw_rev_type; /* firmware revision type */
u32 major; /* uCode version major */
u32 minor; /* uCode version minor */
u32 hw_ver; /* HW Silicon version */
@@ -408,7 +408,7 @@ struct iwl_error_event_table {
* time_flag */
u32 isr4; /* isr status register LMPM_NIC_ISR4:
* wico interrupt */
- u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
+ u32 last_cmd_id; /* last HCMD id handled by the firmware */
u32 wait_event; /* wait event() caller address */
u32 l2p_control; /* L2pControlField */
u32 l2p_duration; /* L2pDurationField */
@@ -419,7 +419,7 @@ 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 /* LOG_ERROR_TABLE_API_S_VER_2 */;
+} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;

/*
* UMAC error struct - relevant starting from family 8000 chip.
@@ -529,9 +529,9 @@ static void iwl_mvm_dump_nic_error_log_old(struct iwl_mvm *mvm)

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.ucode_ver, 0,
+ table.blink2, table.ilink1, table.ilink2,
+ table.bcon_time, table.gp1, 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));
@@ -615,14 +615,14 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)

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.blink2, table.ilink1,
table.ilink2, table.bcon_time, table.gp1,
- table.gp2, table.gp3, table.major,
+ table.gp2, table.fw_rev_type, 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 | trm_hw_status0\n", table.trm_hw_status0);
+ IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
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);
@@ -634,7 +634,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
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 revision type\n", table.fw_rev_type);
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);
@@ -645,7 +645,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
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 | last cmd Id\n", table.last_cmd_id);
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);
--
2.5.0


2016-03-09 17:46:03

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 05/21] iwlwifi: refactor the code that reads the MAC address from the NVM

From: Sara Sharon <[email protected]>

It makes it slightly easier to follow. Pass the pointer to
the transport which allows to read WFMP_MAC_ADDR_X register
only when needed and to use IWL_ERR instead of the less
commonly used IWL_ERR_DEV logger macro.

Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 97 ++++++++++++----------
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 +-
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 11 +--
3 files changed, 55 insertions(+), 58 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 3481357..5e6b90d 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland 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
@@ -69,6 +70,7 @@
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
+#include "iwl-prph.h"

/* NVM offsets (in words) definitions */
enum wkp_nvm_offsets {
@@ -522,27 +524,11 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
}

-static void iwl_set_hw_address(const struct iwl_cfg *cfg,
- struct iwl_nvm_data *data,
- const __le16 *nvm_sec)
-{
- const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR);
-
- /* The byte order is little endian 16 bit, meaning 214365 */
- data->hw_addr[0] = hw_addr[1];
- data->hw_addr[1] = hw_addr[0];
- data->hw_addr[2] = hw_addr[3];
- data->hw_addr[3] = hw_addr[2];
- data->hw_addr[4] = hw_addr[5];
- data->hw_addr[5] = hw_addr[4];
-}
-
-static void iwl_set_hw_address_family_8000(struct device *dev,
+static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
const __le16 *mac_override,
- const __le16 *nvm_hw,
- __le32 mac_addr0, __le32 mac_addr1)
+ const __le16 *nvm_hw)
{
const u8 *hw_addr;

@@ -568,11 +554,16 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0)
return;

- IWL_ERR_DEV(dev,
- "mac address from nvm override section is not valid\n");
+ IWL_ERR(trans,
+ "mac address from nvm override section is not valid\n");
}

if (nvm_hw) {
+ /* read the mac address from WFMP registers */
+ __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans,
+ WFMP_MAC_ADDR_0));
+ __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
+ WFMP_MAC_ADDR_1));
/* read the MAC address from HW resisters */
hw_addr = (const u8 *)&mac_addr0;
data->hw_addr[0] = hw_addr[3];
@@ -585,28 +576,50 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
data->hw_addr[5] = hw_addr[0];

if (!is_valid_ether_addr(data->hw_addr))
- IWL_ERR_DEV(dev,
- "mac address (%pM) from hw section is not valid\n",
- data->hw_addr);
+ IWL_ERR(trans,
+ "mac address (%pM) from hw section is not valid\n",
+ data->hw_addr);

return;
}

- IWL_ERR_DEV(dev, "mac address is not found\n");
+ IWL_ERR(trans, "mac address is not found\n");
+}
+
+static void iwl_set_hw_address(struct iwl_trans *trans,
+ const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data, const __le16 *nvm_hw,
+ const __le16 *mac_override)
+{
+ if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
+
+ /* The byte order is little endian 16 bit, meaning 214365 */
+ data->hw_addr[0] = hw_addr[1];
+ data->hw_addr[1] = hw_addr[0];
+ data->hw_addr[2] = hw_addr[3];
+ data->hw_addr[3] = hw_addr[2];
+ data->hw_addr[4] = hw_addr[5];
+ data->hw_addr[5] = hw_addr[4];
+ } else {
+ iwl_set_hw_address_family_8000(trans, cfg, data,
+ mac_override, nvm_hw);
+ }
}

struct iwl_nvm_data *
-iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
const __le16 *nvm_calib, const __le16 *regulatory,
const __le16 *mac_override, const __le16 *phy_sku,
- u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
- __le32 mac_addr0, __le32 mac_addr1)
+ u8 tx_chains, u8 rx_chains, bool lar_fw_supported)
{
+ struct device *dev = trans->dev;
struct iwl_nvm_data *data;
- u32 sku;
- u32 radio_cfg;
+ bool lar_enabled;
+ u32 sku, radio_cfg;
u16 lar_config;
+ const __le16 *ch_section;

if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
data = kzalloc(sizeof(*data) +
@@ -645,21 +658,16 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
/* Checking for required sections */
if (!nvm_calib) {
- IWL_ERR_DEV(dev,
- "Can't parse empty Calib NVM sections\n");
+ IWL_ERR(trans,
+ "Can't parse empty Calib NVM sections\n");
kfree(data);
return NULL;
}
/* in family 8000 Xtal calibration values moved to OTP */
data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
- }
-
- if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
- iwl_set_hw_address(cfg, data, nvm_hw);
-
- iwl_init_sbands(dev, cfg, data, nvm_sw,
- tx_chains, rx_chains, lar_fw_supported);
+ lar_enabled = true;
+ ch_section = nvm_sw;
} else {
u16 lar_offset = data->nvm_version < 0xE39 ?
NVM_LAR_OFFSET_FAMILY_8000_OLD :
@@ -668,16 +676,13 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
lar_config = le16_to_cpup(regulatory + lar_offset);
data->lar_enabled = !!(lar_config &
NVM_LAR_ENABLED_FAMILY_8000);
-
- /* MAC address in family 8000 */
- iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
- nvm_hw, mac_addr0, mac_addr1);
-
- iwl_init_sbands(dev, cfg, data, regulatory,
- tx_chains, rx_chains,
- lar_fw_supported && data->lar_enabled);
+ lar_enabled = data->lar_enabled;
+ ch_section = regulatory;
}

+ iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override);
+ iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
+ lar_fw_supported && lar_enabled);
data->calib_version = 255;

return data;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
index 4e8e0dc..d704d52 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -74,12 +74,11 @@
* later with iwl_free_nvm_data().
*/
struct iwl_nvm_data *
-iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
const __le16 *nvm_calib, const __le16 *regulatory,
const __le16 *mac_override, const __le16 *phy_sku,
- u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
- __le32 mac_addr0, __le32 mac_addr1);
+ u8 tx_chains, u8 rx_chains, bool lar_fw_supported);

/**
* iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index c446e0d..25a9840 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -300,7 +300,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
struct iwl_nvm_section *sections = mvm->nvm_sections;
const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
bool lar_enabled;
- __le32 mac_addr0, mac_addr1;

/* Checking for required sections */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
@@ -336,12 +335,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if (WARN_ON(!mvm->cfg))
return NULL;

- /* read the mac address from WFMP registers */
- mac_addr0 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
- WFMP_MAC_ADDR_0));
- mac_addr1 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
- WFMP_MAC_ADDR_1));
-
hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
@@ -354,10 +347,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);

- return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
+ return iwl_parse_nvm_data(mvm->trans, mvm->cfg, hw, sw, calib,
regulatory, mac_override, phy_sku,
mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant,
- lar_enabled, mac_addr0, mac_addr1);
+ lar_enabled);
}

#define MAX_NVM_FILE_LEN 16384
--
2.5.0


2016-03-09 17:45:59

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 03/21] iwlwifi: pcie: set RB chunk size back to 64

From: Sara Sharon <[email protected]>

128 byte chunk size is supported only on PCIe and not
on IOSF. For now, change it back to 64 byte.

Reported-by: Oren Givon <[email protected]>
Signed-off-by: Sara Sharon <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index a310fd2..509f790 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -801,11 +801,10 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)

/*
* Activate DMA snooping.
- * Set RX DMA chunk size to 128 bit
+ * Set RX DMA chunk size to 64B
* Default queue is 0
*/
iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
- RFH_GEN_CFG_RB_CHUNK_SIZE |
(DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
RFH_GEN_CFG_SERVICE_DMA_SNOOP);
/* Enable the relevant rx queues */
--
2.5.0