| From ac3e7dc10a5af628e8340ababec3b8f7912ca0ef Mon Sep 17 00:00:00 2001 |
| From: Prabhakar Kushwaha <pkushwaha@marvell.com> |
| Date: Sat, 25 Jan 2020 03:37:29 +0000 |
| Subject: [PATCH] ata: ahci: Add shutdown to freeze hardware resources of ahci |
| |
| commit 10a663a1b15134a5a714aa515e11425a44d4fdf7 upstream. |
| |
| device_shutdown() called from reboot or power_shutdown expect |
| all devices to be shutdown. Same is true for even ahci pci driver. |
| As no ahci shutdown function is implemented, the ata subsystem |
| always remains alive with DMA & interrupt support. File system |
| related calls should not be honored after device_shutdown(). |
| |
| So defining ahci pci driver shutdown to freeze hardware (mask |
| interrupt, stop DMA engine and free DMA resources). |
| |
| Signed-off-by: Prabhakar Kushwaha <pkushwaha@marvell.com> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c |
| index 691852b8bb41..14e612b9de2f 100644 |
| --- a/drivers/ata/ahci.c |
| +++ b/drivers/ata/ahci.c |
| @@ -80,6 +80,7 @@ enum board_ids { |
| |
| static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
| static void ahci_remove_one(struct pci_dev *dev); |
| +static void ahci_shutdown_one(struct pci_dev *dev); |
| static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, |
| unsigned long deadline); |
| static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, |
| @@ -593,6 +594,7 @@ static struct pci_driver ahci_pci_driver = { |
| .id_table = ahci_pci_tbl, |
| .probe = ahci_init_one, |
| .remove = ahci_remove_one, |
| + .shutdown = ahci_shutdown_one, |
| .driver = { |
| .pm = &ahci_pci_pm_ops, |
| }, |
| @@ -1881,6 +1883,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
| return 0; |
| } |
| |
| +static void ahci_shutdown_one(struct pci_dev *pdev) |
| +{ |
| + ata_pci_shutdown_one(pdev); |
| +} |
| + |
| static void ahci_remove_one(struct pci_dev *pdev) |
| { |
| pm_runtime_get_noresume(&pdev->dev); |
| diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c |
| index 9632ebe15055..aace6acf8717 100644 |
| --- a/drivers/ata/libata-core.c |
| +++ b/drivers/ata/libata-core.c |
| @@ -6764,6 +6764,26 @@ void ata_pci_remove_one(struct pci_dev *pdev) |
| ata_host_detach(host); |
| } |
| |
| +void ata_pci_shutdown_one(struct pci_dev *pdev) |
| +{ |
| + struct ata_host *host = pci_get_drvdata(pdev); |
| + int i; |
| + |
| + for (i = 0; i < host->n_ports; i++) { |
| + struct ata_port *ap = host->ports[i]; |
| + |
| + ap->pflags |= ATA_PFLAG_FROZEN; |
| + |
| + /* Disable port interrupts */ |
| + if (ap->ops->freeze) |
| + ap->ops->freeze(ap); |
| + |
| + /* Stop the port DMA engines */ |
| + if (ap->ops->port_stop) |
| + ap->ops->port_stop(ap); |
| + } |
| +} |
| + |
| /* move to PCI subsystem */ |
| int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) |
| { |
| @@ -7384,6 +7404,7 @@ EXPORT_SYMBOL_GPL(ata_timing_cycle2mode); |
| |
| #ifdef CONFIG_PCI |
| EXPORT_SYMBOL_GPL(pci_test_config_bits); |
| +EXPORT_SYMBOL_GPL(ata_pci_shutdown_one); |
| EXPORT_SYMBOL_GPL(ata_pci_remove_one); |
| #ifdef CONFIG_PM |
| EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend); |
| diff --git a/include/linux/libata.h b/include/linux/libata.h |
| index fa0c3dae2094..c44e4cfbcb16 100644 |
| --- a/include/linux/libata.h |
| +++ b/include/linux/libata.h |
| @@ -1220,6 +1220,7 @@ struct pci_bits { |
| }; |
| |
| extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); |
| +extern void ata_pci_shutdown_one(struct pci_dev *pdev); |
| extern void ata_pci_remove_one(struct pci_dev *pdev); |
| |
| #ifdef CONFIG_PM |
| -- |
| 2.7.4 |
| |