iwlwifi: pcie: add pm_prepare and pm_complete ops
authorLuca Coelho <luciano.coelho@intel.com>
Tue, 1 Dec 2015 18:39:57 +0000 (20:39 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sat, 27 Feb 2016 20:00:07 +0000 (22:00 +0200)
With these ops, we can know when we are about to enter system suspend.
This allows us to exit D0i3 state before entering suspend.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/pcie/drv.c

index 0ca0f13b69b0fa66e4d7ee13ed1f4c301bb2a1f6..91d74b3f666b5d5e316ea4d0a66654f5a5533700 100644 (file)
@@ -836,6 +836,7 @@ struct iwl_trans {
 
        enum iwl_plat_pm_mode system_pm_mode;
        enum iwl_plat_pm_mode runtime_pm_mode;
+       bool suspending;
 
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
index 753ec6785912f7f3eed9cab797d6216633582ad6..d33b6baf5f9872156707c27cee8e2a8755160974 100644 (file)
@@ -811,6 +811,45 @@ static int iwl_pci_runtime_resume(struct device *device)
 
        return 0;
 }
+
+static int iwl_pci_system_prepare(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+       IWL_DEBUG_RPM(trans, "preparing for system suspend\n");
+
+       /* This is called before entering system suspend and before
+        * the runtime resume is called.  Set the suspending flag to
+        * prevent the wakelock from being taken.
+        */
+       trans->suspending = true;
+
+       /* Wake the device up from runtime suspend before going to
+        * platform suspend.  This is needed because we don't know
+        * whether wowlan any is set and, if it's not, mac80211 will
+        * disconnect (in which case, we can't be in D0i3).
+        */
+       pm_runtime_resume(device);
+
+       return 0;
+}
+
+static void iwl_pci_system_complete(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+       IWL_DEBUG_RPM(trans, "completing system suspend\n");
+
+       /* This is called as a counterpart to the prepare op.  It is
+        * called either when suspending fails or when suspend
+        * completed successfully.  Now there's no risk of grabbing
+        * the wakelock anymore, so we can release the suspending
+        * flag.
+        */
+       trans->suspending = false;
+}
 #endif /* CONFIG_IWLWIFI_PCIE_RTPM */
 
 static const struct dev_pm_ops iwl_dev_pm_ops = {
@@ -820,6 +859,8 @@ static const struct dev_pm_ops iwl_dev_pm_ops = {
        SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend,
                           iwl_pci_runtime_resume,
                           NULL)
+       .prepare = iwl_pci_system_prepare,
+       .complete = iwl_pci_system_complete,
 #endif /* CONFIG_IWLWIFI_PCIE_RTPM */
 };