aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEran Harary <eran.harary@intel.com>2015-04-27 03:29:31 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-04-28 07:58:51 -0400
commit8d193ca26cc28019e760b77830295a0c349d90dc (patch)
treea6f6ab3f1292c21106fa941c2c9827b065b45370 /drivers/net/wireless
parent553452e5ffc0ed13214a287549627d02d9d7fbdc (diff)
iwlwifi: mvm: don't power off the device between INIT and OPER firmwares
Our device needs two different firmwares: the INIT firmware and the operational (OPER) firmware. The first one is run when the driver loads and it returns calibrations results as well as the NVM. The second one implements the WiFi protocol. If the wlan interface is not brought up, the device is put to low power state: no firmware will be running. When the interface is brought up, we would run the OPER firmware only and reuse the results of the run of the INIT firmware when the driver was loaded. This is changing with this patch. We now run the INIT firmware every time mac80211 calls start(). The penalty for that is minimal since the INIT firwmare run fast. I now also avoid to power down the device between the INIT and OPER firmware on certains buses. The motivation for this change is that there are components on the device (MFUART) that are triggered by the INIT firmware and need the device to be powered up in order to keep running. Powering the device down between the INIT and OPER firmware would stop these components and prevent them from running again since they are triggered by the INIT firmware only. The new flow allows this and also allows to trigger these components again when the interface is brought up after it has been brought down. Signed-off-by: Eran Harary <eran.harary@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h41
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c45
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c6
4 files changed, 51 insertions, 42 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 6dfed1259260..56254a837214 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -6,7 +6,7 @@
6 * GPL LICENSE SUMMARY 6 * GPL LICENSE SUMMARY
7 * 7 *
8 * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. 8 * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10 * 10 *
11 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as 12 * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
32 * BSD LICENSE 32 * BSD LICENSE
33 * 33 *
34 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. 34 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 35 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
36 * All rights reserved. 36 * All rights reserved.
37 * 37 *
38 * Redistribution and use in source and binary forms, with or without 38 * Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg {
421 * 421 *
422 * All the handlers MUST be implemented 422 * All the handlers MUST be implemented
423 * 423 *
424 * @start_hw: starts the HW- from that point on, the HW can send interrupts 424 * @start_hw: starts the HW. If low_power is true, the NIC needs to be taken
425 * May sleep 425 * out of a low power state. From that point on, the HW can send
426 * interrupts. May sleep.
426 * @op_mode_leave: Turn off the HW RF kill indication if on 427 * @op_mode_leave: Turn off the HW RF kill indication if on
427 * May sleep 428 * May sleep
428 * @start_fw: allocates and inits all the resources for the transport 429 * @start_fw: allocates and inits all the resources for the transport
@@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg {
432 * the SCD base address in SRAM, then provide it here, or 0 otherwise. 433 * the SCD base address in SRAM, then provide it here, or 0 otherwise.
433 * May sleep 434 * May sleep
434 * @stop_device: stops the whole device (embedded CPU put to reset) and stops 435 * @stop_device: stops the whole device (embedded CPU put to reset) and stops
435 * the HW. From that point on, the HW will be in low power but will still 436 * the HW. If low_power is true, the NIC will be put in low power state.
436 * issue interrupt if the HW RF kill is triggered. This callback must do 437 * From that point on, the HW will be stopped but will still issue an
437 * the right thing and not crash even if start_hw() was called but not 438 * interrupt if the HW RF kill switch is triggered.
438 * start_fw(). May sleep 439 * This callback must do the right thing and not crash even if %start_hw()
440 * was called but not &start_fw(). May sleep.
439 * @d3_suspend: put the device into the correct mode for WoWLAN during 441 * @d3_suspend: put the device into the correct mode for WoWLAN during
440 * suspend. This is optional, if not implemented WoWLAN will not be 442 * suspend. This is optional, if not implemented WoWLAN will not be
441 * supported. This callback may sleep. 443 * supported. This callback may sleep.
@@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg {
491 */ 493 */
492struct iwl_trans_ops { 494struct iwl_trans_ops {
493 495
494 int (*start_hw)(struct iwl_trans *iwl_trans); 496 int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power);
495 void (*op_mode_leave)(struct iwl_trans *iwl_trans); 497 void (*op_mode_leave)(struct iwl_trans *iwl_trans);
496 int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, 498 int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
497 bool run_in_rfkill); 499 bool run_in_rfkill);
498 int (*update_sf)(struct iwl_trans *trans, 500 int (*update_sf)(struct iwl_trans *trans,
499 struct iwl_sf_region *st_fwrd_space); 501 struct iwl_sf_region *st_fwrd_space);
500 void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); 502 void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
501 void (*stop_device)(struct iwl_trans *trans); 503 void (*stop_device)(struct iwl_trans *trans, bool low_power);
502 504
503 void (*d3_suspend)(struct iwl_trans *trans, bool test); 505 void (*d3_suspend)(struct iwl_trans *trans, bool test);
504 int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, 506 int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
@@ -652,11 +654,16 @@ static inline void iwl_trans_configure(struct iwl_trans *trans,
652 trans->ops->configure(trans, trans_cfg); 654 trans->ops->configure(trans, trans_cfg);
653} 655}
654 656
655static inline int iwl_trans_start_hw(struct iwl_trans *trans) 657static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power)
656{ 658{
657 might_sleep(); 659 might_sleep();
658 660
659 return trans->ops->start_hw(trans); 661 return trans->ops->start_hw(trans, low_power);
662}
663
664static inline int iwl_trans_start_hw(struct iwl_trans *trans)
665{
666 return trans->ops->start_hw(trans, true);
660} 667}
661 668
662static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans) 669static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
@@ -703,15 +710,21 @@ static inline int iwl_trans_update_sf(struct iwl_trans *trans,
703 return 0; 710 return 0;
704} 711}
705 712
706static inline void iwl_trans_stop_device(struct iwl_trans *trans) 713static inline void _iwl_trans_stop_device(struct iwl_trans *trans,
714 bool low_power)
707{ 715{
708 might_sleep(); 716 might_sleep();
709 717
710 trans->ops->stop_device(trans); 718 trans->ops->stop_device(trans, low_power);
711 719
712 trans->state = IWL_TRANS_NO_FW; 720 trans->state = IWL_TRANS_NO_FW;
713} 721}
714 722
723static inline void iwl_trans_stop_device(struct iwl_trans *trans)
724{
725 _iwl_trans_stop_device(trans, true);
726}
727
715static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) 728static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
716{ 729{
717 might_sleep(); 730 might_sleep();
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 9c28fe72fd74..df869633f4dd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -6,7 +6,7 @@
6 * GPL LICENSE SUMMARY 6 * GPL LICENSE SUMMARY
7 * 7 *
8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10 * 10 *
11 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as 12 * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
32 * BSD LICENSE 32 * BSD LICENSE
33 * 33 *
34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 35 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
36 * All rights reserved. 36 * All rights reserved.
37 * 37 *
38 * Redistribution and use in source and binary forms, with or without 38 * Redistribution and use in source and binary forms, with or without
@@ -322,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
322 322
323 lockdep_assert_held(&mvm->mutex); 323 lockdep_assert_held(&mvm->mutex);
324 324
325 if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) 325 if (WARN_ON_ONCE(mvm->calibrating))
326 return 0; 326 return 0;
327 327
328 iwl_init_notification_wait(&mvm->notif_wait, 328 iwl_init_notification_wait(&mvm->notif_wait,
@@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
396 */ 396 */
397 ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, 397 ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
398 MVM_UCODE_CALIB_TIMEOUT); 398 MVM_UCODE_CALIB_TIMEOUT);
399 if (!ret)
400 mvm->init_ucode_complete = true;
401 399
402 if (ret && iwl_mvm_is_radio_killed(mvm)) { 400 if (ret && iwl_mvm_is_radio_killed(mvm)) {
403 IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); 401 IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n");
@@ -649,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
649 * module loading, load init ucode now 647 * module loading, load init ucode now
650 * (for example, if we were in RFKILL) 648 * (for example, if we were in RFKILL)
651 */ 649 */
652 if (!mvm->init_ucode_complete) { 650 ret = iwl_run_init_mvm_ucode(mvm, false);
653 ret = iwl_run_init_mvm_ucode(mvm, false); 651 if (ret && !iwlmvm_mod_params.init_dbg) {
654 if (ret && !iwlmvm_mod_params.init_dbg) { 652 IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
655 IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); 653 /* this can't happen */
656 /* this can't happen */ 654 if (WARN_ON(ret > 0))
657 if (WARN_ON(ret > 0)) 655 ret = -ERFKILL;
658 ret = -ERFKILL; 656 goto error;
659 goto error; 657 }
660 } 658 if (!iwlmvm_mod_params.init_dbg) {
661 if (!iwlmvm_mod_params.init_dbg) { 659 /*
662 /* 660 * Stop and start the transport without entering low power
663 * should stop and start HW since that INIT 661 * mode. This will save the state of other components on the
664 * image just loaded 662 * device that are triggered by the INIT firwmare (MFUART).
665 */ 663 */
666 iwl_trans_stop_device(mvm->trans); 664 _iwl_trans_stop_device(mvm->trans, false);
667 ret = iwl_trans_start_hw(mvm->trans); 665 _iwl_trans_start_hw(mvm->trans, false);
668 if (ret) 666 if (ret)
669 return ret; 667 return ret;
670 }
671 } 668 }
672 669
673 if (iwlmvm_mod_params.init_dbg) 670 if (iwlmvm_mod_params.init_dbg)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d5522a161242..cf70f681d1ac 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -603,7 +603,6 @@ struct iwl_mvm {
603 603
604 enum iwl_ucode_type cur_ucode; 604 enum iwl_ucode_type cur_ucode;
605 bool ucode_loaded; 605 bool ucode_loaded;
606 bool init_ucode_complete;
607 bool calibrating; 606 bool calibrating;
608 u32 error_event_table; 607 u32 error_event_table;
609 u32 log_event_table; 608 u32 log_event_table;
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 6debb0c9111a..47bbf573fdc8 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -1021,7 +1021,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
1021 iwl_pcie_tx_start(trans, scd_addr); 1021 iwl_pcie_tx_start(trans, scd_addr);
1022} 1022}
1023 1023
1024static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) 1024static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
1025{ 1025{
1026 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1026 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1027 bool hw_rfkill, was_hw_rfkill; 1027 bool hw_rfkill, was_hw_rfkill;
@@ -1116,7 +1116,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
1116void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) 1116void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
1117{ 1117{
1118 if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) 1118 if (iwl_op_mode_hw_rf_kill(trans->op_mode, state))
1119 iwl_trans_pcie_stop_device(trans); 1119 iwl_trans_pcie_stop_device(trans, true);
1120} 1120}
1121 1121
1122static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) 1122static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -1201,7 +1201,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
1201 return 0; 1201 return 0;
1202} 1202}
1203 1203
1204static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) 1204static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
1205{ 1205{
1206 bool hw_rfkill; 1206 bool hw_rfkill;
1207 int err; 1207 int err;