Beispiel #1
0
int acpi_bus_init_power(struct acpi_device *device)
{
	int state;
	int result;

	if (!device)
		return -EINVAL;

	device->power.state = ACPI_STATE_UNKNOWN;

	result = acpi_device_get_power(device, &state);
	if (result)
		return result;

	if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
		result = acpi_power_on_resources(device, state);
		if (result)
			return result;

		result = acpi_dev_pm_explicit_set(device, state);
		if (result)
			return result;
	} else if (state == ACPI_STATE_UNKNOWN) {
		/* No power resources and missing _PSC? Try to force D0. */
		state = ACPI_STATE_D0;
		result = acpi_dev_pm_explicit_set(device, state);
		if (result)
			return result;
	}
	device->power.state = state;
	return 0;
}
Beispiel #2
0
/**
 * acpi_device_fix_up_power - Force device with missing _PSC into D0.
 * @device: Device object whose power state is to be fixed up.
 *
 * Devices without power resources and _PSC, but having _PS0 and _PS3 defined,
 * are assumed to be put into D0 by the BIOS.  However, in some cases that may
 * not be the case and this function should be used then.
 */
int acpi_device_fix_up_power(struct acpi_device *device)
{
	int ret = 0;

	if (!device->power.flags.power_resources
	    && !device->power.flags.explicit_get
	    && device->power.state == ACPI_STATE_D0)
		ret = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);

	return ret;
}
int acpi_bus_init_power(struct acpi_device *device)
{
	int state;
	int result;

	if (!device)
		return -EINVAL;

	device->power.state = ACPI_STATE_UNKNOWN;
	if (!acpi_device_is_present(device))
		return -ENXIO;

	result = acpi_device_get_power(device, &state);
	if (result)
		return result;

	if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
		/* Reference count the power resources. */
		result = acpi_power_on_resources(device, state);
		if (result)
			return result;

		if (state == ACPI_STATE_D0) {
			/*
			 * If _PSC is not present and the state inferred from
			 * power resources appears to be D0, it still may be
			 * necessary to execute _PS0 at this point, because
			 * another device using the same power resources may
			 * have been put into D0 previously and that's why we
			 * see D0 here.
			 */
			result = acpi_dev_pm_explicit_set(device, state);
			if (result)
				return result;
		}
	} else if (state == ACPI_STATE_UNKNOWN) {
		/*
		 * No power resources and missing _PSC?  Cross fingers and make
		 * it D0 in hope that this is what the BIOS put the device into.
		 * [We tried to force D0 here by executing _PS0, but that broke
		 * Toshiba P870-303 in a nasty way.]
		 */
		state = ACPI_STATE_D0;
	}
	device->power.state = state;
	return 0;
}
Beispiel #4
0
int acpi_bus_init_power(struct acpi_device *device)
{
	int state;
	int result;

	if (!device)
		return -EINVAL;

	device->power.state = ACPI_STATE_UNKNOWN;
	if (!acpi_device_is_present(device))
		return -ENXIO;

	result = acpi_device_get_power(device, &state);
	if (result)
		return result;

	if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
		result = acpi_power_on_resources(device, state);
		if (result)
			return result;

		result = acpi_dev_pm_explicit_set(device, state);
		if (result)
			return result;
	} else if (state == ACPI_STATE_UNKNOWN) {
		/*
		 * No power resources and missing _PSC?  Cross fingers and make
		 * it D0 in hope that this is what the BIOS put the device into.
		 * [We tried to force D0 here by executing _PS0, but that broke
		 * Toshiba P870-303 in a nasty way.]
		 */
		state = ACPI_STATE_D0;
	}
	device->power.state = state;
	return 0;
}
Beispiel #5
0
/**
 * acpi_device_set_power - Set power state of an ACPI device.
 * @device: Device to set the power state of.
 * @state: New power state to set.
 *
 * Callers must ensure that the device is power manageable before using this
 * function.
 */
int acpi_device_set_power(struct acpi_device *device, int state)
{
	int result = 0;
	bool cut_power = false;

	if (!device || !device->flags.power_manageable
	    || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
		return -EINVAL;

	/* Make sure this is a valid target state */

	if (state == device->power.state) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
				  device->pnp.bus_id,
				  acpi_power_state_string(state)));
		return 0;
	}

	if (!device->power.states[state].flags.valid) {
		dev_warn(&device->dev, "Power state %s not supported\n",
			 acpi_power_state_string(state));
		return -ENODEV;
	}
	if (!device->power.flags.ignore_parent &&
	    device->parent && (state < device->parent->power.state)) {
		dev_warn(&device->dev,
			 "Cannot transition to power state %s for parent in %s\n",
			 acpi_power_state_string(state),
			 acpi_power_state_string(device->parent->power.state));
		return -ENODEV;
	}

	/* For D3cold we should first transition into D3hot. */
	if (state == ACPI_STATE_D3_COLD
	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
		state = ACPI_STATE_D3_HOT;
		cut_power = true;
	}

	if (state < device->power.state && state != ACPI_STATE_D0
	    && device->power.state >= ACPI_STATE_D3_HOT) {
		dev_warn(&device->dev,
			 "Cannot transition to non-D0 state from D3\n");
		return -ENODEV;
	}

	/*
	 * Transition Power
	 * ----------------
	 * In accordance with the ACPI specification first apply power (via
	 * power resources) and then evaluate _PSx.
	 */
	if (device->power.flags.power_resources) {
		result = acpi_power_transition(device, state);
		if (result)
			goto end;
	}
	result = acpi_dev_pm_explicit_set(device, state);
	if (result)
		goto end;

	if (cut_power) {
		device->power.state = state;
		state = ACPI_STATE_D3_COLD;
		result = acpi_power_transition(device, state);
	}

 end:
	if (result) {
		dev_warn(&device->dev, "Failed to change power state to %s\n",
			 acpi_power_state_string(state));
	} else {
		device->power.state = state;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to %s\n",
				  device->pnp.bus_id,
				  acpi_power_state_string(state)));
	}

	return result;
}
/**
 * acpi_device_set_power - Set power state of an ACPI device.
 * @device: Device to set the power state of.
 * @state: New power state to set.
 *
 * Callers must ensure that the device is power manageable before using this
 * function.
 */
int acpi_device_set_power(struct acpi_device *device, int state)
{
	int target_state = state;
	int result = 0;

	if (!device || !device->flags.power_manageable
	    || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
		return -EINVAL;

	/* Make sure this is a valid target state */

	if (state == device->power.state) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
				  device->pnp.bus_id,
				  acpi_power_state_string(state)));
		return 0;
	}

	if (state == ACPI_STATE_D3_COLD) {
		/*
		 * For transitions to D3cold we need to execute _PS3 and then
		 * possibly drop references to the power resources in use.
		 */
		state = ACPI_STATE_D3_HOT;
		/* If _PR3 is not available, use D3hot as the target state. */
		if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid)
			target_state = state;
	} else if (!device->power.states[state].flags.valid) {
		dev_warn(&device->dev, "Power state %s not supported\n",
			 acpi_power_state_string(state));
		return -ENODEV;
	}

	if (!device->power.flags.ignore_parent &&
	    device->parent && (state < device->parent->power.state)) {
		dev_warn(&device->dev,
			 "Cannot transition to power state %s for parent in %s\n",
			 acpi_power_state_string(state),
			 acpi_power_state_string(device->parent->power.state));
		return -ENODEV;
	}

	/*
	 * Transition Power
	 * ----------------
	 * In accordance with ACPI 6, _PSx is executed before manipulating power
	 * resources, unless the target state is D0, in which case _PS0 is
	 * supposed to be executed after turning the power resources on.
	 */
	if (state > ACPI_STATE_D0) {
		/*
		 * According to ACPI 6, devices cannot go from lower-power
		 * (deeper) states to higher-power (shallower) states.
		 */
		if (state < device->power.state) {
			dev_warn(&device->dev, "Cannot transition from %s to %s\n",
				 acpi_power_state_string(device->power.state),
				 acpi_power_state_string(state));
			return -ENODEV;
		}

		result = acpi_dev_pm_explicit_set(device, state);
		if (result)
			goto end;

		if (device->power.flags.power_resources)
			result = acpi_power_transition(device, target_state);
	} else {
		if (device->power.flags.power_resources) {
			result = acpi_power_transition(device, ACPI_STATE_D0);
			if (result)
				goto end;
		}
		result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);
	}

 end:
	if (result) {
		dev_warn(&device->dev, "Failed to change power state to %s\n",
			 acpi_power_state_string(state));
	} else {
		device->power.state = target_state;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to %s\n",
				  device->pnp.bus_id,
				  acpi_power_state_string(state)));
	}

	return result;
}
Beispiel #7
0
/**
 * acpi_device_set_power - Set power state of an ACPI device.
 * @device: Device to set the power state of.
 * @state: New power state to set.
 *
 * Callers must ensure that the device is power manageable before using this
 * function.
 */
int acpi_device_set_power(struct acpi_device *device, int state)
{
	int result = 0;
	bool cut_power = false;

	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
		return -EINVAL;

	/* Make sure this is a valid target state */

	if (state == device->power.state) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
				  acpi_power_state_string(state)));
		return 0;
	}

	if (!device->power.states[state].flags.valid) {
		printk(KERN_WARNING PREFIX "Device does not support %s\n",
		       acpi_power_state_string(state));
		return -ENODEV;
	}
	if (device->parent && (state < device->parent->power.state)) {
		printk(KERN_WARNING PREFIX
			      "Cannot set device to a higher-powered"
			      " state than parent\n");
		return -ENODEV;
	}

	/* For D3cold we should first transition into D3hot. */
	if (state == ACPI_STATE_D3_COLD
	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
		state = ACPI_STATE_D3_HOT;
		cut_power = true;
	}

	if (state < device->power.state && state != ACPI_STATE_D0
	    && device->power.state >= ACPI_STATE_D3_HOT) {
		printk(KERN_WARNING PREFIX
			"Cannot transition to non-D0 state from D3\n");
		return -ENODEV;
	}

	/*
	 * Transition Power
	 * ----------------
	 * In accordance with the ACPI specification first apply power (via
	 * power resources) and then evalute _PSx.
	 */
	if (device->power.flags.power_resources) {
		result = acpi_power_transition(device, state);
		if (result)
			goto end;
	}
	result = acpi_dev_pm_explicit_set(device, state);
	if (result)
		goto end;

	if (cut_power) {
		device->power.state = state;
		state = ACPI_STATE_D3_COLD;
		result = acpi_power_transition(device, state);
	}

 end:
	if (result) {
		printk(KERN_WARNING PREFIX
			      "Device [%s] failed to transition to %s\n",
			      device->pnp.bus_id,
			      acpi_power_state_string(state));
	} else {
		device->power.state = state;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Device [%s] transitioned to %s\n",
				  device->pnp.bus_id,
				  acpi_power_state_string(state)));
	}

	return result;
}