diff options
author | Nate Watterson <nwatters@codeaurora.org> | 2017-07-20 15:26:24 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2017-08-04 16:34:14 -0400 |
commit | 8eede5bc4ef04281fbba7ddfe157052d0e76075d (patch) | |
tree | 87c88cf41e67e8168c4fd7c965d7ec323bb76e67 | |
parent | afbd39a42e2d777852a2809298fd4e71b1e5abf7 (diff) |
ata: ahci_platform: Add shutdown handler
The newly introduced ahci_platform_shutdown() method is called during
system shutdown to disable host controller DMA and interrupts in order
to avoid potentially corrupting or otherwise interfering with a new
kernel being started with kexec.
Signed-off-by: Nate Watterson <nwatters@codeaurora.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | drivers/ata/ahci_platform.c | 1 | ||||
-rw-r--r-- | drivers/ata/libahci_platform.c | 34 | ||||
-rw-r--r-- | include/linux/ahci_platform.h | 2 |
3 files changed, 37 insertions, 0 deletions
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 62a04c8fb5c9..99f9a895a459 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c | |||
@@ -93,6 +93,7 @@ MODULE_DEVICE_TABLE(acpi, ahci_acpi_match); | |||
93 | static struct platform_driver ahci_driver = { | 93 | static struct platform_driver ahci_driver = { |
94 | .probe = ahci_probe, | 94 | .probe = ahci_probe, |
95 | .remove = ata_platform_remove_one, | 95 | .remove = ata_platform_remove_one, |
96 | .shutdown = ahci_platform_shutdown, | ||
96 | .driver = { | 97 | .driver = { |
97 | .name = DRV_NAME, | 98 | .name = DRV_NAME, |
98 | .of_match_table = ahci_of_match, | 99 | .of_match_table = ahci_of_match, |
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index cd2eab6aa92e..a270a1173c8c 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c | |||
@@ -602,6 +602,40 @@ static void ahci_host_stop(struct ata_host *host) | |||
602 | ahci_platform_disable_resources(hpriv); | 602 | ahci_platform_disable_resources(hpriv); |
603 | } | 603 | } |
604 | 604 | ||
605 | /** | ||
606 | * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports | ||
607 | * @dev: platform device pointer for the host | ||
608 | * | ||
609 | * This function is called during system shutdown and performs the minimal | ||
610 | * deconfiguration required to ensure that an ahci_platform host cannot | ||
611 | * corrupt or otherwise interfere with a new kernel being started with kexec. | ||
612 | */ | ||
613 | void ahci_platform_shutdown(struct platform_device *pdev) | ||
614 | { | ||
615 | struct ata_host *host = platform_get_drvdata(pdev); | ||
616 | struct ahci_host_priv *hpriv = host->private_data; | ||
617 | void __iomem *mmio = hpriv->mmio; | ||
618 | int i; | ||
619 | |||
620 | for (i = 0; i < host->n_ports; i++) { | ||
621 | struct ata_port *ap = host->ports[i]; | ||
622 | |||
623 | /* Disable port interrupts */ | ||
624 | if (ap->ops->freeze) | ||
625 | ap->ops->freeze(ap); | ||
626 | |||
627 | /* Stop the port DMA engines */ | ||
628 | if (ap->ops->port_stop) | ||
629 | ap->ops->port_stop(ap); | ||
630 | } | ||
631 | |||
632 | /* Disable and clear host interrupts */ | ||
633 | writel(readl(mmio + HOST_CTL) & ~HOST_IRQ_EN, mmio + HOST_CTL); | ||
634 | readl(mmio + HOST_CTL); /* flush */ | ||
635 | writel(GENMASK(host->n_ports, 0), mmio + HOST_IRQ_STAT); | ||
636 | } | ||
637 | EXPORT_SYMBOL_GPL(ahci_platform_shutdown); | ||
638 | |||
605 | #ifdef CONFIG_PM_SLEEP | 639 | #ifdef CONFIG_PM_SLEEP |
606 | /** | 640 | /** |
607 | * ahci_platform_suspend_host - Suspend an ahci-platform host | 641 | * ahci_platform_suspend_host - Suspend an ahci-platform host |
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index a270f25ee7c7..1b0a17b22cd3 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h | |||
@@ -36,6 +36,8 @@ int ahci_platform_init_host(struct platform_device *pdev, | |||
36 | const struct ata_port_info *pi_template, | 36 | const struct ata_port_info *pi_template, |
37 | struct scsi_host_template *sht); | 37 | struct scsi_host_template *sht); |
38 | 38 | ||
39 | void ahci_platform_shutdown(struct platform_device *pdev); | ||
40 | |||
39 | int ahci_platform_suspend_host(struct device *dev); | 41 | int ahci_platform_suspend_host(struct device *dev); |
40 | int ahci_platform_resume_host(struct device *dev); | 42 | int ahci_platform_resume_host(struct device *dev); |
41 | int ahci_platform_suspend(struct device *dev); | 43 | int ahci_platform_suspend(struct device *dev); |