diff options
Diffstat (limited to 'drivers/ata/libata-acpi.c')
| -rw-r--r-- | drivers/ata/libata-acpi.c | 393 | 
1 files changed, 208 insertions, 185 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 8b5ea399a4f..97a14fe47de 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -16,11 +16,10 @@  #include <linux/libata.h>  #include <linux/pci.h>  #include <linux/slab.h> +#include <linux/pm_runtime.h>  #include <scsi/scsi_device.h>  #include "libata.h" -#include <acpi/acpi_bus.h> -  unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;  module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);  MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)"); @@ -33,76 +32,34 @@ struct ata_acpi_gtf {  	u8	tf[REGS_PER_GTF];	/* regs. 0x1f1 - 0x1f7 */  } __packed; -/* - *	Helper - belongs in the PCI layer somewhere eventually - */ -static int is_pci_dev(struct device *dev) -{ -	return (dev->bus == &pci_bus_type); -} -  static void ata_acpi_clear_gtf(struct ata_device *dev)  {  	kfree(dev->gtf_cache);  	dev->gtf_cache = NULL;  } +struct ata_acpi_hotplug_context { +	struct acpi_hotplug_context hp; +	union { +		struct ata_port *ap; +		struct ata_device *dev; +	} data; +}; + +#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data) +  /** - * ata_acpi_associate_sata_port - associate SATA port with ACPI objects - * @ap: target SATA port + * ata_dev_acpi_handle - provide the acpi_handle for an ata_device + * @dev: the acpi_handle returned will correspond to this device   * - * Look up ACPI objects associated with @ap and initialize acpi_handle - * fields of @ap, the port and devices accordingly. - * - * LOCKING: - * EH context. - * - * RETURNS: - * 0 on success, -errno on failure. + * Returns the acpi_handle for the ACPI namespace object corresponding to + * the ata_device passed into the function, or NULL if no such object exists + * or ACPI is disabled for this device due to consecutive errors.   */ -void ata_acpi_associate_sata_port(struct ata_port *ap) -{ -	WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); - -	if (!sata_pmp_attached(ap)) { -		u64 adr = SATA_ADR(ap->port_no, NO_PORT_MULT); - -		ap->link.device->acpi_handle = -			acpi_get_child(ap->host->acpi_handle, adr); -	} else { -		struct ata_link *link; - -		ap->link.device->acpi_handle = NULL; - -		ata_for_each_link(link, ap, EDGE) { -			u64 adr = SATA_ADR(ap->port_no, link->pmp); - -			link->device->acpi_handle = -				acpi_get_child(ap->host->acpi_handle, adr); -		} -	} -} - -static void ata_acpi_associate_ide_port(struct ata_port *ap) +acpi_handle ata_dev_acpi_handle(struct ata_device *dev)  { -	int max_devices, i; - -	ap->acpi_handle = acpi_get_child(ap->host->acpi_handle, ap->port_no); -	if (!ap->acpi_handle) -		return; - -	max_devices = 1; -	if (ap->flags & ATA_FLAG_SLAVE_POSS) -		max_devices++; - -	for (i = 0; i < max_devices; i++) { -		struct ata_device *dev = &ap->link.device[i]; - -		dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); -	} - -	if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) -		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; +	return dev->flags & ATA_DFLAG_ACPI_DISABLED ? +			NULL : ACPI_HANDLE(&dev->tdev);  }  /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ @@ -174,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,  		ata_port_wait_eh(ap);  } -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)  { -	struct ata_device *dev = data; - +	struct ata_device *dev = ata_hotplug_data(adev->hp).dev;  	ata_acpi_handle_hotplug(dev->link->ap, dev, event); +	return 0;  } -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)  { -	struct ata_port *ap = data; - -	ata_acpi_handle_hotplug(ap, NULL, event); +	ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event); +	return 0;  }  static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, @@ -207,75 +163,85 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,  	}  } -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)  { -	ata_acpi_uevent(data, NULL, event); +	ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);  } -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)  { -	struct ata_device *dev = data; +	struct ata_device *dev = ata_hotplug_data(adev->hp).dev;  	ata_acpi_uevent(dev->link->ap, dev, event);  } -static struct acpi_dock_ops ata_acpi_dev_dock_ops = { -	.handler = ata_acpi_dev_notify_dock, -	.uevent = ata_acpi_dev_uevent, -}; +/* bind acpi handle to pata port */ +void ata_acpi_bind_port(struct ata_port *ap) +{ +	struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); +	struct acpi_device *adev; +	struct ata_acpi_hotplug_context *context; -static struct acpi_dock_ops ata_acpi_ap_dock_ops = { -	.handler = ata_acpi_ap_notify_dock, -	.uevent = ata_acpi_ap_uevent, -}; +	if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) +		return; -/** - * ata_acpi_associate - associate ATA host with ACPI objects - * @host: target ATA host - * - * Look up ACPI objects associated with @host and initialize - * acpi_handle fields of @host, its ports and devices accordingly. - * - * LOCKING: - * EH context. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -void ata_acpi_associate(struct ata_host *host) -{ -	int i, j; +	acpi_preset_companion(&ap->tdev, host_companion, ap->port_no); -	if (!is_pci_dev(host->dev) || libata_noacpi) +	if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) +		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; + +	adev = ACPI_COMPANION(&ap->tdev); +	if (!adev || adev->hp)  		return; -	host->acpi_handle = DEVICE_ACPI_HANDLE(host->dev); -	if (!host->acpi_handle) +	context = kzalloc(sizeof(*context), GFP_KERNEL); +	if (!context)  		return; -	for (i = 0; i < host->n_ports; i++) { -		struct ata_port *ap = host->ports[i]; +	context->data.ap = ap; +	acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock, +				   ata_acpi_ap_uevent); +} + +void ata_acpi_bind_dev(struct ata_device *dev) +{ +	struct ata_port *ap = dev->link->ap; +	struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); +	struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); +	struct acpi_device *parent, *adev; +	struct ata_acpi_hotplug_context *context; +	u64 adr; -		if (host->ports[0]->flags & ATA_FLAG_ACPI_SATA) -			ata_acpi_associate_sata_port(ap); +	/* +	 * For both sata/pata devices, host companion device is required. +	 * For pata device, port companion device is also required. +	 */ +	if (libata_noacpi || !host_companion || +			(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion)) +		return; + +	if (ap->flags & ATA_FLAG_ACPI_SATA) { +		if (!sata_pmp_attached(ap)) +			adr = SATA_ADR(ap->port_no, NO_PORT_MULT);  		else -			ata_acpi_associate_ide_port(ap); +			adr = SATA_ADR(ap->port_no, dev->link->pmp); +		parent = host_companion; +	} else { +		adr = dev->devno; +		parent = port_companion; +	} -		if (ap->acpi_handle) { -			/* we might be on a docking station */ -			register_hotplug_dock_device(ap->acpi_handle, -					     &ata_acpi_ap_dock_ops, ap); -		} +	acpi_preset_companion(&dev->tdev, parent, adr); +	adev = ACPI_COMPANION(&dev->tdev); +	if (!adev || adev->hp) +		return; -		for (j = 0; j < ata_link_max_devices(&ap->link); j++) { -			struct ata_device *dev = &ap->link.device[j]; +	context = kzalloc(sizeof(*context), GFP_KERNEL); +	if (!context) +		return; -			if (dev->acpi_handle) { -				/* we might be on a docking station */ -				register_hotplug_dock_device(dev->acpi_handle, -					     &ata_acpi_dev_dock_ops, dev); -			} -		} -	} +	context->data.dev = dev; +	acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock, +				   ata_acpi_dev_uevent);  }  /** @@ -299,7 +265,7 @@ void ata_acpi_dissociate(struct ata_host *host)  		struct ata_port *ap = host->ports[i];  		const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); -		if (ap->acpi_handle && gtm) +		if (ACPI_HANDLE(&ap->tdev) && gtm)  			ata_acpi_stm(ap, gtm);  	}  } @@ -323,8 +289,12 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)  	union acpi_object *out_obj;  	acpi_status status;  	int rc = 0; +	acpi_handle handle = ACPI_HANDLE(&ap->tdev); -	status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output); +	if (!handle) +		return -EINVAL; + +	status = acpi_evaluate_object(handle, "_GTM", NULL, &output);  	rc = -ENOENT;  	if (status == AE_NOT_FOUND) @@ -332,25 +302,22 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)  	rc = -EINVAL;  	if (ACPI_FAILURE(status)) { -		ata_port_printk(ap, KERN_ERR, -				"ACPI get timing mode failed (AE 0x%x)\n", -				status); +		ata_port_err(ap, "ACPI get timing mode failed (AE 0x%x)\n", +			     status);  		goto out_free;  	}  	out_obj = output.pointer;  	if (out_obj->type != ACPI_TYPE_BUFFER) { -		ata_port_printk(ap, KERN_WARNING, -				"_GTM returned unexpected object type 0x%x\n", -				out_obj->type); +		ata_port_warn(ap, "_GTM returned unexpected object type 0x%x\n", +			      out_obj->type);  		goto out_free;  	}  	if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) { -		ata_port_printk(ap, KERN_ERR, -				"_GTM returned invalid length %d\n", -				out_obj->buffer.length); +		ata_port_err(ap, "_GTM returned invalid length %d\n", +			     out_obj->buffer.length);  		goto out_free;  	} @@ -397,13 +364,14 @@ int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm)  	input.count = 3;  	input.pointer = in_params; -	status = acpi_evaluate_object(ap->acpi_handle, "_STM", &input, NULL); +	status = acpi_evaluate_object(ACPI_HANDLE(&ap->tdev), "_STM", +				      &input, NULL);  	if (status == AE_NOT_FOUND)  		return -ENOENT;  	if (ACPI_FAILURE(status)) { -		ata_port_printk(ap, KERN_ERR, -			"ACPI set timing mode failed (status=0x%x)\n", status); +		ata_port_err(ap, "ACPI set timing mode failed (status=0x%x)\n", +			     status);  		return -EINVAL;  	}  	return 0; @@ -450,18 +418,18 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)  	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */  	if (ata_msg_probe(ap)) -		ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", -			       __func__, ap->port_no); +		ata_dev_dbg(dev, "%s: ENTER: port#: %d\n", +			    __func__, ap->port_no);  	/* _GTF has no input parameters */ -	status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); +	status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_GTF", NULL, +				      &output);  	out_obj = dev->gtf_cache = output.pointer;  	if (ACPI_FAILURE(status)) {  		if (status != AE_NOT_FOUND) { -			ata_dev_printk(dev, KERN_WARNING, -				       "_GTF evaluation failed (AE 0x%x)\n", -				       status); +			ata_dev_warn(dev, "_GTF evaluation failed (AE 0x%x)\n", +				     status);  			rc = -EINVAL;  		}  		goto out_free; @@ -469,27 +437,24 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)  	if (!output.length || !output.pointer) {  		if (ata_msg_probe(ap)) -			ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " -				"length or ptr is NULL (0x%llx, 0x%p)\n", -				__func__, -				(unsigned long long)output.length, -				output.pointer); +			ata_dev_dbg(dev, "%s: Run _GTF: length or ptr is NULL (0x%llx, 0x%p)\n", +				    __func__, +				    (unsigned long long)output.length, +				    output.pointer);  		rc = -EINVAL;  		goto out_free;  	}  	if (out_obj->type != ACPI_TYPE_BUFFER) { -		ata_dev_printk(dev, KERN_WARNING, -			       "_GTF unexpected object type 0x%x\n", -			       out_obj->type); +		ata_dev_warn(dev, "_GTF unexpected object type 0x%x\n", +			     out_obj->type);  		rc = -EINVAL;  		goto out_free;  	}  	if (out_obj->buffer.length % REGS_PER_GTF) { -		ata_dev_printk(dev, KERN_WARNING, -			       "unexpected _GTF length (%d)\n", -			       out_obj->buffer.length); +		ata_dev_warn(dev, "unexpected _GTF length (%d)\n", +			     out_obj->buffer.length);  		rc = -EINVAL;  		goto out_free;  	} @@ -499,9 +464,8 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)  	if (gtf) {  		*gtf = (void *)out_obj->buffer.pointer;  		if (ata_msg_probe(ap)) -			ata_dev_printk(dev, KERN_DEBUG, -				       "%s: returning gtf=%p, gtf_count=%d\n", -				       __func__, *gtf, rc); +			ata_dev_dbg(dev, "%s: returning gtf=%p, gtf_count=%d\n", +				    __func__, *gtf, rc);  	}  	return rc; @@ -660,8 +624,7 @@ static int ata_acpi_filter_tf(struct ata_device *dev,   * @dev: target ATA device   * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)   * - * Outputs ATA taskfile to standard ATA host controller using MMIO - * or PIO as indicated by the ATA_FLAG_MMIO flag. + * Outputs ATA taskfile to standard ATA host controller.   * Writes the control, feature, nsect, lbal, lbam, and lbah registers.   * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,   * hob_lbal, hob_lbam, and hob_lbah. @@ -812,8 +775,8 @@ static int ata_acpi_push_id(struct ata_device *dev)  	union acpi_object in_params[1];  	if (ata_msg_probe(ap)) -		ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", -			       __func__, dev->devno, ap->port_no); +		ata_dev_dbg(dev, "%s: ix = %d, port#: %d\n", +			    __func__, dev->devno, ap->port_no);  	/* Give the drive Identify data to the drive via the _SDD method */  	/* _SDD: set up input parameters */ @@ -826,15 +789,15 @@ static int ata_acpi_push_id(struct ata_device *dev)  	/* It's OK for _SDD to be missing too. */  	swap_buf_le16(dev->id, ATA_ID_WORDS); -	status = acpi_evaluate_object(dev->acpi_handle, "_SDD", &input, NULL); +	status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_SDD", &input, +				      NULL);  	swap_buf_le16(dev->id, ATA_ID_WORDS);  	if (status == AE_NOT_FOUND)  		return -ENOENT;  	if (ACPI_FAILURE(status)) { -		ata_dev_printk(dev, KERN_WARNING, -			       "ACPI _SDD failed (AE 0x%x)\n", status); +		ata_dev_warn(dev, "ACPI _SDD failed (AE 0x%x)\n", status);  		return -EIO;  	} @@ -877,7 +840,7 @@ void ata_acpi_on_resume(struct ata_port *ap)  	const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);  	struct ata_device *dev; -	if (ap->acpi_handle && gtm) { +	if (ACPI_HANDLE(&ap->tdev) && gtm) {  		/* _GTM valid */  		/* restore timing parameters */ @@ -890,6 +853,7 @@ void ata_acpi_on_resume(struct ata_port *ap)  		ata_for_each_dev(dev, &ap->link, ALL) {  			ata_acpi_clear_gtf(dev);  			if (ata_dev_enabled(dev) && +			    ata_dev_acpi_handle(dev) &&  			    ata_dev_get_GTF(dev, NULL) >= 0)  				dev->flags |= ATA_DFLAG_ACPI_PENDING;  		} @@ -906,34 +870,94 @@ void ata_acpi_on_resume(struct ata_port *ap)  	}  } -/** - * 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 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 +	 * 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; + +out: +	return acpi_pm_device_sleep_state(&dev->tdev, NULL, d_max_in); +} + +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; + +	ata_for_each_dev(dev, &ap->link, ENABLED) { +		handle = ata_dev_acpi_handle(dev); +		if (!handle) +			continue; + +		if (!(state.event & PM_EVENT_RESUME)) { +			acpi_state = ata_acpi_choose_suspend_state(dev, runtime); +			if (acpi_state == ACPI_STATE_D0) +				continue; +			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 (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; -	if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA)) +	port_handle = ACPI_HANDLE(&ap->tdev); +	if (!port_handle)  		return;  	/* channel first and then drives for power on and vica versa  	   for power off */ -	if (state.event == PM_EVENT_ON) -		acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0); +	if (state.event & PM_EVENT_RESUME) +		acpi_bus_set_power(port_handle, ACPI_STATE_D0);  	ata_for_each_dev(dev, &ap->link, ENABLED) { -		if (dev->acpi_handle) -			acpi_bus_set_power(dev->acpi_handle, -				state.event == PM_EVENT_ON ? -					ACPI_STATE_D0 : ACPI_STATE_D3); +		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_COLD);  	} -	if (state.event != PM_EVENT_ON) -		acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3); + +	if (!(state.event & PM_EVENT_RESUME)) +		acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD); +} + +/** + * 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);  }  /** @@ -958,7 +982,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)  	int nr_executed = 0;  	int rc; -	if (!dev->acpi_handle) +	if (!ata_dev_acpi_handle(dev))  		return 0;  	/* do we need to do _GTF? */ @@ -984,8 +1008,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev)  	if (nr_executed) {  		rc = ata_dev_reread_id(dev, 0);  		if (rc < 0) { -			ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " -				       "after ACPI commands\n"); +			ata_dev_err(dev, +				    "failed to IDENTIFY after ACPI commands\n");  			return rc;  		}  	} @@ -1003,9 +1027,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev)  		return rc;  	} -	ata_dev_printk(dev, KERN_WARNING, -		       "ACPI: failed the second time, disabled\n"); -	dev->acpi_handle = NULL; +	dev->flags |= ATA_DFLAG_ACPI_DISABLED; +	ata_dev_warn(dev, "ACPI: failed the second time, disabled\n");  	/* We can safely continue if no _GTF command has been executed  	 * and port is not frozen.  | 
