From 25effc3647635b8775aefcfd884a359b9fa31e9d Mon Sep 17 00:00:00 2001 From: Jingoo Han <jg1.han@samsung.com> Date: Thu, 10 Jan 2013 11:05:06 +0900 Subject: pata_samsung_cf: Use devm_clk_get() Use devm_clk_get() rather than clk_get() to make cleanup paths more simple. Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/pata_samsung_cf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 63ffb002ec6..70b0e01372b 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -512,7 +512,7 @@ static int __init pata_s3c_probe(struct platform_device *pdev) return -ENOMEM; } - info->clk = clk_get(&pdev->dev, "cfcon"); + info->clk = devm_clk_get(&pdev->dev, "cfcon"); if (IS_ERR(info->clk)) { dev_err(dev, "failed to get access to cf controller clock\n"); ret = PTR_ERR(info->clk); @@ -589,7 +589,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev) stop_clk: clk_disable(info->clk); - clk_put(info->clk); return ret; } @@ -601,7 +600,6 @@ static int __exit pata_s3c_remove(struct platform_device *pdev) ata_host_detach(host); clk_disable(info->clk); - clk_put(info->clk); return 0; } -- cgit v1.2.3-18-g5258 From 1757d902b029a29dfcef63609964385cf8865b5a Mon Sep 17 00:00:00 2001 From: David Milburn <dmilburn@redhat.com> Date: Mon, 14 Jan 2013 09:59:30 -0600 Subject: libata: export host controller number thru /sys As low-level drivers register their host controller(s), keep track of the number of controllers and export thru /sys in a <host.port> format so that udev can better match up port numbers with a specific controller. # pwd /sys/devices/pci0000:00 # find . -name 'ata*' -print (2nd controller with port multiplier attached) ./0000:00:1e.0/0000:05:01.0/ata2.7 ./0000:00:1e.0/0000:05:01.0/ata2.7/link7/dev7.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.0/dev7.0.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.0/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.1/dev7.1.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.1/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.2/dev7.2.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.2/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.3/dev7.3.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.3/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.4/dev7.4.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.4/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.5/dev7.5.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.5/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.6/dev7.6.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.6/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.7/dev7.7.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.7/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.8/dev7.8.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.8/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.9/dev7.9.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.9/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/ata_port ./0000:00:1e.0/0000:05:01.0/ata2.7/ata_port/ata2.7 ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.10/dev7.10.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.10/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.11/dev7.11.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.11/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.12/dev7.12.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.12/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.13/dev7.13.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.13/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.14/dev7.14.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.7/link7.14/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.8 ./0000:00:1e.0/0000:05:01.0/ata2.8/link8/dev8.0/ata_device ./0000:00:1e.0/0000:05:01.0/ata2.8/link8/ata_link ./0000:00:1e.0/0000:05:01.0/ata2.8/ata_port ./0000:00:1e.0/0000:05:01.0/ata2.8/ata_port/ata2.8 (1st controller) ./0000:00:1f.2/ata1.1 ./0000:00:1f.2/ata1.1/link1/dev1.0/ata_device ./0000:00:1f.2/ata1.1/link1/ata_link ./0000:00:1f.2/ata1.1/ata_port ./0000:00:1f.2/ata1.1/ata_port/ata1.1 ./0000:00:1f.2/ata1.2 ./0000:00:1f.2/ata1.2/link2/dev2.0/ata_device ./0000:00:1f.2/ata1.2/link2/ata_link ./0000:00:1f.2/ata1.2/ata_port ./0000:00:1f.2/ata1.2/ata_port/ata1.2 ./0000:00:1f.2/ata1.3 ./0000:00:1f.2/ata1.3/link3/dev3.0/ata_device ./0000:00:1f.2/ata1.3/link3/ata_link ./0000:00:1f.2/ata1.3/ata_port ./0000:00:1f.2/ata1.3/ata_port/ata1.3 ./0000:00:1f.2/ata1.4 ./0000:00:1f.2/ata1.4/link4/dev4.0/ata_device ./0000:00:1f.2/ata1.4/link4/ata_link ./0000:00:1f.2/ata1.4/ata_port ./0000:00:1f.2/ata1.4/ata_port/ata1.4 ./0000:00:1f.2/ata1.5 ./0000:00:1f.2/ata1.5/link5/dev5.0/ata_device ./0000:00:1f.2/ata1.5/link5/ata_link ./0000:00:1f.2/ata1.5/ata_port ./0000:00:1f.2/ata1.5/ata_port/ata1.5 ./0000:00:1f.2/ata1.6 ./0000:00:1f.2/ata1.6/link6/dev6.0/ata_device ./0000:00:1f.2/ata1.6/link6/ata_link ./0000:00:1f.2/ata1.6/ata_port ./0000:00:1f.2/ata1.6/ata_port/ata1.6 Signed-off-by: David Milburn <dmilburn@redhat.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-core.c | 4 ++++ drivers/ata/libata-transport.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 46cd3f4c6aa..275941b576a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -99,6 +99,7 @@ static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); atomic_t ata_print_id = ATOMIC_INIT(0); +atomic_t host_print_id = ATOMIC_INIT(0); struct ata_force_param { const char *name; @@ -6097,6 +6098,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = host->n_ports; host->ports[i]; i++) kfree(host->ports[i]); + /* track host controller */ + host->host_id = atomic_inc_return(&host_print_id); + /* give ports names and add SCSI hosts */ for (i = 0; i < host->n_ports; i++) host->ports[i]->print_id = atomic_inc_return(&ata_print_id); diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index c04d393d20c..61dca7a20a3 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -284,7 +284,7 @@ int ata_tport_add(struct device *parent, dev->parent = get_device(parent); dev->release = ata_tport_release; - dev_set_name(dev, "ata%d", ap->print_id); + dev_set_name(dev, "ata%d.%d", ap->host->host_id, ap->print_id); transport_setup_device(dev); error = device_add(dev); if (error) { -- cgit v1.2.3-18-g5258 From afe759511808cd5bb508b598007cf0c7b0ca8e08 Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:20:58 +0800 Subject: libata: identify and init ZPODD devices The ODD can be enabled for ZPODD if the following three conditions are satisfied: 1 The ODD supports device attention; 2 The platform can runtime power off the ODD through ACPI; 3 The ODD is either slot type or drawer type. For such ODDs, zpodd_init is called and a new structure is allocated for it to store ZPODD related stuffs. And the zpodd_dev_enabled function is used to test if ZPODD is currently enabled for this ODD. A new config CONFIG_SATA_ZPODD is added to selectively build ZPODD code. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/Kconfig | 13 ++++++ drivers/ata/Makefile | 1 + drivers/ata/libata-core.c | 4 +- drivers/ata/libata-scsi.c | 2 + drivers/ata/libata-zpodd.c | 100 +++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 14 +++++++ 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 drivers/ata/libata-zpodd.c (limited to 'drivers/ata') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index e08d322d01d..996d16c9c6e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -58,6 +58,19 @@ config ATA_ACPI You can disable this at kernel boot time by using the option libata.noacpi=1 +config SATA_ZPODD + bool "SATA Zero Power ODD Support" + depends on ATA_ACPI + default n + help + This option adds support for SATA ZPODD. It requires both + ODD and the platform support, and if enabled, will automatically + power on/off the ODD when certain condition is satisfied. This + does not impact user's experience of the ODD, only power is saved + when ODD is not in use(i.e. no disc inside). + + If unsure, say N. + config SATA_PMP bool "SATA Port Multiplier support" default y diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 9329dafba91..85e3de463ed 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -107,3 +107,4 @@ libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o +libata-$(CONFIG_SATA_ZPODD) += libata-zpodd.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 275941b576a..c7ecd8492f1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2401,8 +2401,10 @@ int ata_dev_configure(struct ata_device *dev) dma_dir_string = ", DMADIR"; } - if (ata_id_has_da(dev->id)) + if (ata_id_has_da(dev->id)) { dev->flags |= ATA_DFLAG_DA; + zpodd_init(dev); + } /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7c337e754da..1ff018525e3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3755,6 +3755,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev) mutex_lock(&ap->scsi_host->scan_mutex); spin_lock_irqsave(ap->lock, flags); + if (zpodd_dev_enabled(dev)) + zpodd_exit(dev); ata_acpi_unbind(dev); /* clearing dev->sdev is protected by host lock */ diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c new file mode 100644 index 00000000000..27eed2f09a8 --- /dev/null +++ b/drivers/ata/libata-zpodd.c @@ -0,0 +1,100 @@ +#include <linux/libata.h> +#include <linux/cdrom.h> + +#include "libata.h" + +enum odd_mech_type { + ODD_MECH_TYPE_SLOT, + ODD_MECH_TYPE_DRAWER, + ODD_MECH_TYPE_UNSUPPORTED, +}; + +struct zpodd { + enum odd_mech_type mech_type; /* init during probe, RO afterwards */ + struct ata_device *dev; +}; + +/* Per the spec, only slot type and drawer type ODD can be supported */ +static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) +{ + char buf[16]; + unsigned int ret; + struct rm_feature_desc *desc = (void *)(buf + 8); + struct ata_taskfile tf = {}; + + char cdb[] = { GPCMD_GET_CONFIGURATION, + 2, /* only 1 feature descriptor requested */ + 0, 3, /* 3, removable medium feature */ + 0, 0, 0,/* reserved */ + 0, sizeof(buf), + 0, 0, 0, + }; + + tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.command = ATA_CMD_PACKET; + tf.protocol = ATAPI_PROT_PIO; + tf.lbam = sizeof(buf); + + ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, + buf, sizeof(buf), 0); + if (ret) + return ODD_MECH_TYPE_UNSUPPORTED; + + if (be16_to_cpu(desc->feature_code) != 3) + return ODD_MECH_TYPE_UNSUPPORTED; + + if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1) + return ODD_MECH_TYPE_SLOT; + else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1) + return ODD_MECH_TYPE_DRAWER; + else + return ODD_MECH_TYPE_UNSUPPORTED; +} + +static bool odd_can_poweroff(struct ata_device *ata_dev) +{ + acpi_handle handle; + acpi_status status; + struct acpi_device *acpi_dev; + + handle = ata_dev_acpi_handle(ata_dev); + if (!handle) + return false; + + status = acpi_bus_get_device(handle, &acpi_dev); + if (ACPI_FAILURE(status)) + return false; + + return acpi_device_can_poweroff(acpi_dev); +} + +void zpodd_init(struct ata_device *dev) +{ + enum odd_mech_type mech_type; + struct zpodd *zpodd; + + if (dev->zpodd) + return; + + if (!odd_can_poweroff(dev)) + return; + + mech_type = zpodd_get_mech_type(dev); + if (mech_type == ODD_MECH_TYPE_UNSUPPORTED) + return; + + zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL); + if (!zpodd) + return; + + zpodd->mech_type = mech_type; + + zpodd->dev = dev; + dev->zpodd = zpodd; +} + +void zpodd_exit(struct ata_device *dev) +{ + kfree(dev->zpodd); + dev->zpodd = NULL; +} diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 7148a58020b..a21740b4ee1 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -230,4 +230,18 @@ static inline void ata_sff_exit(void) { } #endif /* CONFIG_ATA_SFF */ +/* libata-zpodd.c */ +#ifdef CONFIG_SATA_ZPODD +void zpodd_init(struct ata_device *dev); +void zpodd_exit(struct ata_device *dev); +static inline bool zpodd_dev_enabled(struct ata_device *dev) +{ + return dev->zpodd != NULL; +} +#else /* CONFIG_SATA_ZPODD */ +static inline void zpodd_init(struct ata_device *dev) {} +static inline void zpodd_exit(struct ata_device *dev) {} +static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } +#endif /* CONFIG_SATA_ZPODD */ + #endif /* __LIBATA_H__ */ -- cgit v1.2.3-18-g5258 From f064a20dded807448669426c9bfb7d03aba5659c Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:20:59 +0800 Subject: libata: move acpi notification code to zpodd Since the ata acpi notification code introduced in commit 3bd46600a7a7e938c54df8cdbac9910668c7dfb0 is solely for ZPODD, and we now have a dedicated place for it, move these code there. And the ata_acpi_add_pm_notifier code is changed a little bit in that it is now invoked when scsi device is not bound with ACPI yet, so the way to get the acpi handle is different with the previous version. And the ata_acpi_add/remove_pm_notifier is also simplified a little bit in that it doesn't check if the acpi_device for the handle exists or not as the odd_can_poweroff function already checked that. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-acpi.c | 71 ---------------------------------------------- drivers/ata/libata-zpodd.c | 34 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 71 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ef01ac07502..446b4e761af 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -974,57 +974,6 @@ void ata_acpi_on_disable(struct ata_device *dev) ata_acpi_clear_gtf(dev); } -static void ata_acpi_wake_dev(acpi_handle handle, u32 event, void *context) -{ - struct ata_device *ata_dev = context; - - if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev && - pm_runtime_suspended(&ata_dev->sdev->sdev_gendev)) - scsi_autopm_get_device(ata_dev->sdev); -} - -static void ata_acpi_add_pm_notifier(struct ata_device *dev) -{ - struct acpi_device *acpi_dev; - acpi_handle handle; - acpi_status status; - - handle = ata_dev_acpi_handle(dev); - if (!handle) - return; - - status = acpi_bus_get_device(handle, &acpi_dev); - if (ACPI_FAILURE(status)) - return; - - if (dev->sdev->can_power_off) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - ata_acpi_wake_dev, dev); - device_set_run_wake(&dev->sdev->sdev_gendev, true); - } -} - -static void ata_acpi_remove_pm_notifier(struct ata_device *dev) -{ - struct acpi_device *acpi_dev; - acpi_handle handle; - acpi_status status; - - handle = ata_dev_acpi_handle(dev); - if (!handle) - return; - - status = acpi_bus_get_device(handle, &acpi_dev); - if (ACPI_FAILURE(status)) - return; - - if (dev->sdev->can_power_off) { - device_set_run_wake(&dev->sdev->sdev_gendev, false); - acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - ata_acpi_wake_dev); - } -} - static void ata_acpi_register_power_resource(struct ata_device *dev) { struct scsi_device *sdev = dev->sdev; @@ -1057,13 +1006,11 @@ static void ata_acpi_unregister_power_resource(struct ata_device *dev) void ata_acpi_bind(struct ata_device *dev) { - ata_acpi_add_pm_notifier(dev); ata_acpi_register_power_resource(dev); } void ata_acpi_unbind(struct ata_device *dev) { - ata_acpi_remove_pm_notifier(dev); ata_acpi_unregister_power_resource(dev); } @@ -1105,9 +1052,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, acpi_handle *handle) { struct ata_device *ata_dev; - acpi_status status; - struct acpi_device *acpi_dev; - struct acpi_device_power_state *states; if (ap->flags & ATA_FLAG_ACPI_SATA) { if (!sata_pmp_attached(ap)) @@ -1124,21 +1068,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, if (!*handle) return -ENODEV; - status = acpi_bus_get_device(*handle, &acpi_dev); - if (ACPI_FAILURE(status)) - return 0; - - /* - * If firmware has _PS3 or _PR3 for this device, - * and this ata ODD device support device attention, - * it means this device can be powered off - */ - states = acpi_dev->power.states; - if ((states[ACPI_STATE_D3_HOT].flags.valid || - states[ACPI_STATE_D3_COLD].flags.explicit_set) && - ata_dev->flags & ATA_DFLAG_DA) - sdev->can_power_off = 1; - return 0; } diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 27eed2f09a8..9a0d90d09d8 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -1,5 +1,7 @@ #include <linux/libata.h> #include <linux/cdrom.h> +#include <linux/pm_runtime.h> +#include <scsi/scsi_device.h> #include "libata.h" @@ -12,6 +14,10 @@ enum odd_mech_type { struct zpodd { enum odd_mech_type mech_type; /* init during probe, RO afterwards */ struct ata_device *dev; + + /* The following fields are synchronized by PM core. */ + bool from_notify; /* resumed as a result of + * acpi wake notification */ }; /* Per the spec, only slot type and drawer type ODD can be supported */ @@ -68,6 +74,32 @@ static bool odd_can_poweroff(struct ata_device *ata_dev) return acpi_device_can_poweroff(acpi_dev); } +static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) +{ + struct ata_device *ata_dev = context; + struct zpodd *zpodd = ata_dev->zpodd; + struct device *dev = &ata_dev->sdev->sdev_gendev; + + if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev && + pm_runtime_suspended(dev)) { + zpodd->from_notify = true; + pm_runtime_resume(dev); + } +} + +static void ata_acpi_add_pm_notifier(struct ata_device *dev) +{ + acpi_handle handle = ata_dev_acpi_handle(dev); + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + zpodd_wake_dev, dev); +} + +static void ata_acpi_remove_pm_notifier(struct ata_device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev); + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev); +} + void zpodd_init(struct ata_device *dev) { enum odd_mech_type mech_type; @@ -89,12 +121,14 @@ void zpodd_init(struct ata_device *dev) zpodd->mech_type = mech_type; + ata_acpi_add_pm_notifier(dev); zpodd->dev = dev; dev->zpodd = zpodd; } void zpodd_exit(struct ata_device *dev) { + ata_acpi_remove_pm_notifier(dev); kfree(dev->zpodd); dev->zpodd = NULL; } -- cgit v1.2.3-18-g5258 From 3dc67440d99b2c718ef5f1eb1424a9066ffa3fb9 Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:21:00 +0800 Subject: libata: check zero power ready status for ZPODD Per the Mount Fuji spec, the ODD is considered zero power ready when: - For slot type ODD, no media inside; - For tray type ODD, no media inside and tray closed. The information can be retrieved by either the returned information of command GET_EVENT_STATUS_NOTIFICATION(the command is used to poll for media event) or sense code. The information provided by the media status byte is not accurate, it is possible that after a new disc is just inserted, the status byte still returns media not present. So this information can not be used as the deciding factor, we use sense code to decide if zpready status is true. When we first sensed the ODD in the zero power ready state, the zp_sampled will be set and timestamp will be recoreded. And after ODD stayed in this state for some pre-defined period, the ODD is considered as power off ready and the zp_ready flag will be set. The zp_ready flag serves as the deciding factor other code will use to see if power off is OK for the ODD. The Mount Fuji spec suggests a delay should be used here, to avoid the case user ejects the ODD and then instantly inserts a new one again, so that we can avoid a power transition. And some ODDs may be slow to place its head to the home position after disc is ejected, so a delay here is generally a good idea. And the delay time can be changed via the module param zpodd_poweroff_delay. The zero power ready status check is performed in the ata port's runtime suspend code path, when port is not frozen yet, as we need to issue some IOs to the ODD. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-eh.c | 14 +++++++-- drivers/ata/libata-zpodd.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 5 ++++ 3 files changed, 92 insertions(+), 2 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index bcf4437214f..a0dddc3b492 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1591,7 +1591,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev, * RETURNS: * 0 on success, AC_ERR_* mask on failure. */ -static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) +unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) { u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 }; struct ata_taskfile tf; @@ -1624,7 +1624,7 @@ static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) * RETURNS: * 0 on success, AC_ERR_* mask on failure */ -static unsigned int atapi_eh_request_sense(struct ata_device *dev, +unsigned int atapi_eh_request_sense(struct ata_device *dev, u8 *sense_buf, u8 dfl_sense_key) { u8 cdb[ATAPI_CDB_LEN] = @@ -4022,6 +4022,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) { unsigned long flags; int rc = 0; + struct ata_device *dev; /* are we suspending? */ spin_lock_irqsave(ap->lock, flags); @@ -4034,6 +4035,15 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); + /* + * If we have a ZPODD attached, check its zero + * power ready status before the port is frozen. + */ + ata_for_each_dev(dev, &ap->link, ENABLED) { + if (zpodd_dev_enabled(dev)) + zpodd_on_suspend(dev); + } + /* tell ACPI we're suspending */ rc = ata_acpi_on_suspend(ap); if (rc) diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 9a0d90d09d8..71dd48c94f2 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -1,10 +1,15 @@ #include <linux/libata.h> #include <linux/cdrom.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include <scsi/scsi_device.h> #include "libata.h" +static int zpodd_poweroff_delay = 30; /* 30 seconds for power off delay */ +module_param(zpodd_poweroff_delay, int, 0644); +MODULE_PARM_DESC(zpodd_poweroff_delay, "Poweroff delay for ZPODD in seconds"); + enum odd_mech_type { ODD_MECH_TYPE_SLOT, ODD_MECH_TYPE_DRAWER, @@ -18,6 +23,9 @@ struct zpodd { /* The following fields are synchronized by PM core. */ bool from_notify; /* resumed as a result of * acpi wake notification */ + bool zp_ready; /* ZP ready state */ + unsigned long last_ready; /* last ZP ready timestamp */ + bool zp_sampled; /* ZP ready state sampled */ }; /* Per the spec, only slot type and drawer type ODD can be supported */ @@ -74,6 +82,73 @@ static bool odd_can_poweroff(struct ata_device *ata_dev) return acpi_device_can_poweroff(acpi_dev); } +/* Test if ODD is zero power ready by sense code */ +static bool zpready(struct ata_device *dev) +{ + u8 sense_key, *sense_buf; + unsigned int ret, asc, ascq, add_len; + struct zpodd *zpodd = dev->zpodd; + + ret = atapi_eh_tur(dev, &sense_key); + + if (!ret || sense_key != NOT_READY) + return false; + + sense_buf = dev->link->ap->sector_buf; + ret = atapi_eh_request_sense(dev, sense_buf, sense_key); + if (ret) + return false; + + /* sense valid */ + if ((sense_buf[0] & 0x7f) != 0x70) + return false; + + add_len = sense_buf[7]; + /* has asc and ascq */ + if (add_len < 6) + return false; + + asc = sense_buf[12]; + ascq = sense_buf[13]; + + if (zpodd->mech_type == ODD_MECH_TYPE_SLOT) + /* no media inside */ + return asc == 0x3a; + else + /* no media inside and door closed */ + return asc == 0x3a && ascq == 0x01; +} + +/* + * Update the zpodd->zp_ready field. This field will only be set + * if the ODD has stayed in ZP ready state for zpodd_poweroff_delay + * time, and will be used to decide if power off is allowed. If it + * is set, it will be cleared during resume from powered off state. + */ +void zpodd_on_suspend(struct ata_device *dev) +{ + struct zpodd *zpodd = dev->zpodd; + unsigned long expires; + + if (!zpready(dev)) { + zpodd->zp_sampled = false; + return; + } + + if (!zpodd->zp_sampled) { + zpodd->zp_sampled = true; + zpodd->last_ready = jiffies; + return; + } + + expires = zpodd->last_ready + + msecs_to_jiffies(zpodd_poweroff_delay * 1000); + if (time_before(jiffies, expires)) + return; + + zpodd->zp_ready = true; +} + static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) { struct ata_device *ata_dev = context; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a21740b4ee1..b9b2bb1d5dc 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -182,6 +182,9 @@ extern void ata_eh_finish(struct ata_port *ap); extern int ata_ering_map(struct ata_ering *ering, int (*map_fn)(struct ata_ering_entry *, void *), void *arg); +extern unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key); +extern unsigned int atapi_eh_request_sense(struct ata_device *dev, + u8 *sense_buf, u8 dfl_sense_key); /* libata-pmp.c */ #ifdef CONFIG_SATA_PMP @@ -238,10 +241,12 @@ static inline bool zpodd_dev_enabled(struct ata_device *dev) { return dev->zpodd != NULL; } +void zpodd_on_suspend(struct ata_device *dev); #else /* CONFIG_SATA_ZPODD */ static inline void zpodd_init(struct ata_device *dev) {} static inline void zpodd_exit(struct ata_device *dev) {} static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } +static inline void zpodd_on_suspend(struct ata_device *dev) {} #endif /* CONFIG_SATA_ZPODD */ #endif /* __LIBATA_H__ */ -- cgit v1.2.3-18-g5258 From 213342053db58eabdaddff9c036c2b81ca63c443 Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:21:01 +0800 Subject: libata: handle power transition of ODD When ata port is runtime suspended, it will check if the ODD attched to it is a zero power(ZP) capable ODD and if the ZP capable ODD is in zero power ready state. And if this is not the case, the highest acpi state will be limited to ACPI_STATE_D3_HOT to avoid powering off the ODD. And if the ODD can be powered off, runtime wake capability needs to be enabled and powered_off flag will be set to let resume code knows that the ODD was in powered off state. And on resume, before it is powered on, if it was powered off during suspend, runtime wake capability needs to be disabled. After it is recovered, the ODD is considered functional, post power on processing like eject tray if the ODD is drawer type is done, and several ZPODD related fields will also be reset. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-acpi.c | 35 +++++++++++++------ drivers/ata/libata-eh.c | 2 ++ drivers/ata/libata-zpodd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 8 +++++ 4 files changed, 118 insertions(+), 10 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 446b4e761af..6f72c648ea1 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -835,6 +835,22 @@ void ata_acpi_on_resume(struct ata_port *ap) } } +static int ata_acpi_choose_suspend_state(struct ata_device *dev) +{ + int d_max_in = ACPI_STATE_D3_COLD; + + /* + * For ATAPI, runtime D3 cold is only allowed + * for ZPODD in zero power ready state + */ + if (dev->class == ATA_DEV_ATAPI && + !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) + d_max_in = ACPI_STATE_D3_HOT; + + return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev, + NULL, d_max_in); +} + /** * ata_acpi_set_state - set the port power state * @ap: target ATA port @@ -861,17 +877,16 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) continue; if (state.event != PM_EVENT_ON) { - acpi_state = acpi_pm_device_sleep_state( - &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3); - if (acpi_state > 0) - acpi_bus_set_power(handle, acpi_state); - /* TBD: need to check if it's runtime pm request */ - acpi_pm_device_run_wake( - &dev->sdev->sdev_gendev, true); + acpi_state = ata_acpi_choose_suspend_state(dev); + if (acpi_state == ACPI_STATE_D0) + continue; + if (zpodd_dev_enabled(dev) && + acpi_state == ACPI_STATE_D3_COLD) + zpodd_enable_run_wake(dev); + acpi_bus_set_power(handle, acpi_state); } else { - /* Ditto */ - acpi_pm_device_run_wake( - &dev->sdev->sdev_gendev, false); + if (zpodd_dev_enabled(dev)) + zpodd_disable_run_wake(dev); acpi_bus_set_power(handle, ACPI_STATE_D0); } } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a0dddc3b492..50f3ef04809 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, rc = atapi_eh_clear_ua(dev); if (rc) goto rest_fail; + if (zpodd_dev_enabled(dev)) + zpodd_post_poweron(dev); } } diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 71dd48c94f2..1f5d52ae397 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -26,8 +26,26 @@ struct zpodd { bool zp_ready; /* ZP ready state */ unsigned long last_ready; /* last ZP ready timestamp */ bool zp_sampled; /* ZP ready state sampled */ + bool powered_off; /* ODD is powered off + * during suspend */ }; +static int eject_tray(struct ata_device *dev) +{ + struct ata_taskfile tf = {}; + const char cdb[] = { GPCMD_START_STOP_UNIT, + 0, 0, 0, + 0x02, /* LoEj */ + 0, 0, 0, 0, 0, 0, 0, + }; + + tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.command = ATA_CMD_PACKET; + tf.protocol = ATAPI_PROT_NODATA; + + return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0); +} + /* Per the spec, only slot type and drawer type ODD can be supported */ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) { @@ -149,6 +167,71 @@ void zpodd_on_suspend(struct ata_device *dev) zpodd->zp_ready = true; } +bool zpodd_zpready(struct ata_device *dev) +{ + struct zpodd *zpodd = dev->zpodd; + return zpodd->zp_ready; +} + +/* + * Enable runtime wake capability through ACPI and set the powered_off flag, + * this flag will be used during resume to decide what operations are needed + * to take. + */ +void zpodd_enable_run_wake(struct ata_device *dev) +{ + struct zpodd *zpodd = dev->zpodd; + + zpodd->powered_off = true; + device_set_run_wake(&dev->sdev->sdev_gendev, true); + acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true); +} + +/* Disable runtime wake capability if it is enabled */ +void zpodd_disable_run_wake(struct ata_device *dev) +{ + struct zpodd *zpodd = dev->zpodd; + + if (zpodd->powered_off) { + acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false); + device_set_run_wake(&dev->sdev->sdev_gendev, false); + } +} + +/* + * Post power on processing after the ODD has been recovered. If the + * ODD wasn't powered off during suspend, it doesn't do anything. + * + * For drawer type ODD, if it is powered on due to user pressed the + * eject button, the tray needs to be ejected. This can only be done + * after the ODD has been recovered, i.e. link is initialized and + * device is able to process NON_DATA PIO command, as eject needs to + * send command for the ODD to process. + * + * The from_notify flag set in wake notification handler function + * zpodd_wake_dev represents if power on is due to user's action. + * + * For both types of ODD, several fields need to be reset. + */ +void zpodd_post_poweron(struct ata_device *dev) +{ + struct zpodd *zpodd = dev->zpodd; + + if (!zpodd->powered_off) + return; + + zpodd->powered_off = false; + + if (zpodd->from_notify) { + zpodd->from_notify = false; + if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER) + eject_tray(dev); + } + + zpodd->zp_sampled = false; + zpodd->zp_ready = false; +} + static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) { struct ata_device *ata_dev = context; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index b9b2bb1d5dc..c949dd311b2 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -242,11 +242,19 @@ static inline bool zpodd_dev_enabled(struct ata_device *dev) return dev->zpodd != NULL; } void zpodd_on_suspend(struct ata_device *dev); +bool zpodd_zpready(struct ata_device *dev); +void zpodd_enable_run_wake(struct ata_device *dev); +void zpodd_disable_run_wake(struct ata_device *dev); +void zpodd_post_poweron(struct ata_device *dev); #else /* CONFIG_SATA_ZPODD */ static inline void zpodd_init(struct ata_device *dev) {} static inline void zpodd_exit(struct ata_device *dev) {} static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } static inline void zpodd_on_suspend(struct ata_device *dev) {} +static inline bool zpodd_zpready(struct ata_device *dev) { return false; } +static inline void zpodd_enable_run_wake(struct ata_device *dev) {} +static inline void zpodd_disable_run_wake(struct ata_device *dev) {} +static inline void zpodd_post_poweron(struct ata_device *dev) {} #endif /* CONFIG_SATA_ZPODD */ #endif /* __LIBATA_H__ */ -- cgit v1.2.3-18-g5258 From a59b9aae230316134597775c6202cf28f6da0333 Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:21:02 +0800 Subject: libata: expose pm qos flags for ata device Expose pm qos flags to user space so that user has a chance to disable ZPODD feature, if he/she has a broken platform or devices or simply does not like this feature. This flag is exposed to user space only for ZPODD devices. Due to this flag, it is possible the ODD is ZP ready but we didn't power it off. So the zp_ready flag will need to be cleared whenever we found the ODD is not in ZP ready state. Previously, once zp_ready is set, the ODD will always be powered off and the flag will be cleared in post_poweron. But this is no longer the case now. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-acpi.c | 3 +++ drivers/ata/libata-zpodd.c | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 6f72c648ea1..97094496127 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> #include <scsi/scsi_device.h> #include "libata.h" @@ -1022,6 +1023,8 @@ static void ata_acpi_unregister_power_resource(struct ata_device *dev) void ata_acpi_bind(struct ata_device *dev) { ata_acpi_register_power_resource(dev); + if (zpodd_dev_enabled(dev)) + dev_pm_qos_expose_flags(&dev->sdev->sdev_gendev, 0); } void ata_acpi_unbind(struct ata_device *dev) diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 1f5d52ae397..540b0b7904f 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -150,6 +150,7 @@ void zpodd_on_suspend(struct ata_device *dev) if (!zpready(dev)) { zpodd->zp_sampled = false; + zpodd->zp_ready = false; return; } -- cgit v1.2.3-18-g5258 From 7e15e9be37eb834aaaca69030064ac97eaf5df2f Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Tue, 15 Jan 2013 17:21:04 +0800 Subject: libata: do not suspend port if normal ODD is attached For ODDs, the upper layer will poll for media change every few seconds, which will make it enter and leave suspend state very often. And as each suspend will also cause a hard/soft reset, the gain of runtime suspend is very little while the ODD may malfunction after constantly being reset. So the idle callback here will not proceed to suspend if a non-ZPODD capable ODD is attached to the port. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c7ecd8492f1..b7eed827daa 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5413,8 +5413,27 @@ static int ata_port_resume(struct device *dev) return rc; } +/* + * For ODDs, the upper layer will poll for media change every few seconds, + * which will make it enter and leave suspend state every few seconds. And + * as each suspend will cause a hard/soft reset, the gain of runtime suspend + * is very little and the ODD may malfunction after constantly being reset. + * So the idle callback here will not proceed to suspend if a non-ZPODD capable + * ODD is attached to the port. + */ static int ata_port_runtime_idle(struct device *dev) { + struct ata_port *ap = to_ata_port(dev); + struct ata_link *link; + struct ata_device *adev; + + ata_for_each_link(link, ap, HOST_FIRST) { + ata_for_each_dev(adev, link, ENABLED) + if (adev->class == ATA_DEV_ATAPI && + !zpodd_dev_enabled(adev)) + return -EBUSY; + } + return pm_runtime_suspend(dev); } -- cgit v1.2.3-18-g5258 From e175435ed281d06ffd56d4edc8a2dd56f8672f07 Mon Sep 17 00:00:00 2001 From: Jeff Garzik <jeff@garzik.org> Date: Fri, 25 Jan 2013 15:30:23 -0500 Subject: Revert "libata: export host controller number thru /sys" This reverts commit 1757d902b029a29dfcef63609964385cf8865b5a. Discussion continues upstream. --- drivers/ata/libata-core.c | 4 ---- drivers/ata/libata-transport.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b7eed827daa..4b6fb48eb83 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -99,7 +99,6 @@ static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); atomic_t ata_print_id = ATOMIC_INIT(0); -atomic_t host_print_id = ATOMIC_INIT(0); struct ata_force_param { const char *name; @@ -6119,9 +6118,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = host->n_ports; host->ports[i]; i++) kfree(host->ports[i]); - /* track host controller */ - host->host_id = atomic_inc_return(&host_print_id); - /* give ports names and add SCSI hosts */ for (i = 0; i < host->n_ports; i++) host->ports[i]->print_id = atomic_inc_return(&ata_print_id); diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 61dca7a20a3..c04d393d20c 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -284,7 +284,7 @@ int ata_tport_add(struct device *parent, dev->parent = get_device(parent); dev->release = ata_tport_release; - dev_set_name(dev, "ata%d.%d", ap->host->host_id, ap->print_id); + dev_set_name(dev, "ata%d", ap->print_id); transport_setup_device(dev); error = device_add(dev); if (error) { -- cgit v1.2.3-18-g5258 From a7ff60dbe0858496531c75b1544666c099a2b200 Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Fri, 25 Jan 2013 14:29:35 +0800 Subject: [libata] pm: differentiate system and runtime pm for ata port We need to do different things for system PM and runtime PM, e.g. we do not need to enable runtime wake for ZPODD when we are doing system suspend, etc. Currently, we use PMSG_SUSPEND for both system suspend and runtime suspend and PMSG_ON for both system resume and runtime resume. Change this by using PMSG_AUTO_SUSPEND for runtime suspend and PMSG_AUTO_RESUME for runtime resume. And since PMSG_ON means no transition, it is changed to PMSG_RESUME for ata port's system resume. The ata_acpi_set_state is modified accordingly, and the sata case and pata case is seperated for easy reading. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-acpi.c | 76 +++++++++++++++++++++++++++++++++-------------- drivers/ata/libata-core.c | 29 ++++++++++++------ drivers/ata/libata-eh.c | 17 ++++++----- 3 files changed, 83 insertions(+), 39 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 97094496127..dfd529a30c2 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -836,9 +836,11 @@ void ata_acpi_on_resume(struct ata_port *ap) } } -static int ata_acpi_choose_suspend_state(struct ata_device *dev) +static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime) { int d_max_in = ACPI_STATE_D3_COLD; + if (!runtime) + goto out; /* * For ATAPI, runtime D3 cold is only allowed @@ -848,53 +850,81 @@ static int ata_acpi_choose_suspend_state(struct ata_device *dev) !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) d_max_in = ACPI_STATE_D3_HOT; +out: return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev, NULL, d_max_in); } -/** - * ata_acpi_set_state - set the port power state - * @ap: target ATA port - * @state: state, on/off - * - * This function executes the _PS0/_PS3 ACPI method to set the power state. - * ACPI spec requires _PS0 when IDE power on and _PS3 when power off - */ -void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state) { + bool runtime = PMSG_IS_AUTO(state); struct ata_device *dev; acpi_handle handle; int acpi_state; - /* channel first and then drives for power on and vica versa - for power off */ - handle = ata_ap_acpi_handle(ap); - if (handle && state.event == PM_EVENT_ON) - acpi_bus_set_power(handle, ACPI_STATE_D0); - ata_for_each_dev(dev, &ap->link, ENABLED) { handle = ata_dev_acpi_handle(dev); if (!handle) continue; - if (state.event != PM_EVENT_ON) { - acpi_state = ata_acpi_choose_suspend_state(dev); + if (!(state.event & PM_EVENT_RESUME)) { + acpi_state = ata_acpi_choose_suspend_state(dev, runtime); if (acpi_state == ACPI_STATE_D0) continue; - if (zpodd_dev_enabled(dev) && + if (runtime && zpodd_dev_enabled(dev) && acpi_state == ACPI_STATE_D3_COLD) zpodd_enable_run_wake(dev); acpi_bus_set_power(handle, acpi_state); } else { - if (zpodd_dev_enabled(dev)) + if (runtime && zpodd_dev_enabled(dev)) zpodd_disable_run_wake(dev); acpi_bus_set_power(handle, ACPI_STATE_D0); } } +} + +/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */ +static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + struct ata_device *dev; + acpi_handle port_handle; + + port_handle = ata_ap_acpi_handle(ap); + if (!port_handle) + return; + + /* channel first and then drives for power on and vica versa + for power off */ + if (state.event & PM_EVENT_RESUME) + acpi_bus_set_power(port_handle, ACPI_STATE_D0); + + ata_for_each_dev(dev, &ap->link, ENABLED) { + acpi_handle dev_handle = ata_dev_acpi_handle(dev); + if (!dev_handle) + continue; + + acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ? + ACPI_STATE_D0 : ACPI_STATE_D3); + } + + if (!(state.event & PM_EVENT_RESUME)) + acpi_bus_set_power(port_handle, ACPI_STATE_D3); +} - handle = ata_ap_acpi_handle(ap); - if (handle && state.event != PM_EVENT_ON) - acpi_bus_set_power(handle, ACPI_STATE_D3); +/** + * ata_acpi_set_state - set the port power state + * @ap: target ATA port + * @state: state, on/off + * + * This function sets a proper ACPI D state for the device on + * system and runtime PM operations. + */ +void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + if (ap->flags & ATA_FLAG_ACPI_SATA) + sata_acpi_set_state(ap, state); + else + pata_acpi_set_state(ap, state); } /** diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4b6fb48eb83..b7c972dc8b9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5344,7 +5344,7 @@ static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int * * http://thread.gmane.org/gmane.linux.ide/46764 */ - if (mesg.event == PM_EVENT_SUSPEND) + if (mesg.event & PM_EVENT_SUSPEND) ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY; rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async); @@ -5382,27 +5382,28 @@ static int ata_port_poweroff(struct device *dev) return ata_port_suspend_common(dev, PMSG_HIBERNATE); } -static int __ata_port_resume_common(struct ata_port *ap, int *async) +static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg, + int *async) { int rc; - rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET, + rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET, ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async); return rc; } -static int ata_port_resume_common(struct device *dev) +static int ata_port_resume_common(struct device *dev, pm_message_t mesg) { struct ata_port *ap = to_ata_port(dev); - return __ata_port_resume_common(ap, NULL); + return __ata_port_resume_common(ap, mesg, NULL); } static int ata_port_resume(struct device *dev) { int rc; - rc = ata_port_resume_common(dev); + rc = ata_port_resume_common(dev, PMSG_RESUME); if (!rc) { pm_runtime_disable(dev); pm_runtime_set_active(dev); @@ -5436,6 +5437,16 @@ static int ata_port_runtime_idle(struct device *dev) return pm_runtime_suspend(dev); } +static int ata_port_runtime_suspend(struct device *dev) +{ + return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND); +} + +static int ata_port_runtime_resume(struct device *dev) +{ + return ata_port_resume_common(dev, PMSG_AUTO_RESUME); +} + static const struct dev_pm_ops ata_port_pm_ops = { .suspend = ata_port_suspend, .resume = ata_port_resume, @@ -5444,8 +5455,8 @@ static const struct dev_pm_ops ata_port_pm_ops = { .poweroff = ata_port_poweroff, .restore = ata_port_resume, - .runtime_suspend = ata_port_suspend, - .runtime_resume = ata_port_resume_common, + .runtime_suspend = ata_port_runtime_suspend, + .runtime_resume = ata_port_runtime_resume, .runtime_idle = ata_port_runtime_idle, }; @@ -5462,7 +5473,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend); int ata_sas_port_async_resume(struct ata_port *ap, int *async) { - return __ata_port_resume_common(ap, async); + return __ata_port_resume_common(ap, PMSG_RESUME, async); } EXPORT_SYMBOL_GPL(ata_sas_port_async_resume); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 50f3ef04809..f9476fb3ac4 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -4029,7 +4029,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) /* are we suspending? */ spin_lock_irqsave(ap->lock, flags); if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || - ap->pm_mesg.event == PM_EVENT_ON) { + ap->pm_mesg.event & PM_EVENT_RESUME) { spin_unlock_irqrestore(ap->lock, flags); return; } @@ -4040,10 +4040,13 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) /* * If we have a ZPODD attached, check its zero * power ready status before the port is frozen. + * Only needed for runtime suspend. */ - ata_for_each_dev(dev, &ap->link, ENABLED) { - if (zpodd_dev_enabled(dev)) - zpodd_on_suspend(dev); + if (PMSG_IS_AUTO(ap->pm_mesg)) { + ata_for_each_dev(dev, &ap->link, ENABLED) { + if (zpodd_dev_enabled(dev)) + zpodd_on_suspend(dev); + } } /* tell ACPI we're suspending */ @@ -4057,7 +4060,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) if (ap->ops->port_suspend) rc = ap->ops->port_suspend(ap, ap->pm_mesg); - ata_acpi_set_state(ap, PMSG_SUSPEND); + ata_acpi_set_state(ap, ap->pm_mesg); out: /* report result */ spin_lock_irqsave(ap->lock, flags); @@ -4097,7 +4100,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) /* are we resuming? */ spin_lock_irqsave(ap->lock, flags); if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || - ap->pm_mesg.event != PM_EVENT_ON) { + !(ap->pm_mesg.event & PM_EVENT_RESUME)) { spin_unlock_irqrestore(ap->lock, flags); return; } @@ -4116,7 +4119,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) ata_for_each_dev(dev, link, ALL) ata_ering_clear(&dev->ering); - ata_acpi_set_state(ap, PMSG_ON); + ata_acpi_set_state(ap, ap->pm_mesg); if (ap->ops->port_resume) rc = ap->ops->port_resume(ap); -- cgit v1.2.3-18-g5258 From f5e6d0d0eb819cbe1a68b9561c8e83fbd1a6d13a Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Fri, 25 Jan 2013 14:32:25 +0800 Subject: [libata] PM code cleanup for ata port For system freeze, if the port is already runtime suspended, leave it alone and just return. The port will be resumed on thaw before it will be used. And since we will call get_noresume for every device during prepare phase, and the port is resumed during thaw phase, it can't be in runtime suspended state during the poweroff phase. So remove the runtime_suspended check in poweroff callback. And for all suspend(freeze/suspend/poweroff/etc.), there is no need to touch the device, so set no_autopsy and no_recovery for them all. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-core.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b7c972dc8b9..497adea1f0d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5333,9 +5333,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async) { - unsigned int ehi_flags = ATA_EHI_QUIET; - int rc; - /* * On some hardware, device fails to respond after spun down * for suspend. As the device won't be used before being @@ -5344,11 +5341,9 @@ static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int * * http://thread.gmane.org/gmane.linux.ide/46764 */ - if (mesg.event & PM_EVENT_SUSPEND) - ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY; - - rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async); - return rc; + unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY | + ATA_EHI_NO_RECOVERY; + return ata_port_request_pm(ap, mesg, 0, ehi_flags, async); } static int ata_port_suspend_common(struct device *dev, pm_message_t mesg) @@ -5369,16 +5364,13 @@ static int ata_port_suspend(struct device *dev) static int ata_port_do_freeze(struct device *dev) { if (pm_runtime_suspended(dev)) - pm_runtime_resume(dev); + return 0; return ata_port_suspend_common(dev, PMSG_FREEZE); } static int ata_port_poweroff(struct device *dev) { - if (pm_runtime_suspended(dev)) - return 0; - return ata_port_suspend_common(dev, PMSG_HIBERNATE); } -- cgit v1.2.3-18-g5258 From aaa515277db9585eeb4fdeb4637b9f9df50a1dd9 Mon Sep 17 00:00:00 2001 From: Seth Heasley <seth.heasley@intel.com> Date: Fri, 25 Jan 2013 11:57:05 -0800 Subject: ata_piix: IDE-mode SATA patch for Intel Avoton DeviceIDs This patch adds the IDE-mode SATA DeviceIDs for the Intel Avoton SOC. Signed-off-by: Seth Heasley <seth.heasley@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/ata_piix.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 174eca609b4..651fa85f173 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -317,6 +317,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (DH89xxCC) */ { 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Avoton) */ + { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; -- cgit v1.2.3-18-g5258 From 29e674dd5c8e781589f09c3ee139c80f6da274e4 Mon Sep 17 00:00:00 2001 From: Seth Heasley <seth.heasley@intel.com> Date: Fri, 25 Jan 2013 12:01:05 -0800 Subject: ahci: AHCI-mode SATA patch for Intel Avoton DeviceIDs This patch adds the AHCI and RAID-mode SATA DeviceIDs for the Intel Avoton SOC. Signed-off-by: Seth Heasley <seth.heasley@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/ahci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 49791273256..083b90e80d2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -265,6 +265,22 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */ + { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3-18-g5258 From 6f4c827e68a78731c6c75df69bf7b75b029ec70c Mon Sep 17 00:00:00 2001 From: Aaron Lu <aaron.lu@intel.com> Date: Wed, 23 Jan 2013 15:09:32 +0800 Subject: [libata] scsi: no poll when ODD is powered off When the ODD is powered off, any action the user did to the ODD that would generate a media event will trigger an ACPI interrupt, so the poll for media event is no longer necessary. And the poll will also cause a runtime status change, which will stop the ODD from staying in powered off state, so the poll should better be stopped. But since we don't have access to the gendisk structure in LLDs, here comes the disk_events_disable_depth for scsi device. This field is a hint set by LLDs to convey information to upper layer drivers. A value of 0 means media poll is necessary for the device, while values above 0 means media poll is not needed and should better be skipped. So we can increase its value when we are to power off the ODD in ATA layer and decrease its value when the ODD is powered on, effectively silence the media events poll. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-zpodd.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 540b0b7904f..a7df6038353 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -178,11 +178,16 @@ bool zpodd_zpready(struct ata_device *dev) * Enable runtime wake capability through ACPI and set the powered_off flag, * this flag will be used during resume to decide what operations are needed * to take. + * + * Also, media poll needs to be silenced, so that it doesn't bring the ODD + * back to full power state every few seconds. */ void zpodd_enable_run_wake(struct ata_device *dev) { struct zpodd *zpodd = dev->zpodd; + sdev_disable_disk_events(dev->sdev); + zpodd->powered_off = true; device_set_run_wake(&dev->sdev->sdev_gendev, true); acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true); @@ -231,6 +236,8 @@ void zpodd_post_poweron(struct ata_device *dev) zpodd->zp_sampled = false; zpodd->zp_ready = false; + + sdev_enable_disk_events(dev->sdev); } static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) -- cgit v1.2.3-18-g5258 From 3aee8bc52c415aba8148f144e5e5359b0fd75dd1 Mon Sep 17 00:00:00 2001 From: James Ralston <james.d.ralston@intel.com> Date: Fri, 8 Feb 2013 17:24:12 -0800 Subject: ata_piix: Add Device IDs for Intel Wellsburg PCH This patch adds the IDE-mode SATA Device IDs for the Intel Wellsburg PCH Signed-off-by: James Ralston <james.d.ralston@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/ata_piix.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 651fa85f173..d2ba439cfe5 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -325,6 +325,15 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Avoton) */ { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Wellsburg) */ + { 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + { } /* terminate list */ }; -- cgit v1.2.3-18-g5258 From 151743fd8dfb02956c5184b5f4f0f42677eb75bc Mon Sep 17 00:00:00 2001 From: James Ralston <james.d.ralston@intel.com> Date: Fri, 8 Feb 2013 17:34:47 -0800 Subject: ahci: Add Device IDs for Intel Wellsburg PCH This patch adds the AHCI-mode SATA Device IDs for the Intel Wellsburg PCH Signed-off-by: James Ralston <james.d.ralston@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/ahci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 083b90e80d2..72e3e126d38 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -281,6 +281,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */ + { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ + { PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */ + { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */ + { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3-18-g5258 From 163cf81d266f017d718ef786fbbb6b2513ce7ec3 Mon Sep 17 00:00:00 2001 From: Vladimir Barinov <vladimir.barinov@cogentembedded.com> Date: Wed, 20 Feb 2013 23:10:29 +0300 Subject: libata: add R-Car SATA driver Add Renesas R-Car on-chip 3Gbps SATA controller driver. Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> [Sergei: few bugs fixed, significant cleanup] Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/Kconfig | 8 + drivers/ata/Makefile | 1 + drivers/ata/sata_rcar.c | 910 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 919 insertions(+) create mode 100644 drivers/ata/sata_rcar.c (limited to 'drivers/ata') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 996d16c9c6e..9b58d32dced 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -260,6 +260,14 @@ config SATA_PROMISE If unsure, say N. +config SATA_RCAR + tristate "Renesas R-Car SATA support" + depends on ARCH_SHMOBILE && ARCH_R8A7779 + help + This option enables support for Renesas R-Car Serial ATA. + + If unsure, say N. + config SATA_SIL tristate "Silicon Image SATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 85e3de463ed..c04d0fd038a 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_ATA_PIIX) += ata_piix.o obj-$(CONFIG_SATA_MV) += sata_mv.o obj-$(CONFIG_SATA_NV) += sata_nv.o obj-$(CONFIG_SATA_PROMISE) += sata_promise.o +obj-$(CONFIG_SATA_RCAR) += sata_rcar.o obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_SATA_SIS) += sata_sis.o obj-$(CONFIG_SATA_SVW) += sata_svw.o diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c new file mode 100644 index 00000000000..caf33f620c3 --- /dev/null +++ b/drivers/ata/sata_rcar.c @@ -0,0 +1,910 @@ +/* + * Renesas R-Car SATA driver + * + * Author: Vladimir Barinov <source@cogentembedded.com> + * Copyright (C) 2013 Cogent Embedded, Inc. + * Copyright (C) 2013 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#define DRV_NAME "sata_rcar" + +/* SH-Navi2G/ATAPI-ATA compatible task registers */ +#define DATA_REG 0x100 +#define SDEVCON_REG 0x138 + +/* SH-Navi2G/ATAPI module compatible control registers */ +#define ATAPI_CONTROL1_REG 0x180 +#define ATAPI_STATUS_REG 0x184 +#define ATAPI_INT_ENABLE_REG 0x188 +#define ATAPI_DTB_ADR_REG 0x198 +#define ATAPI_DMA_START_ADR_REG 0x19C +#define ATAPI_DMA_TRANS_CNT_REG 0x1A0 +#define ATAPI_CONTROL2_REG 0x1A4 +#define ATAPI_SIG_ST_REG 0x1B0 +#define ATAPI_BYTE_SWAP_REG 0x1BC + +/* ATAPI control 1 register (ATAPI_CONTROL1) bits */ +#define ATAPI_CONTROL1_ISM BIT(16) +#define ATAPI_CONTROL1_DTA32M BIT(11) +#define ATAPI_CONTROL1_RESET BIT(7) +#define ATAPI_CONTROL1_DESE BIT(3) +#define ATAPI_CONTROL1_RW BIT(2) +#define ATAPI_CONTROL1_STOP BIT(1) +#define ATAPI_CONTROL1_START BIT(0) + +/* ATAPI status register (ATAPI_STATUS) bits */ +#define ATAPI_STATUS_SATAINT BIT(11) +#define ATAPI_STATUS_DNEND BIT(6) +#define ATAPI_STATUS_DEVTRM BIT(5) +#define ATAPI_STATUS_DEVINT BIT(4) +#define ATAPI_STATUS_ERR BIT(2) +#define ATAPI_STATUS_NEND BIT(1) +#define ATAPI_STATUS_ACT BIT(0) + +/* Interrupt enable register (ATAPI_INT_ENABLE) bits */ +#define ATAPI_INT_ENABLE_SATAINT BIT(11) +#define ATAPI_INT_ENABLE_DNEND BIT(6) +#define ATAPI_INT_ENABLE_DEVTRM BIT(5) +#define ATAPI_INT_ENABLE_DEVINT BIT(4) +#define ATAPI_INT_ENABLE_E