Skip to content

Commit 02e5329

Browse files
westerihtejun
authored andcommitted
ahci: Add runtime PM support for the host controller
This patch adds runtime PM support for the AHCI host controller driver so that the host controller is powered down when all SATA ports are runtime suspended. Powering down the AHCI host controller can reduce power consumption and possibly allow the CPU to enter lower power idle states (S0ix) during runtime. Runtime PM is blocked by default and needs to be unblocked from userspace as needed (via power/* sysfs nodes). Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent bb03c64 commit 02e5329

File tree

1 file changed

+61
-12
lines changed

1 file changed

+61
-12
lines changed

drivers/ata/ahci.c

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ enum board_ids {
8585
};
8686

8787
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
88+
static void ahci_remove_one(struct pci_dev *dev);
8889
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
8990
unsigned long deadline);
9091
static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
@@ -93,10 +94,14 @@ static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
9394
static bool is_mcp89_apple(struct pci_dev *pdev);
9495
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
9596
unsigned long deadline);
97+
#ifdef CONFIG_PM
98+
static int ahci_pci_device_runtime_suspend(struct device *dev);
99+
static int ahci_pci_device_runtime_resume(struct device *dev);
96100
#ifdef CONFIG_PM_SLEEP
97101
static int ahci_pci_device_suspend(struct device *dev);
98102
static int ahci_pci_device_resume(struct device *dev);
99103
#endif
104+
#endif /* CONFIG_PM */
100105

101106
static struct scsi_host_template ahci_sht = {
102107
AHCI_SHT("ahci"),
@@ -559,13 +564,15 @@ static const struct pci_device_id ahci_pci_tbl[] = {
559564

560565
static const struct dev_pm_ops ahci_pci_pm_ops = {
561566
SET_SYSTEM_SLEEP_PM_OPS(ahci_pci_device_suspend, ahci_pci_device_resume)
567+
SET_RUNTIME_PM_OPS(ahci_pci_device_runtime_suspend,
568+
ahci_pci_device_runtime_resume, NULL)
562569
};
563570

564571
static struct pci_driver ahci_pci_driver = {
565572
.name = DRV_NAME,
566573
.id_table = ahci_pci_tbl,
567574
.probe = ahci_init_one,
568-
.remove = ata_pci_remove_one,
575+
.remove = ahci_remove_one,
569576
.driver = {
570577
.pm = &ahci_pci_pm_ops,
571578
},
@@ -796,21 +803,13 @@ static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
796803
}
797804

798805

799-
#ifdef CONFIG_PM_SLEEP
800-
static int ahci_pci_device_suspend(struct device *dev)
806+
#ifdef CONFIG_PM
807+
static void ahci_pci_disable_interrupts(struct ata_host *host)
801808
{
802-
struct pci_dev *pdev = to_pci_dev(dev);
803-
struct ata_host *host = pci_get_drvdata(pdev);
804809
struct ahci_host_priv *hpriv = host->private_data;
805810
void __iomem *mmio = hpriv->mmio;
806811
u32 ctl;
807812

808-
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
809-
dev_err(&pdev->dev,
810-
"BIOS update required for suspend/resume\n");
811-
return -EIO;
812-
}
813-
814813
/* AHCI spec rev1.1 section 8.3.3:
815814
* Software must disable interrupts prior to requesting a
816815
* transition of the HBA to D3 state.
@@ -819,7 +818,44 @@ static int ahci_pci_device_suspend(struct device *dev)
819818
ctl &= ~HOST_IRQ_EN;
820819
writel(ctl, mmio + HOST_CTL);
821820
readl(mmio + HOST_CTL); /* flush */
821+
}
822+
823+
static int ahci_pci_device_runtime_suspend(struct device *dev)
824+
{
825+
struct pci_dev *pdev = to_pci_dev(dev);
826+
struct ata_host *host = pci_get_drvdata(pdev);
822827

828+
ahci_pci_disable_interrupts(host);
829+
return 0;
830+
}
831+
832+
static int ahci_pci_device_runtime_resume(struct device *dev)
833+
{
834+
struct pci_dev *pdev = to_pci_dev(dev);
835+
struct ata_host *host = pci_get_drvdata(pdev);
836+
int rc;
837+
838+
rc = ahci_pci_reset_controller(host);
839+
if (rc)
840+
return rc;
841+
ahci_pci_init_controller(host);
842+
return 0;
843+
}
844+
845+
#ifdef CONFIG_PM_SLEEP
846+
static int ahci_pci_device_suspend(struct device *dev)
847+
{
848+
struct pci_dev *pdev = to_pci_dev(dev);
849+
struct ata_host *host = pci_get_drvdata(pdev);
850+
struct ahci_host_priv *hpriv = host->private_data;
851+
852+
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
853+
dev_err(&pdev->dev,
854+
"BIOS update required for suspend/resume\n");
855+
return -EIO;
856+
}
857+
858+
ahci_pci_disable_interrupts(host);
823859
return ata_host_suspend(host, PMSG_SUSPEND);
824860
}
825861

@@ -847,6 +883,8 @@ static int ahci_pci_device_resume(struct device *dev)
847883
}
848884
#endif
849885

886+
#endif /* CONFIG_PM */
887+
850888
static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
851889
{
852890
int rc;
@@ -1666,7 +1704,18 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
16661704

16671705
pci_set_master(pdev);
16681706

1669-
return ahci_host_activate(host, &ahci_sht);
1707+
rc = ahci_host_activate(host, &ahci_sht);
1708+
if (rc)
1709+
return rc;
1710+
1711+
pm_runtime_put_noidle(&pdev->dev);
1712+
return 0;
1713+
}
1714+
1715+
static void ahci_remove_one(struct pci_dev *pdev)
1716+
{
1717+
pm_runtime_get_noresume(&pdev->dev);
1718+
ata_pci_remove_one(pdev);
16701719
}
16711720

16721721
module_pci_driver(ahci_pci_driver);

0 commit comments

Comments
 (0)