Skip to content

Commit 8d193ca

Browse files
Eran Hararyegrumbach
authored andcommitted
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 <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]>
1 parent 553452e commit 8d193ca

File tree

4 files changed

+51
-42
lines changed

4 files changed

+51
-42
lines changed

drivers/net/wireless/iwlwifi/iwl-trans.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* GPL LICENSE SUMMARY
77
*
88
* 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
1010
*
1111
* This program is free software; you can redistribute it and/or modify
1212
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
3232
* BSD LICENSE
3333
*
3434
* 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
3636
* All rights reserved.
3737
*
3838
* Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg {
421421
*
422422
* All the handlers MUST be implemented
423423
*
424-
* @start_hw: starts the HW- from that point on, the HW can send interrupts
425-
* May sleep
424+
* @start_hw: starts the HW. If low_power is true, the NIC needs to be taken
425+
* out of a low power state. From that point on, the HW can send
426+
* interrupts. May sleep.
426427
* @op_mode_leave: Turn off the HW RF kill indication if on
427428
* May sleep
428429
* @start_fw: allocates and inits all the resources for the transport
@@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg {
432433
* the SCD base address in SRAM, then provide it here, or 0 otherwise.
433434
* May sleep
434435
* @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-
* issue interrupt if the HW RF kill is triggered. This callback must do
437-
* the right thing and not crash even if start_hw() was called but not
438-
* start_fw(). May sleep
436+
* the HW. If low_power is true, the NIC will be put in low power state.
437+
* From that point on, the HW will be stopped but will still issue an
438+
* interrupt if the HW RF kill switch is triggered.
439+
* This callback must do the right thing and not crash even if %start_hw()
440+
* was called but not &start_fw(). May sleep.
439441
* @d3_suspend: put the device into the correct mode for WoWLAN during
440442
* suspend. This is optional, if not implemented WoWLAN will not be
441443
* supported. This callback may sleep.
@@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg {
491493
*/
492494
struct iwl_trans_ops {
493495

494-
int (*start_hw)(struct iwl_trans *iwl_trans);
496+
int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power);
495497
void (*op_mode_leave)(struct iwl_trans *iwl_trans);
496498
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
497499
bool run_in_rfkill);
498500
int (*update_sf)(struct iwl_trans *trans,
499501
struct iwl_sf_region *st_fwrd_space);
500502
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);
502504

503505
void (*d3_suspend)(struct iwl_trans *trans, bool test);
504506
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,
652654
trans->ops->configure(trans, trans_cfg);
653655
}
654656

655-
static inline int iwl_trans_start_hw(struct iwl_trans *trans)
657+
static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power)
656658
{
657659
might_sleep();
658660

659-
return trans->ops->start_hw(trans);
661+
return trans->ops->start_hw(trans, low_power);
662+
}
663+
664+
static inline int iwl_trans_start_hw(struct iwl_trans *trans)
665+
{
666+
return trans->ops->start_hw(trans, true);
660667
}
661668

662669
static 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,
703710
return 0;
704711
}
705712

706-
static inline void iwl_trans_stop_device(struct iwl_trans *trans)
713+
static inline void _iwl_trans_stop_device(struct iwl_trans *trans,
714+
bool low_power)
707715
{
708716
might_sleep();
709717

710-
trans->ops->stop_device(trans);
718+
trans->ops->stop_device(trans, low_power);
711719

712720
trans->state = IWL_TRANS_NO_FW;
713721
}
714722

723+
static inline void iwl_trans_stop_device(struct iwl_trans *trans)
724+
{
725+
_iwl_trans_stop_device(trans, true);
726+
}
727+
715728
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
716729
{
717730
might_sleep();

drivers/net/wireless/iwlwifi/mvm/fw.c

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* GPL LICENSE SUMMARY
77
*
88
* 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
1010
*
1111
* This program is free software; you can redistribute it and/or modify
1212
* it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
3232
* BSD LICENSE
3333
*
3434
* 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
3636
* All rights reserved.
3737
*
3838
* 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)
322322

323323
lockdep_assert_held(&mvm->mutex);
324324

325-
if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating))
325+
if (WARN_ON_ONCE(mvm->calibrating))
326326
return 0;
327327

328328
iwl_init_notification_wait(&mvm->notif_wait,
@@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
396396
*/
397397
ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
398398
MVM_UCODE_CALIB_TIMEOUT);
399-
if (!ret)
400-
mvm->init_ucode_complete = true;
401399

402400
if (ret && iwl_mvm_is_radio_killed(mvm)) {
403401
IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n");
@@ -649,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
649647
* module loading, load init ucode now
650648
* (for example, if we were in RFKILL)
651649
*/
652-
if (!mvm->init_ucode_complete) {
653-
ret = iwl_run_init_mvm_ucode(mvm, false);
654-
if (ret && !iwlmvm_mod_params.init_dbg) {
655-
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
656-
/* this can't happen */
657-
if (WARN_ON(ret > 0))
658-
ret = -ERFKILL;
659-
goto error;
660-
}
661-
if (!iwlmvm_mod_params.init_dbg) {
662-
/*
663-
* should stop and start HW since that INIT
664-
* image just loaded
665-
*/
666-
iwl_trans_stop_device(mvm->trans);
667-
ret = iwl_trans_start_hw(mvm->trans);
668-
if (ret)
669-
return ret;
670-
}
650+
ret = iwl_run_init_mvm_ucode(mvm, false);
651+
if (ret && !iwlmvm_mod_params.init_dbg) {
652+
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
653+
/* this can't happen */
654+
if (WARN_ON(ret > 0))
655+
ret = -ERFKILL;
656+
goto error;
657+
}
658+
if (!iwlmvm_mod_params.init_dbg) {
659+
/*
660+
* Stop and start the transport without entering low power
661+
* mode. This will save the state of other components on the
662+
* device that are triggered by the INIT firwmare (MFUART).
663+
*/
664+
_iwl_trans_stop_device(mvm->trans, false);
665+
_iwl_trans_start_hw(mvm->trans, false);
666+
if (ret)
667+
return ret;
671668
}
672669

673670
if (iwlmvm_mod_params.init_dbg)

drivers/net/wireless/iwlwifi/mvm/mvm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,6 @@ struct iwl_mvm {
603603

604604
enum iwl_ucode_type cur_ucode;
605605
bool ucode_loaded;
606-
bool init_ucode_complete;
607606
bool calibrating;
608607
u32 error_event_table;
609608
u32 log_event_table;

drivers/net/wireless/iwlwifi/pcie/trans.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
10211021
iwl_pcie_tx_start(trans, scd_addr);
10221022
}
10231023

1024-
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
1024+
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
10251025
{
10261026
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
10271027
bool hw_rfkill, was_hw_rfkill;
@@ -1116,7 +1116,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
11161116
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
11171117
{
11181118
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);
11201120
}
11211121

11221122
static 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,
12011201
return 0;
12021202
}
12031203

1204-
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
1204+
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
12051205
{
12061206
bool hw_rfkill;
12071207
int err;

0 commit comments

Comments
 (0)