*
* 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
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+#include <linux/pm_runtime.h>
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
if (ret)
goto out_free_drv;
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ 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);
+ pm_runtime_allow(&pdev->dev);
+#endif
return 0;
out_free_drv:
return 0;
}
-static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+static int iwl_pci_runtime_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+ IWL_DEBUG_RPM(trans, "entering runtime suspend\n");
+
+ /* For now we only allow D0I3 if the device is off */
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+ return -EBUSY;
+
+ trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+
+ iwl_trans_d3_suspend(trans, false);
+
+ return 0;
+}
+
+static int iwl_pci_runtime_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct iwl_trans *trans = pci_get_drvdata(pdev);
+ enum iwl_d3_status d3_status;
+
+ IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n");
+
+ iwl_trans_d3_resume(trans, &d3_status, false);
+
+ trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
+
+ return 0;
+}
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
+static const struct dev_pm_ops iwl_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend,
+ iwl_pci_resume)
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend,
+ iwl_pci_runtime_resume,
+ NULL)
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+};
#define IWL_PM_OPS (&iwl_dev_pm_ops)
-#else
+#else /* CONFIG_PM_SLEEP */
#define IWL_PM_OPS NULL
-#endif
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver iwl_pci_driver = {
.name = DRV_NAME,
#include <linux/bitops.h>
#include <linux/gfp.h>
#include <linux/vmalloc.h>
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+#include <linux/pm_runtime.h>
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
#include "iwl-drv.h"
#include "iwl-trans.h"
if (hw_rfkill != was_hw_rfkill)
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ pm_runtime_put_sync(trans->dev);
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
/* re-take ownership to prevent other users from stealing the deivce */
iwl_pcie_prepare_card_hw(trans);
}
/* ... rfkill can call stop_device and set it false if needed */
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ pm_runtime_get_sync(trans->dev);
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
return 0;
}
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int i;
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ /* TODO: check if this is really needed */
+ pm_runtime_disable(trans->dev);
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
synchronize_irq(trans_pcie->pci_dev->irq);
iwl_pcie_tx_free(trans);
spin_lock_irqsave(&trans_pcie->ref_lock, flags);
IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
trans_pcie->ref_count++;
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ pm_runtime_get(&trans_pcie->pci_dev->dev);
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
}
return;
}
trans_pcie->ref_count--;
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ pm_runtime_mark_last_busy(&trans_pcie->pci_dev->dev);
+ pm_runtime_put_autosuspend(&trans_pcie->pci_dev->dev);
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
}
trans_pcie->inta_mask = CSR_INI_SET_MASK;
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+#else
+ trans->runtime_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
return trans;
out_free_ict: