Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH v8 3/3] Take maintainership of power sequences
From: Alexandre Courbot @ 2012-11-16  6:38 UTC (permalink / raw)
  To: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann
  Cc: Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, Alexandre Courbot,
	Alexandre Courbot
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot@nvidia.com>

Add entry for power sequences into MAINTAINERS with all the needed
contact and SCM info.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 59203e7..c86a93b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5696,6 +5696,16 @@ F:	fs/timerfd.c
 F:	include/linux/timer*
 F:	kernel/*timer*
 
+POWER SEQUENCES
+M:	Alexandre Courbot <acourbot@nvidia.com>
+S:	Maintained
+W:	https://github.com/Gnurou/linux-power-seqs
+T:	git https://github.com/Gnurou/linux-power-seqs.git
+F:	Documentation/devicetree/bindings/power/power_seq.txt
+F:	Documentation/power/power_seq.txt
+F:	include/linux/power_seq.h
+F:	drivers/power/power_seq/
+
 POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
 M:	Anton Vorontsov <cbou@mail.ru>
 M:	David Woodhouse <dwmw2@infradead.org>
-- 
1.8.0


^ permalink raw reply related

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Anton Vorontsov @ 2012-11-16  7:26 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra, linux-kernel, linux-fbdev,
	devicetree-discuss, linux-pm, Alexandre Courbot
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

Hi Alexandre,

The code looks neat, thanks for you work!

Just a couple of comments...

On Fri, Nov 16, 2012 at 03:38:21PM +0900, Alexandre Courbot wrote:
[...]
> +
> +#include "power_seq_delay.c"
> +#include "power_seq_regulator.c"
> +#include "power_seq_pwm.c"
> +#include "power_seq_gpio.c"

This is odd, although I remember you already explained why you have to
include the .c files, instead of linking them separately. But I forgot the
reason. :) I think this deserves a comment in the code.

> +static int of_power_seq_parse_step(struct device *dev,
> +				   struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct list_head *resources)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	struct power_seq_resource res, *res2;
> +	const char *type;
> +	int i, err;

nit: one variable declaration per line.

Thanks,
Anton.

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Srinivas KANDAGATLA @ 2012-11-16  7:58 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann, Alexandre Courbot, linux-fbdev, linux-pm,
	Leela Krishna Amudala, devicetree-discuss, linux-kernel,
	linux-tegra
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

Hi Alex,
I am looking forward for this feature to be mainlined, but I have
comment on the way the types are tied up to power seq infrastructure.
I know your use case are limited to using type "delay", "pwm" and "gpio"
and "regulator", However there are instances where the devices can be
powered up or reset by writing to special registers or sysconfs or
something else.
So My suggestion would be to make these type register them selfs
dynamically with the power_seq infrastructure so that in future this can
be extended to other types as-well.
This trivial change can make a lot of difference for the future chips
which do thing bit differently.
ST Microelectronics chips fit it in these category and I guess other
Vendors have this similar chips.

What do you think?


Thanks,
srini

On 16/11/12 06:38, Alexandre Courbot wrote:
> Some device drivers (e.g. panel or backlights) need to follow precise
> sequences for powering on and off, involving GPIOs, regulators, PWMs
> with a precise powering order and delays to respect between steps.
> These sequences are device-specific, and do not belong to a particular
> driver - therefore they have been performed by board-specific hook
> functions to far.
>
> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but
> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  include/linux/power_seq.h                          | 203 +++++++++++
>  12 files changed, 1282 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h
>
> diff --git a/Documentation/devicetree/bindings/power/power_seq.txt b/Documentation/devicetree/bindings/power/power_seq.txt
> new file mode 100644
> index 0000000..7880a6c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/power_seq.txt
> @@ -0,0 +1,121 @@
> +Runtime Interpreted Power Sequences
> +===================================
> +
> +Power sequences are sequential descriptions of actions to be performed on
> +power-related resources. Having these descriptions in a well-defined data format
> +allows us to take much of the board- or device- specific power control code out
> +of the kernel and place it into the device tree instead, making kernels less
> +board-dependant.
> +
> +A device typically makes use of multiple power sequences, for different purposes
> +such as powering on and off. All the power sequences of a given device are
> +grouped into a set. In the device tree, this set is a sub-node of the device
> +node named "power-sequences".
> +
> +Power Sequences Structure
> +-------------------------
> +Every device that makes use of power sequences must have a "power-sequences"
> +node into which individual power sequences are declared as sub-nodes. The name
> +of the node becomes the name of the sequence within the power sequences
> +framework.
> +
> +Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
> +must be named sequentially, with the first step named step0, the second step1,
> +etc. Failure to follow this rule will result in a parsing error.
> +
> +Power Sequences Steps
> +---------------------
> +Steps of a sequence describe an action to be performed on a resource. They
> +always include a "type" property which indicates what kind of resource this
> +step works on. Depending on the resource type, additional properties are defined
> +to control the action to be performed.
> +
> +"delay" type required properties:
> +  - delay: delay to wait (in microseconds)
> +
> +"regulator" type required properties:
> +  - id: name of the regulator to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"pwm" type required properties:
> +  - id: name of the PWM to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"gpio" type required properties:
> +  - gpio: phandle of the GPIO to use.
> +  - value: value this GPIO should take. Must be 0 or 1.
> +
> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +	backlight {
> +		compatible = "pwm-backlight";
> +		...
> +
> +		/* resources used by the power sequences */
> +		pwms = <&pwm 2 5000000>;
> +		pwm-names = "backlight";
> +		power-supply = <&backlight_reg>;
> +
> +		power-sequences {
> +			power-on {
> +				step0 {
> +					type = "regulator";
> +					id = "power";
> +					enable;
> +				};
> +				step1 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step2 {
> +					type = "pwm";
> +					id = "backlight";
> +					enable;
> +				};
> +				step3 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <1>;
> +				};
> +			};
> +
> +			power-off {
> +				step0 {
> +					type = "gpio";
> +					gpio = <&gpio 28 0>;
> +					value = <0>;
> +				};
> +				step1 {
> +					type = "pwm";
> +					id = "backlight";
> +					disable;
> +				};
> +				step2 {
> +					type = "delay";
> +					delay = <10000>;
> +				};
> +				step3 {
> +					type = "regulator";
> +					id = "power";
> +					disable;
> +				};
> +			};
> +		};
> +	};
> +
> +The first part lists the PWM and regulator resources used by the sequences.
> +These resources will be requested on behalf of the backlight device when the
> +sequences are built and are declared according to their own bindings (for
> +instance, regulators and pwms are resolved by name - note though that name
> +declaration is done differently by the two frameworks).
> +
> +After the resources declaration, two sequences follow for powering the backlight
> +on and off. Their names are specified by the pwm-backlight device bindings. Once
> +the sequences are built by calling devm_of_parse_power_seq_set() on the
> +backlight device, they can be added to a set using
> +power_seq_set_add_sequences().
> diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
> new file mode 100644
> index 0000000..8be0570
> --- /dev/null
> +++ b/Documentation/power/power_seq.txt
> @@ -0,0 +1,253 @@
> +Runtime Interpreted Power Sequences
> +===================================
> +
> +Problem
> +-------
> +Very commonly, boards need the help of out-of-driver code to turn some of their
> +devices on and off. For instance, SoC boards might use a GPIO (abstracted to a
> +regulator or not) to control the power supply of a backlight. The GPIO that
> +should be used, however, as well as the exact power sequence that may also
> +involve other resources, is board-dependent and thus unknown to the driver.
> +
> +This was previously addressed by having hooks in the device's platform data that
> +are called whenever the state of the device might need a power status change.
> +This approach, however, introduces board-dependant code into the kernel and is
> +not compatible with the device tree.
> +
> +The Runtime Interpreted Power Sequences (or power sequences for short) aim at
> +turning this code into platform data or device tree nodes. Power sequences are
> +described using a simple format and run by a lightweight interpreter whenever
> +needed. This allows device drivers to work without power callbacks and makes the
> +kernel less board-dependant.
> +
> +What are Power Sequences?
> +-------------------------
> +A power sequence is an array of sequential steps describing an action to be
> +performed on a resource. The supported resources and actions operations are:
> +- delay (just wait for a given number of microseconds)
> +- GPIO (set to 0 or 1)
> +- regulator (enable or disable)
> +- PWM (enable or disable)
> +
> +When a power sequence is run, its steps is executed one after the other until
> +one step fails or the end of the sequence is reached.
> +
> +Power sequences are named, and grouped into "sets" which contain all the
> +sequences of a device as well as the resources they use.
> +
> +Power sequences can be declared as platform data or in the device tree.
> +
> +Platform Data Format
> +--------------------
> +All relevant data structures for declaring power sequences are located in
> +include/linux/power_seq.h.
> +
> +The platform data for a device may include an instance of platform_power_seq_set
> +which references all the power sequences used for a device. The power sequences
> +reference resources in their steps, and setup the union member that corresponds
> +to the resource's type. Resources, similarly, have a union which relevant member
> +depends on their type.
> +
> +Note that the only "platform data" per se here is platform_power_seq_set. Other
> +structures (power_seq and power_seq_resource) will be used at runtime and thus
> +*must* survive initialization, so do not declare them with the __initdata
> +attribute.
> +
> +The following example should make it clear how the platform data for power
> +sequences is defined. It declares two power sequences named "power-on" and
> +"power-off" for a backlight device. The "power-on" sequence enables the "power"
> +regulator of the device, waits for 10ms, and then enables PWM "backlight" and
> +set GPIO 28 to 1. "power-off" does the opposite.
> +
> +struct power_seq_resource reg_res = {
> +	.type = POWER_SEQ_REGULATOR,
> +	.regulator.id = "power",
> +};
> +
> +struct power_seq_resource gpio_res = {
> +	.type = POWER_SEQ_GPIO,
> +	.gpio.gpio = 28,
> +};
> +
> +struct power_seq_resource pwm_res = {
> +	.type = POWER_SEQ_PWM,
> +	.pwm.id = "backlight",
> +};
> +
> +struct power_seq_resource delay_res = {
> +	.type = POWER_SEQ_DELAY,
> +};
> +
> +struct power_seq power_on_seq = {
> +	.id = "power-on",
> +	.num_steps = 4,
> +	.steps = {
> +		{
> +			.resource = &reg_res,
> +			.regulator.enable = true,
> +		}, {
> +			.resource = &delay_res,
> +			.delay.delay = 10000,
> +		}, {
> +			.resource = &pwm_res,
> +			.pwm.enable = true,
> +		}, {
> +			.resource = &gpio_res,
> +			.gpio.value = 1,
> +		},
> +	},
> +};
> +
> +struct power_seq power_off_seq = {
> +	.id = "power-off",
> +	.num_steps = 4,
> +	.steps = {
> +		{
> +			.resource = &gpio_res,
> +			.gpio.value = 0,
> +		}, {
> +			.resource = &pwm_res,
> +			.pwm.enable = false,
> +		}, {
> +			.resource = &delay_res,
> +			.delay.delay = 10000,
> +		}, {
> +			.resource = &reg_res,
> +			.regulator.enable = false,
> +		},
> +	},
> +};
> +
> +struct platform_power_seq_set backlight_power_seqs __initdata = {
> +	.num_seqs = 2,
> +	.seqs = {
> +		&power_on_seq,
> +		&power_off_seq,
> +	},
> +};
> +
> +"backlight_power_seqs" can then be passed to power_seq_set_add_sequences() in
> +order to add the sequences to a set and allocate all the necessary resources.
> +More on this later in this document.
> +
> +Device Tree
> +-----------
> +Power sequences can also be encoded as device tree nodes. The following
> +properties and nodes are equivalent to the platform data defined previously:
> +
> +pwms = <&pwm 2 5000000>;
> +pwm-names = "backlight";
> +power-supply = <&vdd_bl_reg>;
> +
> +power-sequences {
> +	power-on {
> +		step0 {
> +			type = "regulator";
> +			id = "power";
> +			enable;
> +		};
> +		step1 {
> +			type = "delay";
> +			delay = <10000>;
> +		};
> +		step2 {
> +			type = "pwm";
> +			id = "backlight";
> +			enable;
> +		};
> +		step3 {
> +			type = "gpio";
> +			gpio = <&gpio 28 0>;
> +			value = <1>;
> +		};
> +	};
> +
> +	power-off {
> +		step0 {
> +			type = "gpio";
> +			gpio = <&gpio 28 0>;
> +			value = <0>;
> +		};
> +		step1 {
> +			type = "pwm";
> +			id = "backlight";
> +			disable;
> +		};
> +		step2 {
> +			type = "delay";
> +			delay = <10000>;
> +		};
> +		step3 {
> +			type = "regulator";
> +			id = "power";
> +			disable;
> +		};
> +	};
> +};
> +
> +See Documentation/devicetree/bindings/power/power_seq.txt for the complete
> +syntax of the DT bindings.
> +
> +Use by Drivers and Resources Management
> +---------------------------------------
> +Power sequences make use of resources that must be properly allocated and
> +managed. The power_seq_set structure manages the sequences and resources for a
> +particular device. A driver willing to use power sequences will thus declare one
> +instance of power_seq_set per device and initialize it at probe time:
> +
> +struct my_device_data {
> +	struct device *dev;
> +	...
> +	struct power_set_set power_seqs;
> +	...
> +};
> +
> +power_seq_set_init(&my_device->power_seqs, my_device->dev);
> +
> +The power_seq_set_add_sequence() and power_seq_set_add_sequences() functions are
> +then used to add one or several sequences to a set. These functions will also
> +allocate all the resources used by the sequence(s) and make sure they are ready
> +to be run. All resources are allocated through devm and will thus be freed when
> +the set's device is removed.
> +
> +  int power_seq_set_add_sequence(struct power_seq_set *set,
> +			         struct power_seq *seq);
> +  int power_seq_set_add_sequences(struct power_seq_set *set,
> +				  struct platform_power_seq_set *seqs);
> +
> +Power sequences added to a set can then be resolved by their name using
> +power_seq_lookup():
> +
> +  struct power_seq *power_seq_lookup(struct power_seq_set *seqs,
> +				     const char *id);
> +
> +power_seq_lookup() returns a ready-to-run pointer to the power sequence which
> +name matches the id parameter.
> +
> +A retrieved power sequence can then be executed by power_seq_run:
> +
> +  int power_seq_run(struct power_seq *seq);
> +
> +It returns 0 if the sequence has successfully been run, or an error code if a
> +problem occurred.
> +
> +Sometimes, you may want to browse the list of resources allocated for the
> +sequences of a device, for instance to ensure that a resource of a given type is
> +present. The power_seq_for_each_resource() macro does this:
> +
> +  power_seq_for_each_resource(pos, seqs)
> +
> +Here "pos" will be a pointer to a struct power_seq_resource. This structure
> +contains the type of the resource, the information used for identifying it, and
> +the resolved resource itself.
> +
> +Finally, users of the device tree can obtain a platform_power_seq_set structure
> +built from the device's node using devm_of_parse_power_seq_set:
> +
> +  struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
> +
> +The power sequences must be declared under a "power-sequences" node directly
> +declared under the device's node. Detailed syntax contained in Documentation/devicetree/bindings/power/power_seq.txt. As the function name
> +states, all memory is allocated through devm. The returned
> +platform_power_seq_set can be freed after being added to a set, but the
> +sequences themselves must be preserved until they are freed by devm.
> \ No newline at end of file
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index 49a8939..f20d449 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -338,3 +338,4 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
>  endif # POWER_SUPPLY
>  
>  source "drivers/power/avs/Kconfig"
> +source "drivers/power/power_seq/Kconfig"
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index b949cf8..883ad4d 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -49,3 +49,4 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
>  obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
>  obj-$(CONFIG_POWER_AVS)		+= avs/
>  obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
> +obj-$(CONFIG_POWER_SEQ)		+= power_seq/
> diff --git a/drivers/power/power_seq/Kconfig b/drivers/power/power_seq/Kconfig
> new file mode 100644
> index 0000000..3bff26e
> --- /dev/null
> +++ b/drivers/power/power_seq/Kconfig
> @@ -0,0 +1,2 @@
> +config POWER_SEQ
> +	bool
> diff --git a/drivers/power/power_seq/Makefile b/drivers/power/power_seq/Makefile
> new file mode 100644
> index 0000000..f77a359
> --- /dev/null
> +++ b/drivers/power/power_seq/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_POWER_SEQ)		+= power_seq.o
> diff --git a/drivers/power/power_seq/power_seq.c b/drivers/power/power_seq/power_seq.c
> new file mode 100644
> index 0000000..255b1a0
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq.c
> @@ -0,0 +1,376 @@
> +/*
> + * power_seq.c - power sequence interpreter for platform devices and device tree
> + *
> + * Author: Alexandre Courbot <acourbot@nvidia.com>
> + *
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <linux/power_seq.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +
> +#include <linux/of.h>
> +
> +#define power_seq_err(seq, step_nbr, format, ...)			\
> +	dev_err(seq->set->dev, "%s[%d]: " format, seq->id, step_nbr,	\
> +	##__VA_ARGS__);
> +
> +/**
> + * struct power_seq_res_ops - operators for power sequences resources
> + * @name:		Name of the resource type. Set to null when a resource
> + *			type support is not compiled in
> + * @of_parse:		Parse a step for this kind of resource from a device
> + *			tree node. The result of parsing must be written into
> + *			step step_nbr of seq
> + * @step_run:		Run a step for this kind of resource
> + * @res_compare:	Return true if the resource used by the resource is the
> + *			same as the one referenced by the step, false otherwise.
> + * @res_alloc:		Resolve and allocate a resource. Return error code if
> + *			the resource cannot be allocated, 0 otherwise
> + */
> +struct power_seq_res_ops {
> +	const char *name;
> +	int (*of_parse)(struct device_node *node, struct power_seq *seq,
> +			unsigned int step_nbr, struct power_seq_resource *res);
> +	int (*step_run)(struct power_seq_step *step);
> +	bool (*res_compare)(struct power_seq_resource *res,
> +			    struct power_seq_resource *res2);
> +	int (*res_alloc)(struct device *dev,
> +			 struct power_seq_resource *res);
> +};
> +
> +static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES];
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_enable_properties(struct device_node *node,
> +						struct power_seq *seq,
> +						unsigned int step_nbr,
> +						bool *enable)
> +{
> +	if (of_find_property(node, "enable", NULL)) {
> +		*enable = true;
> +	} else if (of_find_property(node, "disable", NULL)) {
> +		*enable = false;
> +	} else {
> +		power_seq_err(seq, step_nbr,
> +			      "missing enable or disable property\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int of_power_seq_parse_step(struct device *dev,
> +				   struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct list_head *resources)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	struct power_seq_resource res, *res2;
> +	const char *type;
> +	int i, err;
> +
> +	err = of_property_read_string(node, "type", &type);
> +	if (err < 0) {
> +		power_seq_err(seq, step_nbr, "cannot read type property\n");
> +		return err;
> +	}
> +	for (i = 0; i < POWER_SEQ_NUM_TYPES; i++) {
> +		if (power_seq_ops[i].name == NULL)
> +			continue;
> +		if (!strcmp(type, power_seq_ops[i].name))
> +			break;
> +	}
> +	if (i >= POWER_SEQ_NUM_TYPES) {
> +		power_seq_err(seq, step_nbr, "unknown type %s\n", type);
> +		return -EINVAL;
> +	}
> +	memset(&res, 0, sizeof(res));
> +	res.type = i;
> +	err = power_seq_ops[res.type].of_parse(node, seq, step_nbr, &res);
> +	if (err < 0)
> +		return err;
> +
> +	/* Use the same instance of the resource if met before */
> +	list_for_each_entry(res2, resources, list) {
> +		if (res.type == res2->type &&
> +		    power_seq_ops[res.type].res_compare(&res, res2))
> +			break;
> +	}
> +	/* Resource never met before, create it */
> +	if (&res2->list == resources) {
> +		res2 = devm_kzalloc(dev, sizeof(*res2), GFP_KERNEL);
> +		if (!res2)
> +			return -ENOMEM;
> +		memcpy(res2, &res, sizeof(res));
> +		list_add_tail(&res2->list, resources);
> +	}
> +	step->resource = res2;
> +
> +	return 0;
> +}
> +
> +static struct power_seq *of_parse_power_seq(struct device *dev,
> +					    struct device_node *node,
> +					    struct list_head *resources)
> +{
> +	struct device_node *child = NULL;
> +	struct power_seq *pseq;
> +	int num_steps, sz;
> +	int err;
> +
> +	if (!node)
> +		return ERR_PTR(-EINVAL);
> +
> +	num_steps = of_get_child_count(node);
> +	sz = sizeof(*pseq) + sizeof(pseq->steps[0]) * num_steps;
> +	pseq = devm_kzalloc(dev, sz, GFP_KERNEL);
> +	if (!pseq)
> +		return ERR_PTR(-ENOMEM);
> +	pseq->id = node->name;
> +	pseq->num_steps = num_steps;
> +
> +	for_each_child_of_node(node, child) {
> +		unsigned int pos;
> +
> +		/* Check that the name's format is correct and within bounds */
> +		if (strncmp("step", child->name, 4)) {
> +			err = -EINVAL;
> +			goto parse_error;
> +		}
> +
> +		err = kstrtouint(child->name + 4, 10, &pos);
> +		if (err < 0)
> +			goto parse_error;
> +
> +		/* Invalid step index or step already parsed? */
> +		if (pos >= num_steps || pseq->steps[pos].resource != NULL) {
> +			err = -EINVAL;
> +			goto parse_error;
> +		}
> +
> +		err = of_power_seq_parse_step(dev, child, pseq, pos, resources);
> +		if (err)
> +			return ERR_PTR(err);
> +	}
> +
> +	return pseq;
> +
> +parse_error:
> +	dev_err(dev, "%s: invalid power step name %s!\n", pseq->id,
> +		child->name);
> +	return ERR_PTR(err);
> +}
> +
> +/**
> + * devm_of_parse_power_seq_set - build a power_seq_set from the device tree
> + * @dev:	Device to parse the power sequences of
> + *
> + * Sequences must be contained into a subnode named "power-sequences" of the
> + * device root node.
> + *
> + * Memory for the sequence is allocated using devm_kzalloc on dev. The returned
> + * platform_power_seq_set can be freed by devm_kfree after the sequences have
> + * been added, but the sequences themselves must be preserved.
> + *
> + * Returns the built set on success, or an error code in case of failure.
> + */
> +struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev)
> +{
> +	struct platform_power_seq_set *set;
> +	struct device_node *root = dev->of_node;
> +	struct device_node *seq;
> +	struct list_head resources;
> +	int n, sz;
> +
> +	if (!root)
> +		return NULL;
> +
> +	root = of_find_node_by_name(root, "power-sequences");
> +	if (!root)
> +		return NULL;
> +
> +	n = of_get_child_count(root);
> +	sz = sizeof(*set) + sizeof(struct power_seq *) * n;
> +	set = devm_kzalloc(dev, sz, GFP_KERNEL);
> +	if (!set)
> +		return ERR_PTR(-ENOMEM);
> +	set->num_seqs = n;
> +
> +	n = 0;
> +	INIT_LIST_HEAD(&resources);
> +	for_each_child_of_node(root, seq) {
> +		struct power_seq *pseq;
> +
> +		pseq = of_parse_power_seq(dev, seq, &resources);
> +		if (IS_ERR(pseq))
> +			return (void *)pseq;
> +
> +		set->seqs[n++] = pseq;
> +	}
> +
> +	return set;
> +}
> +EXPORT_SYMBOL_GPL(devm_of_parse_power_seq_set);
> +#endif /* CONFIG_OF */
> +
> +/**
> + * power_seq_set_init - initialize a power_seq_set
> + * @set:	Set to initialize
> + * @dev:	Device this set is going to belong to
> + */
> +void power_seq_set_init(struct power_seq_set *set, struct device *dev)
> +{
> +	set->dev = dev;
> +	INIT_LIST_HEAD(&set->resources);
> +	INIT_LIST_HEAD(&set->seqs);
> +}
> +EXPORT_SYMBOL_GPL(power_seq_set_init);
> +
> +/**
> + * power_seq_add_sequence - add a power sequence to a set
> + * @set:	Set to add the sequence to
> + * @seq:	Sequence to add
> + *
> + * This step will check that all the resources used by the sequence are
> + * allocated. If they are not, an attempt to allocate them is made. This
> + * operation can fail and and return an error code.
> + *
> + * Returns 0 on success, error code if a resource initialization failed.
> + */
> +int power_seq_add_sequence(struct power_seq_set *set, struct power_seq *seq)
> +{
> +	struct power_seq_resource *res;
> +	int i, err;
> +
> +	for (i = 0; i < seq->num_steps; i++) {
> +		struct power_seq_step *step = &seq->steps[i];
> +		struct power_seq_resource *step_res = step->resource;
> +		list_for_each_entry(res, &set->resources, list) {
> +			if (res == step_res)
> +				break;
> +		}
> +		/* resource not allocated yet, allocate and add it */
> +		if (&res->list == &set->resources) {
> +			err = power_seq_ops[step_res->type].res_alloc(set->dev,
> +								      step_res);
> +			if (err)
> +				return err;
> +			list_add_tail(&step->resource->list, &set->resources);
> +		}
> +	}
> +
> +	list_add_tail(&seq->list, &set->seqs);
> +	seq->set = set;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_add_sequence);
> +
> +/**
> + * power_seq_add_sequences - add power sequences defined as platform data
> + * @set:	Set to add the sequences to
> + * @seqs:	Sequences to add
> + *
> + * See power_seq_add_sequence for more details.
> + *
> + * Returns 0 on success, error code if a resource initialization failed.
> + */
> +int power_seq_set_add_sequences(struct power_seq_set *set,
> +				struct platform_power_seq_set *seqs)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < seqs->num_seqs; i++) {
> +		ret = power_seq_add_sequence(set, seqs->seqs[i]);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_set_add_sequences);
> +
> +/**
> + * power_seq_lookup - Lookup a power sequence by name from a set
> + * @seqs:	The set to look in
> + * @id:		Name to look after
> + *
> + * Returns a matching power sequence if it exists, NULL if it does not.
> + */
> +struct power_seq *power_seq_lookup(struct power_seq_set *set, const char *id)
> +{
> +	struct power_seq *seq;
> +
> +	list_for_each_entry(seq, &set->seqs, list) {
> +		if (!strcmp(seq->id, id))
> +			return seq;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_lookup);
> +
> +/**
> + * power_seq_run() - run a power sequence
> + * @seq:	The power sequence to run
> + *
> + * Returns 0 on success, error code in case of failure.
> + */
> +int power_seq_run(struct power_seq *seq)
> +{
> +	unsigned int i;
> +	int err;
> +
> +	if (!seq)
> +		return 0;
> +
> +	if (!seq->set) {
> +		pr_err("cannot run a sequence not added to a set");
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < seq->num_steps; i++) {
> +		unsigned int type = seq->steps[i].resource->type;
> +
> +		err = power_seq_ops[type].step_run(&seq->steps[i]);
> +		if (err) {
> +			power_seq_err(seq, i,
> +				"error %d while running power sequence step\n",
> +				err);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(power_seq_run);
> +
> +#include "power_seq_delay.c"
> +#include "power_seq_regulator.c"
> +#include "power_seq_pwm.c"
> +#include "power_seq_gpio.c"
> +
> +static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
> +	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
> +	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
> +	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
> +	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
> +};
> +
> +MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
> +MODULE_DESCRIPTION("Runtime Interpreted Power Sequences");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/power/power_seq/power_seq_delay.c b/drivers/power/power_seq/power_seq_delay.c
> new file mode 100644
> index 0000000..5bb0a46
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_delay.c
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <linux/delay.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_delay(struct device_node *node,
> +				    struct power_seq *seq,
> +				    unsigned int step_nbr,
> +				    struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_u32(node, "delay",
> +				   &step->delay.delay);
> +	if (err < 0)
> +		power_seq_err(seq, step_nbr, "error reading delay property\n");
> +
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_delay NULL
> +#endif
> +
> +static bool power_seq_res_compare_delay(struct power_seq_resource *res,
> +					struct power_seq_resource *res2)
> +{
> +	/* Delay resources are just here to hold the type of steps, so they are
> +	 * all equivalent. */
> +	return true;
> +}
> +
> +static int power_seq_res_alloc_delay(struct device *dev,
> +				     struct power_seq_resource *res)
> +{
> +	return 0;
> +}
> +
> +static int power_seq_step_run_delay(struct power_seq_step *step)
> +{
> +	usleep_range(step->delay.delay,
> +		     step->delay.delay + 1000);
> +
> +	return 0;
> +}
> +
> +#define POWER_SEQ_DELAY_TYPE {				\
> +	.name = "delay",				\
> +	.of_parse = of_power_seq_parse_delay,		\
> +	.step_run = power_seq_step_run_delay,		\
> +	.res_compare = power_seq_res_compare_delay,	\
> +	.res_alloc = power_seq_res_alloc_delay,		\
> +}
> diff --git a/drivers/power/power_seq/power_seq_gpio.c b/drivers/power/power_seq/power_seq_gpio.c
> new file mode 100644
> index 0000000..028a4cc
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_gpio.c
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_gpio(struct device_node *node,
> +				   struct power_seq *seq,
> +				   unsigned int step_nbr,
> +				   struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int gpio;
> +	int err;
> +
> +	gpio = of_get_named_gpio(node, "gpio", 0);
> +	if (gpio < 0) {
> +		power_seq_err(seq, step_nbr, "error reading gpio property\n");
> +		return gpio;
> +	}
> +	res->gpio.gpio = gpio;
> +
> +	err = of_property_read_u32(node, "value", &step->gpio.value);
> +	if (err < 0) {
> +		power_seq_err(seq, step_nbr, "error reading value property\n");
> +	} else if (step->gpio.value < 0 || step->gpio.value > 1) {
> +		power_seq_err(seq, step_nbr,
> +			      "value out of range (must be 0 or 1)\n");
> +		err = -EINVAL;
> +	}
> +
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_gpio NULL
> +#endif
> +
> +static bool power_seq_res_compare_gpio(struct power_seq_resource *res,
> +				       struct power_seq_resource *res2)
> +{
> +	return res->gpio.gpio == res2->gpio.gpio;
> +}
> +
> +static int power_seq_res_alloc_gpio(struct device *dev,
> +				    struct power_seq_resource *res)
> +{
> +	int err;
> +
> +	err = devm_gpio_request(dev, res->gpio.gpio, dev_name(dev));
> +	if (err) {
> +		dev_err(dev, "cannot get gpio %d\n", res->gpio.gpio);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_gpio(struct power_seq_step *step)
> +{
> +	struct power_seq_resource *res = step->resource;
> +
> +	/* set the GPIO direction at first use */
> +	if (!res->gpio.is_set) {
> +		int err = gpio_direction_output(res->gpio.gpio,
> +						step->gpio.value);
> +		if (err)
> +			return err;
> +		res->gpio.is_set = true;
> +	} else {
> +		gpio_set_value_cansleep(res->gpio.gpio, step->gpio.value);
> +	}
> +
> +	return 0;
> +}
> +
> +#define POWER_SEQ_GPIO_TYPE {					\
> +	.name = "gpio",					\
> +	.of_parse = of_power_seq_parse_gpio,		\
> +	.step_run = power_seq_step_run_gpio,		\
> +	.res_compare = power_seq_res_compare_gpio,	\
> +	.res_alloc = power_seq_res_alloc_gpio,		\
> +}
> diff --git a/drivers/power/power_seq/power_seq_pwm.c b/drivers/power/power_seq/power_seq_pwm.c
> new file mode 100644
> index 0000000..e61acdd
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_pwm.c
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#ifdef CONFIG_PWM
> +
> +#include <linux/pwm.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_pwm(struct device_node *node,
> +				  struct power_seq *seq,
> +				  unsigned int step_nbr,
> +				  struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_string(node, "id", &res->pwm.id);
> +	if (err) {
> +		power_seq_err(seq, step_nbr, "error reading id property\n");
> +		return err;
> +	}
> +
> +	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
> +						   &step->pwm.enable);
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_pwm NULL
> +#endif
> +
> +static bool power_seq_res_compare_pwm(struct power_seq_resource *res,
> +				      struct power_seq_resource *res2)
> +{
> +	return !strcmp(res->pwm.id, res2->pwm.id);
> +}
> +
> +static int power_seq_res_alloc_pwm(struct device *dev,
> +				   struct power_seq_resource *res)
> +{
> +	res->pwm.pwm = devm_pwm_get(dev, res->pwm.id);
> +	if (IS_ERR(res->pwm.pwm)) {
> +		dev_err(dev, "cannot get pwm \"%s\"\n", res->pwm.id);
> +		return PTR_ERR(res->pwm.pwm);
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_pwm(struct power_seq_step *step)
> +{
> +	if (step->pwm.enable) {
> +		return pwm_enable(step->resource->pwm.pwm);
> +	} else {
> +		pwm_disable(step->resource->pwm.pwm);
> +		return 0;
> +	}
> +}
> +
> +#define POWER_SEQ_PWM_TYPE {				\
> +	.name = "pwm",					\
> +	.of_parse = of_power_seq_parse_pwm,		\
> +	.step_run = power_seq_step_run_pwm,		\
> +	.res_compare = power_seq_res_compare_pwm,	\
> +	.res_alloc = power_seq_res_alloc_pwm,		\
> +}
> +
> +#else
> +
> +#define POWER_SEQ_PWM_TYPE {}
> +
> +#endif
> diff --git a/drivers/power/power_seq/power_seq_regulator.c b/drivers/power/power_seq/power_seq_regulator.c
> new file mode 100644
> index 0000000..2025155
> --- /dev/null
> +++ b/drivers/power/power_seq/power_seq_regulator.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#ifdef CONFIG_REGULATOR
> +
> +#include <linux/regulator/consumer.h>
> +
> +#ifdef CONFIG_OF
> +static int of_power_seq_parse_regulator(struct device_node *node,
> +					struct power_seq *seq,
> +					unsigned int step_nbr,
> +					struct power_seq_resource *res)
> +{
> +	struct power_seq_step *step = &seq->steps[step_nbr];
> +	int err;
> +
> +	err = of_property_read_string(node, "id",
> +				      &res->regulator.id);
> +	if (err) {
> +		power_seq_err(seq, step_nbr, "error reading id property\n");
> +		return err;
> +	}
> +
> +	err = of_power_seq_parse_enable_properties(node, seq, step_nbr,
> +						   &step->regulator.enable);
> +	return err;
> +}
> +#else
> +#define of_power_seq_parse_regulator NULL
> +#endif
> +
> +static bool
> +power_seq_res_compare_regulator(struct power_seq_resource *res,
> +				struct power_seq_resource *res2)
> +{
> +	return !strcmp(res->regulator.id, res2->regulator.id);
> +}
> +
> +static int power_seq_res_alloc_regulator(struct device *dev,
> +					 struct power_seq_resource *res)
> +{
> +	res->regulator.regulator = devm_regulator_get(dev, res->regulator.id);
> +	if (IS_ERR(res->regulator.regulator)) {
> +		dev_err(dev, "cannot get regulator \"%s\"\n",
> +			res->regulator.id);
> +		return PTR_ERR(res->regulator.regulator);
> +	}
> +
> +	return 0;
> +}
> +
> +static int power_seq_step_run_regulator(struct power_seq_step *step)
> +{
> +	if (step->regulator.enable)
> +		return regulator_enable(step->resource->regulator.regulator);
> +	else
> +		return regulator_disable(step->resource->regulator.regulator);
> +}
> +
> +#define POWER_SEQ_REGULATOR_TYPE {			\
> +	.name = "regulator",				\
> +	.of_parse = of_power_seq_parse_regulator,	\
> +	.step_run = power_seq_step_run_regulator,	\
> +	.res_compare = power_seq_res_compare_regulator,	\
> +	.res_alloc = power_seq_res_alloc_regulator,	\
> +}
> +
> +#else
> +
> +#define POWER_SEQ_REGULATOR_TYPE {}
> +
> +#endif
> diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
> new file mode 100644
> index 0000000..21b95b6
> --- /dev/null
> +++ b/include/linux/power_seq.h
> @@ -0,0 +1,203 @@
> +/*
> + * power_seq.h
> + *
> + * Simple interpreter for power sequences defined as platform data or device
> + * tree properties.
> + *
> + * Power sequences are designed to replace the callbacks typically used in
> + * board-specific files that implement board- or device- specific power
> + * sequences (such as those of backlights). A power sequence is an array of
> + * steps referencing resources (regulators, GPIOs, PWMs, ...) with an action to
> + * perform on them. By having the power sequences interpreted, it becomes
> + * possible to describe them in the device tree and thus to remove
> + * board-specific files from the kernel.
> + *
> + * See Documentation/power/power_seqs.txt for detailed information.
> + *
> + * Author: Alexandre Courbot <acourbot@nvidia.com>
> + *
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * 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; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#ifndef __LINUX_POWER_SEQ_H
> +#define __LINUX_POWER_SEQ_H
> +
> +#include <linux/types.h>
> +#include <linux/list.h>
> +
> +struct device;
> +struct regulator;
> +struct pwm_device;
> +
> +/**
> + * The different kinds of resources that can be controlled by the sequences
> + */
> +enum power_seq_res_type {
> +	POWER_SEQ_DELAY,
> +	POWER_SEQ_REGULATOR,
> +	POWER_SEQ_PWM,
> +	POWER_SEQ_GPIO,
> +	POWER_SEQ_NUM_TYPES,
> +};
> +
> +/**
> + * struct power_seq_regulator_resource
> + * @id:		name of the regulator
> + * @regulator:	resolved regulator. Written during resource resolution.
> + */
> +struct power_seq_regulator_resource {
> +	const char *id;
> +	struct regulator *regulator;
> +};
> +
> +/**
> + * struct power_seq_pwm_resource
> + * @id:		name of the PWM
> + * @regulator:	resolved PWM. Written during resource resolution.
> + */
> +struct power_seq_pwm_resource {
> +	const char *id;
> +	struct pwm_device *pwm;
> +};
> +
> +/**
> + * struct power_seq_gpio_resource
> + * @gpio:	number of the GPIO
> + * @is_set:	track GPIO state to set its direction at first use
> + */
> +struct power_seq_gpio_resource {
> +	int gpio;
> +	bool is_set;
> +};
> +
> +/**
> + * struct power_seq_resource - resource used by power sequences
> + * @type:	type of the resource. This decides which member of the union is
> + *		used for this resource
> + * @list:	link resources together in power_seq_set
> + * @regulator:	used if @type == POWER_SEQ_REGULATOR
> + * @pwm:	used if @type == POWER_SEQ_PWM
> + * @gpio:	used if @type == POWER_SEQ_GPIO
> + */
> +struct power_seq_resource {
> +	enum power_seq_res_type type;
> +	struct list_head list;
> +	union {
> +		struct power_seq_regulator_resource regulator;
> +		struct power_seq_pwm_resource pwm;
> +		struct power_seq_gpio_resource gpio;
> +	};
> +};
> +#define power_seq_for_each_resource(pos, set)			\
> +	list_for_each_entry(pos, &(set)->resources, list)
> +
> +/**
> + * struct power_seq_delay_step - action data for delay steps
> + * @delay:	amount of time to wait, in microseconds
> + */
> +struct power_seq_delay_step {
> +	unsigned int delay;
> +};
> +
> +/**
> + * struct power_seq_regulator_step - platform data for regulator steps
> + * @enable:	whether to enable or disable the regulator during this step
> + */
> +struct power_seq_regulator_step {
> +	bool enable;
> +};
> +
> +/**
> + * struct power_seq_pwm_step - action data for PWM steps
> + * @enable:	whether to enable or disable the PWM during this step
> + */
> +struct power_seq_pwm_step {
> +	bool enable;
> +};
> +
> +/**
> + * struct power_seq_gpio_step - action data for GPIO steps
> + * @enable:	whether to enable or disable the GPIO during this step
> + */
> +struct power_seq_gpio_step {
> +	int value;
> +};
> +
> +/**
> + * struct power_seq_step - data for power sequences steps
> + * @resource:	resource used by this step
> + * @delay:	used if resource->type == POWER_SEQ_DELAY
> + * @regulator:	used if resource->type == POWER_SEQ_REGULATOR
> + * @pwm:	used if resource->type == POWER_SEQ_PWN
> + * @gpio:	used if resource->type == POWER_SEQ_GPIO
> + */
> +struct power_seq_step {
> +	struct power_seq_resource *resource;
> +	union {
> +		struct power_seq_delay_step delay;
> +		struct power_seq_regulator_step regulator;
> +		struct power_seq_pwm_step pwm;
> +		struct power_seq_gpio_step gpio;
> +	};
> +};
> +
> +struct power_seq_set;
> +
> +/**
> + * struct power_seq - single power sequence
> + * @id:		name of this sequence
> + * @list:	link sequences together in power_seq_set. Leave as-is
> + * @set:	set this sequence belongs to. Written when added to a set
> + * @num_steps:	number of steps in the sequence
> + * @steps:	array of steps that make the sequence
> + */
> +struct power_seq {
> +	const char *id;
> +	struct list_head list;
> +	struct power_seq_set *set;
> +	unsigned int num_steps;
> +	struct power_seq_step steps[];
> +};
> +
> +/**
> + * struct power_seq_set - power sequences and resources used by a device
> + * @dev:	device this set belongs to
> + * @resources:	list of resources used by power sequences
> + * @seqs:	list of power sequences
> + */
> +struct power_seq_set {
> +	struct device *dev;
> +	struct list_head resources;
> +	struct list_head seqs;
> +};
> +
> +/**
> + * struct platform_power_seq_set - define power sequences as platform data
> + * @num_seqs:	number of sequences defined
> + * @seqs:	array of num_seqs power sequences
> + */
> +struct platform_power_seq_set {
> +	unsigned int num_seqs;
> +	struct power_seq *seqs[];
> +};
> +
> +struct platform_power_seq_set *devm_of_parse_power_seq_set(struct device *dev);
> +void power_seq_set_init(struct power_seq_set *set, struct device *dev);
> +int power_seq_set_add_sequence(struct power_seq_set *set,
> +			       struct power_seq *seq);
> +int power_seq_set_add_sequences(struct power_seq_set *set,
> +				struct platform_power_seq_set *seqs);
> +struct power_seq *power_seq_lookup(struct power_seq_set *seqs, const char *id);
> +int power_seq_run(struct power_seq *seq);
> +
> +#endif


^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alex Courbot @ 2012-11-16  8:31 UTC (permalink / raw)
  To: srinivas.kandagatla-qxv4g6HH51o@public.gmane.org
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann, Alexandre Courbot,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <50A5F225.6000200-qxv4g6HH51o@public.gmane.org>

Hi Srinivas,

On Friday 16 November 2012 15:58:29 Srinivas KANDAGATLA wrote:
> Hi Alex,
> I am looking forward for this feature to be mainlined,

*cough* Ack *cough* :)

> but I have
> comment on the way the types are tied up to power seq infrastructure.
> I know your use case are limited to using type "delay", "pwm" and "gpio"
> and "regulator", However there are instances where the devices can be
> powered up or reset by writing to special registers or sysconfs or
> something else.
> So My suggestion would be to make these type register them selfs
> dynamically with the power_seq infrastructure so that in future this can
> be extended to other types as-well.
> This trivial change can make a lot of difference for the future chips
> which do thing bit differently.
> ST Microelectronics chips fit it in these category and I guess other
> Vendors have this similar chips.

The current implementation is (purposedly) minimal and will certainly be 
extended. There are other aspects of regulators for instance that should also 
be controllable (voltage comes to mind). And I am totally open to supporting 
new kinds of resources as usage broadens. For this first version I just wanted 
to introduce the feature and minimize the impact should anything (DT 
bindings?) need to change.

I am a little bit skeptical about the purpose of directly accessing registers 
(or any part of the address space) from power sequences. It should at least be 
possible to involve some kind of abstraction. Not necessarily one of the 
currently supported types - but at least something.

The reason is that I'd like to try and avoid direct references to resources 
within sequences as much as possible to make them reusable. If your system has 
two identical devices, you should not need to duplicate their sequences just 
to change a register range from the few steps that make use of it. If you can 
do the same job with, say, a regulator, you can just give it a name, get it at 
runtime using regulator_get() and define it outside of the sequence, in our 
device node.

Of course there might be scenarios where you really need to access a register 
and there is no way to do otherwise, in this case I am open to discussion. But 
before resorting to this I'd like to make that the existing abstraction cannot 
cover the case already.

Alex.

^ permalink raw reply

* Re: [PATCH RESEND v4 0/5] Migrate SCSI drivers to use dev_pm_ops
From: Aaron Lu @ 2012-11-16  8:43 UTC (permalink / raw)
  To: James Bottomley; +Cc: Alan Stern, Rafael J. Wysocki, linux-pm, linux-scsi
In-Reply-To: <1352446075-1814-1-git-send-email-aaron.lu@intel.com>

Hi James,

Care to comment?

Thanks,
Aaron

On 11/09/2012 03:27 PM, Aaron Lu wrote:
> This patchset has been quiet for a while, so resend them.
> 
> v4:
> Only Patch 4 is modified:
> Fixed a line over 80 characters warning by checkpatch.pl;
> Update the changelog so that it is no more a try :-)
> 
> v3:
> Only patch 4 is modified:
> Remove the special case for system freeze in scsi_bus_suspend_common
> as pointed out by Alan Stern;
> Updated some comments;
> Removed the use of typedef (*pm_callback_t)(struct device *).
> 
> v2:
> Change the runtime suspend behaviour of sd driver by putting the device
> into stopped power state.
> Revert 2 patches which are no longer needed as pointed out by Alan Stern.
> Find out device callbacks in bus callbacks as suggested by Alan Stern.
> 
> Due to these changes, patch number grows from 2 -> 5.
> 
> v1:
> The 2 patches will migrate SCSI drivers to use the pm callbacks defined
> in dev_pm_ops as pm_message is deprecated and should not be used by driver.
> Bus level callback is changed to use callbacks defined in dev_pm_ops when
> needed and sd's pm callback is updated to use what are defined in dev_pm_ops.
> 
> 
> Aaron Lu (5):
>   sd: put to stopped power state when runtime suspend
>   Revert "[SCSI] scsi_pm: set device runtime state before parent
>     suspended"
>   Revert "[SCSI] runtime resume parent for child's system-resume"
>   pm: use callbacks from dev_pm_ops for scsi devices
>   sd: update sd to use the new pm callbacks
> 
>  drivers/scsi/scsi_pm.c | 98 +++++++++++++++++++++++++++-----------------------
>  drivers/scsi/sd.c      | 18 +++++++---
>  2 files changed, 67 insertions(+), 49 deletions(-)
> 


^ permalink raw reply

* Re: [PATCH v8 0/3] Runtime Interpreted Power Sequences
From: Thierry Reding @ 2012-11-16  8:44 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 2755 bytes --]

On Fri, Nov 16, 2012 at 03:38:20PM +0900, Alexandre Courbot wrote:
> Hopefully the final series before the feature gets merged. Anton Vorontsov
> kindly accepted to take it into his tree, so this series is mostly a call for
> acks, tests and reviews notices before the merge window for 3.8 opens. If you
> are interested in seeing this feature, please add your name.
> 
> This series also adds an entry for the subsystem into MAINTAINERS, setting me as
> the person in charge.
> 
> Changes from v7:
> - fix bug reported by Tony Prisk
> - add MAINTAINERS entry
> 
> Alexandre Courbot (3):
>   Runtime Interpreted Power Sequences
>   pwm_backlight: use power sequences
>   Take maintainership of power sequences
> 
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  .../bindings/video/backlight/pwm-backlight.txt     |  63 +++-
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  MAINTAINERS                                        |  10 +
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  drivers/video/backlight/Kconfig                    |   1 +
>  drivers/video/backlight/pwm_bl.c                   | 160 +++++++--
>  include/linux/power_seq.h                          | 203 +++++++++++
>  include/linux/pwm_backlight.h                      |  18 +-
>  17 files changed, 1494 insertions(+), 40 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h

The series,

Tested-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
Acked-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v8 2/3] pwm_backlight: use power sequences
From: Thierry Reding @ 2012-11-16  8:49 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <1353047903-14363-3-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 859 bytes --]

On Fri, Nov 16, 2012 at 03:38:22PM +0900, Alexandre Courbot wrote:
> Make use of the power sequences specified in the device tree or platform
> data to control how the backlight is powered on and off.
> 
> Signed-off-by: Alexandre Courbot <acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> Reviewed-by: Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>

Anton,

I would normally take pwm-backlight patches through the PWM tree, but
since this patch depends on the first in this series, I think it would
be easier if you took it through your tree along with the rest of the
series. If that's okay with you:

Acked-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>

Otherwise just let me know and I'm sure we can coordinate to take this
in via the two trees separately.

Thanks,
Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Srinivas KANDAGATLA @ 2012-11-16  9:04 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Alexandre Courbot,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	Mark Zhang, Rob Herring,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Anton Vorontsov,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	David Woodhouse
In-Reply-To: <4423025.WvVzNKlS3r@percival>

On 16/11/12 08:31, Alex Courbot wrote:
> Hi Srinivas,
>
> On Friday 16 November 2012 15:58:29 Srinivas KANDAGATLA wrote:
>> Hi Alex,
>> I am looking forward for this feature to be mainlined,
> *cough* Ack *cough* :)
:-)
>> but I have
>> comment on the way the types are tied up to power seq infrastructure.
>> I know your use case are limited to using type "delay", "pwm" and "gpio"
>> and "regulator", However there are instances where the devices can be
>> powered up or reset by writing to special registers or sysconfs or
>> something else.
>> So My suggestion would be to make these type register them selfs
>> dynamically with the power_seq infrastructure so that in future this can
>> be extended to other types as-well.
>> This trivial change can make a lot of difference for the future chips
>> which do thing bit differently.
>> ST Microelectronics chips fit it in these category and I guess other
>> Vendors have this similar chips.
> The current implementation is (purposedly) minimal and will certainly be 
> extended. There are other aspects of regulators for instance that should also 
> be controllable (voltage comes to mind). And I am totally open to supporting 
> new kinds of resources as usage broadens. For this first version I just wanted 
> to introduce the feature and minimize the impact should anything (DT 
> bindings?) need to change.
Ok I agree. I was thinking more of to fit few things specific to our
chip via power-seqs.
>
> I am a little bit skeptical about the purpose of directly accessing registers 
> (or any part of the address space) from power sequences. It should at least be 
> possible to involve some kind of abstraction. Not necessarily one of the 
> currently supported types - but at least something.
Yes, There is a level of abstraction (aka sysconf) in our case.. again
it is not mainlined yet.
>
> The reason is that I'd like to try and avoid direct references to resources 
> within sequences as much as possible to make them reusable. If your system has 
> two identical devices, you should not need to duplicate their sequences just 
> to change a register range from the few steps that make use of it. If you can 
> do the same job with, say, a regulator, you can just give it a name, get it at 
> runtime using regulator_get() and define it outside of the sequence, in our 
> device node.
>
> Of course there might be scenarios where you really need to access a register 
> and there is no way to do otherwise, in this case I am open to discussion. But 
> before resorting to this I'd like to make that the existing abstraction cannot 
> cover the case already.
yep.

thanks,
srini
>
> Alex.
>
>

^ permalink raw reply

* Re: [PATCH v8 2/3] pwm_backlight: use power sequences
From: Anton Vorontsov @ 2012-11-16  9:39 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Alexandre Courbot, Stephen Warren, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Alexandre Courbot
In-Reply-To: <20121116084958.GB20785-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>

On Fri, Nov 16, 2012 at 09:49:58AM +0100, Thierry Reding wrote:
> On Fri, Nov 16, 2012 at 03:38:22PM +0900, Alexandre Courbot wrote:
> > Make use of the power sequences specified in the device tree or platform
> > data to control how the backlight is powered on and off.
> > 
> > Signed-off-by: Alexandre Courbot <acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> > Reviewed-by: Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
> 
> Anton,
> 
> I would normally take pwm-backlight patches through the PWM tree, but
> since this patch depends on the first in this series, I think it would
> be easier if you took it through your tree along with the rest of the
> series. If that's okay with you:
> 
> Acked-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>

Sure, I'll take it. Thank you!

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alex Courbot @ 2012-11-16  9:44 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-pm@vger.kernel.org,
	Alexandre Courbot
In-Reply-To: <20121116072642.GA22291@lizard>

On 11/16/2012 04:26 PM, Anton Vorontsov wrote:
>> +#include "power_seq_delay.c"
>> +#include "power_seq_regulator.c"
>> +#include "power_seq_pwm.c"
>> +#include "power_seq_gpio.c"
>
> This is odd, although I remember you already explained why you have to
> include the .c files, instead of linking them separately. But I forgot the
> reason. :) I think this deserves a comment in the code.

This is because of the table right after these includes:

static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
};

The POWER_SEQ_*_TYPE macros are defined in the C files. It's the 
simplest way to initialize this table, and the code inside these C files 
is short and simple enough that I thought I would be forgiven. :)

At first everything was in power_seq.c and it was fine, then I thought 
it would be better to move resource support code into their own filesm 
and now everybody is asking. :P

But yeah, maybe it would be even better to not stop halfway and use 
dynamic linking.

Comment added for the time being. ;)

>> +static int of_power_seq_parse_step(struct device *dev,
>> +				   struct device_node *node,
>> +				   struct power_seq *seq,
>> +				   unsigned int step_nbr,
>> +				   struct list_head *resources)
>> +{
>> +	struct power_seq_step *step = &seq->steps[step_nbr];
>> +	struct power_seq_resource res, *res2;
>> +	const char *type;
>> +	int i, err;
>
> nit: one variable declaration per line.

Fair enough - but is that a convention? checkpatch.pl was happy with these.

Thanks,
Alex.



^ permalink raw reply

* Re: [BUGFIX] PM: Fix active child counting when disabled and forbidden
From: Rafael J. Wysocki @ 2012-11-16 10:10 UTC (permalink / raw)
  To: Huang Ying; +Cc: Alan Stern, linux-kernel, linux-pm
In-Reply-To: <1353029225.7176.314.camel@yhuang-dev>

On Friday, November 16, 2012 09:27:05 AM Huang Ying wrote:
> On Fri, 2012-11-16 at 02:29 +0100, Rafael J. Wysocki wrote:
> > On Friday, November 16, 2012 08:54:56 AM Huang Ying wrote:
> > > On Fri, 2012-11-16 at 01:55 +0100, Rafael J. Wysocki wrote:
> > > > On Friday, November 16, 2012 01:44:00 AM Rafael J. Wysocki wrote:
> > > > > On Friday, November 16, 2012 08:36:14 AM Huang Ying wrote:
> > > > > > On Thu, 2012-11-15 at 10:51 +0100, Rafael J. Wysocki wrote:
> > > > 
> > > > [...]
> > > > 
> > > > > > 
> > > > > > For this situation, if user "echo auto > .../power/control" for the
> > > > > > device, the runtime PM callbacks of device will be called.  I think that
> > > > > > is not intended.  So I think it is better to use some kind of flag or
> > > > > > state for that.
> > > > > 
> > > > > I'm not sure what situation exactly you have in mind.  Care to give an
> > > > > exact scenario?
> > > > 
> > > > Ah, I see.  When we've just called drv->remove(), there is a window in
> > > > which user space may cause the driver's runtime PM callbacks to be
> > > > executed by changing its attribute to "auto".
> > > > 
> > > > So perhaps we should check pci_dev->driver rather than pci_dev->dev.driver
> > > > in the runtime PM callbacks?  With a few more changes that should allow us
> > > > to close that race.
> > > 
> > > Yes.  And I think, with pci_dev->driver (after some changes suggested by
> > > Alan), we need not to use pm_runtime_get/put_skip_callbacks().
> > 
> > Good.  Can you please prepare a patch, then? :-)
> 
> Sure.

Cool, thanks!

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Mark Rutland @ 2012-11-16 10:35 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, rob.herring@calxeda.com, Mark Brown,
	David Woodhouse, Arnd Bergmann, Alexandre Courbot,
	linux-fbdev@vger.kernel.org, linux-pm@vger.kernel.org,
	Leela Krishna Amudala, devicetree-discuss@lists.ozlabs.org,
	linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org
In-Reply-To: <1353047903-14363-2-git-send-email-acourbot@nvidia.com>

On Fri, Nov 16, 2012 at 06:38:21AM +0000, Alexandre Courbot wrote:
> Some device drivers (e.g. panel or backlights) need to follow precise
> sequences for powering on and off, involving GPIOs, regulators, PWMs
> with a precise powering order and delays to respect between steps.
> These sequences are device-specific, and do not belong to a particular
> driver - therefore they have been performed by board-specific hook
> functions to far.
> 
> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but
> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree.

Given there are several ARM platforms that may have an interest in this, please
consider posting this to the ARM mailing list:
linux-arm-kernel@lists.infradead.org.

> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org>
> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
>  .../devicetree/bindings/power/power_seq.txt        | 121 +++++++
>  Documentation/power/power_seq.txt                  | 253 ++++++++++++++
>  drivers/power/Kconfig                              |   1 +
>  drivers/power/Makefile                             |   1 +
>  drivers/power/power_seq/Kconfig                    |   2 +
>  drivers/power/power_seq/Makefile                   |   1 +
>  drivers/power/power_seq/power_seq.c                | 376 +++++++++++++++++++++
>  drivers/power/power_seq/power_seq_delay.c          |  65 ++++
>  drivers/power/power_seq/power_seq_gpio.c           |  94 ++++++
>  drivers/power/power_seq/power_seq_pwm.c            |  82 +++++
>  drivers/power/power_seq/power_seq_regulator.c      |  83 +++++
>  include/linux/power_seq.h                          | 203 +++++++++++
>  12 files changed, 1282 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/power_seq.txt
>  create mode 100644 Documentation/power/power_seq.txt
>  create mode 100644 drivers/power/power_seq/Kconfig
>  create mode 100644 drivers/power/power_seq/Makefile
>  create mode 100644 drivers/power/power_seq/power_seq.c
>  create mode 100644 drivers/power/power_seq/power_seq_delay.c
>  create mode 100644 drivers/power/power_seq/power_seq_gpio.c
>  create mode 100644 drivers/power/power_seq/power_seq_pwm.c
>  create mode 100644 drivers/power/power_seq/power_seq_regulator.c
>  create mode 100644 include/linux/power_seq.h
> 
> diff --git a/Documentation/devicetree/bindings/power/power_seq.txt b/Documentation/devicetree/bindings/power/power_seq.txt
> new file mode 100644
> index 0000000..7880a6c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/power_seq.txt
> @@ -0,0 +1,121 @@
> +Runtime Interpreted Power Sequences
> +===================================
> +
> +Power sequences are sequential descriptions of actions to be performed on
> +power-related resources. Having these descriptions in a well-defined data format
> +allows us to take much of the board- or device- specific power control code out
> +of the kernel and place it into the device tree instead, making kernels less
> +board-dependant.
> +
> +A device typically makes use of multiple power sequences, for different purposes
> +such as powering on and off. All the power sequences of a given device are
> +grouped into a set. In the device tree, this set is a sub-node of the device
> +node named "power-sequences".
> +
> +Power Sequences Structure
> +-------------------------
> +Every device that makes use of power sequences must have a "power-sequences"
> +node into which individual power sequences are declared as sub-nodes. The name
> +of the node becomes the name of the sequence within the power sequences
> +framework.
> +
> +Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
> +must be named sequentially, with the first step named step0, the second step1,
> +etc. Failure to follow this rule will result in a parsing error.

Could we not encode the step number in the unit-address? i.e. step@N rather than
stepN.

If we ever add additional (non step) data to sequences it might make it easier
to filter, as we only reserve one name rather than a class of names.

> +
> +Power Sequences Steps
> +---------------------
> +Steps of a sequence describe an action to be performed on a resource. They
> +always include a "type" property which indicates what kind of resource this
> +step works on. Depending on the resource type, additional properties are defined
> +to control the action to be performed.
> +
> +"delay" type required properties:
> +  - delay: delay to wait (in microseconds)
> +
> +"regulator" type required properties:
> +  - id: name of the regulator to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"pwm" type required properties:
> +  - id: name of the PWM to use.
> +  - enable / disable: one of these two empty properties must be present to
> +                      enable or disable the resource
> +
> +"gpio" type required properties:
> +  - gpio: phandle of the GPIO to use.
> +  - value: value this GPIO should take. Must be 0 or 1.

Is there any reason for id to be a name rather than a phandle? It seems
inconsistent with the gpio case.

I also see from the example below that the gpio property is not just a phandle,
as it has the gpio-specifier appended. Is there a better way of describing this
format in the documentation?

> +Example
> +-------
> +Here are example sequences declared within a backlight device that use all the
> +supported resources types:
> +
> +       backlight {
> +               compatible = "pwm-backlight";
> +               ...
> +
> +               /* resources used by the power sequences */
> +               pwms = <&pwm 2 5000000>;
> +               pwm-names = "backlight";
> +               power-supply = <&backlight_reg>;
> +
> +               power-sequences {
> +                       power-on {
> +                               step0 {
> +                                       type = "regulator";
> +                                       id = "power";
> +                                       enable;
> +                               };
> +                               step1 {
> +                                       type = "delay";
> +                                       delay = <10000>;
> +                               };
> +                               step2 {
> +                                       type = "pwm";
> +                                       id = "backlight";
> +                                       enable;
> +                               };
> +                               step3 {
> +                                       type = "gpio";
> +                                       gpio = <&gpio 28 0>;
> +                                       value = <1>;
> +                               };
> +                       };
> +
> +                       power-off {
> +                               step0 {
> +                                       type = "gpio";
> +                                       gpio = <&gpio 28 0>;
> +                                       value = <0>;
> +                               };
> +                               step1 {
> +                                       type = "pwm";
> +                                       id = "backlight";
> +                                       disable;
> +                               };
> +                               step2 {
> +                                       type = "delay";
> +                                       delay = <10000>;
> +                               };
> +                               step3 {
> +                                       type = "regulator";
> +                                       id = "power";
> +                                       disable;
> +                               };
> +                       };
> +               };
> +       };
 
Thanks,
Mark


^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Anton Vorontsov @ 2012-11-16 12:25 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-pm@vger.kernel.org,
	Alexandre Courbot
In-Reply-To: <50A60AF6.9080509@nvidia.com>

On Fri, Nov 16, 2012 at 06:44:22PM +0900, Alex Courbot wrote:
> On 11/16/2012 04:26 PM, Anton Vorontsov wrote:
> >>+#include "power_seq_delay.c"
> >>+#include "power_seq_regulator.c"
> >>+#include "power_seq_pwm.c"
> >>+#include "power_seq_gpio.c"
> >
> >This is odd, although I remember you already explained why you have to
> >include the .c files, instead of linking them separately. But I forgot the
> >reason. :) I think this deserves a comment in the code.
> 
> This is because of the table right after these includes:
> 
> static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
> 	[POWER_SEQ_DELAY] = POWER_SEQ_DELAY_TYPE,
> 	[POWER_SEQ_REGULATOR] = POWER_SEQ_REGULATOR_TYPE,
> 	[POWER_SEQ_PWM] = POWER_SEQ_PWM_TYPE,
> 	[POWER_SEQ_GPIO] = POWER_SEQ_GPIO_TYPE,
> };
> 
> The POWER_SEQ_*_TYPE macros are defined in the C files. It's the
> simplest way to initialize this table, and the code inside these C
> files is short and simple enough that I thought I would be forgiven.
> :)

I think in the header file you could just write

extern ..... power_seq_delay_type;
#ifndef ...
#define power_seq_delay_type NULL
#endif

And then, in the .c file:

static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
	[POWER_SEQ_DELAY] = power_seq_delay_type,
	...
};

And then you can stop including the .c files directly, and link them
instead.

> At first everything was in power_seq.c and it was fine, then I
> thought it would be better to move resource support code into their
> own filesm and now everybody is asking. :P
> 
> But yeah, maybe it would be even better to not stop halfway and use
> dynamic linking.
> 
> Comment added for the time being. ;)
> 
> >>+static int of_power_seq_parse_step(struct device *dev,
> >>+				   struct device_node *node,
> >>+				   struct power_seq *seq,
> >>+				   unsigned int step_nbr,
> >>+				   struct list_head *resources)
> >>+{
> >>+	struct power_seq_step *step = &seq->steps[step_nbr];
> >>+	struct power_seq_resource res, *res2;
> >>+	const char *type;
> >>+	int i, err;
> >
> >nit: one variable declaration per line.
> 
> Fair enough - but is that a convention? checkpatch.pl was happy with these.

It's not a rule, although there is a small passage about it in CodingStyle
file when it describes commenting style. Though, some folks choose to
ignore this suggestion quite frequently, especially if variables have no
comments.

Often, the multiple declarations per line are used to hide ugly functions
w/ tons of variables, or just to confuse the reader for the fun of it.

There are exceptions, of course. E.g.

	int i, j, k; /* Our iterators. */

Is perfectly fine.

But
	int i, err;

At least to me seems weird, this stuff is logically disjunct.

Only human can truly differentiate when the stuff "looks better" together
or apart, so that's why checkpatch doesn't complain. Personally, I use
this rule of thumb: when in doubt, use just one declaration per line, it
is always OK. :)

Thanks,
Anton.

^ permalink raw reply

* Instantly boost your website's traffic
From: Instant Booster @ 2012-11-17  0:31 UTC (permalink / raw)
  To: linux-pm

What if you could drive 1000s of 
customers to your website from the 
major search-engines that are exclusively 
looking for your product/offer for free ?

What about an instant number one 
ranking for your keywords, for free ?!

We have developed a program that 
will automatically do this for you.


Visit our website:
http://www.advertise-bz.cn/affiliates/instantbooster/











Unsubscribe:
http://www.advertise-bz.cn/unsubscribe/



^ permalink raw reply

* Re: [PATCH v8 0/3] Runtime Interpreted Power Sequences
From: Stephen Warren @ 2012-11-16 17:08 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Alexandre Courbot, linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Leela Krishna Amudala, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Zhang, Rob Herring, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Anton Vorontsov, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	David Woodhouse
In-Reply-To: <1353047903-14363-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On 11/15/2012 11:38 PM, Alexandre Courbot wrote:
> Hopefully the final series before the feature gets merged. Anton Vorontsov
> kindly accepted to take it into his tree, so this series is mostly a call for
> acks, tests and reviews notices before the merge window for 3.8 opens. If you
> are interested in seeing this feature, please add your name.
> 
> This series also adds an entry for the subsystem into MAINTAINERS, setting me as
> the person in charge.

The series,
Tested-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On Ventana.

^ permalink raw reply

* Re: [PATCH v8 3/3] Take maintainership of power sequences
From: Stephen Warren @ 2012-11-16 17:09 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Alexandre Courbot, linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Mark Brown,
	Stephen Warren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Leela Krishna Amudala, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Zhang, Rob Herring, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Anton Vorontsov, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	David Woodhouse
In-Reply-To: <1353047903-14363-4-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

On 11/15/2012 11:38 PM, Alexandre Courbot wrote:
> Add entry for power sequences into MAINTAINERS with all the needed
> contact and SCM info.

Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

> diff --git a/MAINTAINERS b/MAINTAINERS

> +POWER SEQUENCES
> +M:	Alexandre Courbot <acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> +S:	Maintained

Given you're presumably working on this on NVIDIA's time, perhaps make
that "Supported" not "Maintained"?

^ permalink raw reply

* Re: [RFC PATCH 0/8][Sorted-buddy] mm: Linux VM Infrastructure to support Memory Power Management
From: Srivatsa S. Bhat @ 2012-11-16 18:32 UTC (permalink / raw)
  To: Dave Hansen
  Cc: Mel Gorman, Vaidyanathan Srinivasan, akpm, mjg59, paulmck,
	maxime.coquelin, loic.pallardy, arjan, kmpark, kamezawa.hiroyu,
	lenb, rjw, gargankita, amit.kachhap, thomas.abraham,
	santosh.shilimkar, linux-pm, linux-mm, linux-kernel, andi,
	SrinivasPandruvada
In-Reply-To: <509D34DA.5090303@linux.vnet.ibm.com>

On 11/09/2012 10:22 PM, Srivatsa S. Bhat wrote:
> On 11/09/2012 10:13 PM, Srivatsa S. Bhat wrote:
>> On 11/09/2012 10:04 PM, Srivatsa S. Bhat wrote:
>>> On 11/09/2012 09:43 PM, Dave Hansen wrote:
>>>> On 11/09/2012 07:23 AM, Srivatsa S. Bhat wrote:
>>>>> FWIW, kernbench is actually (and surprisingly) showing a slight performance
>>>>> *improvement* with this patchset, over vanilla 3.7-rc3, as I mentioned in
>>>>> my other email to Dave.
>>>>>
>>>>> https://lkml.org/lkml/2012/11/7/428
>>>>>
>>>>> I don't think I can dismiss it as an experimental error, because I am seeing
>>>>> those results consistently.. I'm trying to find out what's behind that.
>>>>
>>>> The only numbers in that link are in the date. :)  Let's see the
>>>> numbers, please.
>>>>
>>>
>>> Sure :) The reason I didn't post the numbers very eagerly was that I didn't
>>> want it to look ridiculous if it later turned out to be really an error in the
>>> experiment ;) But since I have seen it happening consistently I think I can
>>> post the numbers here with some non-zero confidence.
>>>
>>>> If you really have performance improvement to the memory allocator (or
>>>> something else) here, then surely it can be pared out of your patches
>>>> and merged quickly by itself.  Those kinds of optimizations are hard to
>>>> come by!
>>>>
>>>
>>> :-)
>>>
>>> Anyway, here it goes:
>>>
>>> Test setup:
>>> ----------
>>> x86 2-socket quad-core machine. (CONFIG_NUMA=n because I figured that my
>>> patchset might not handle NUMA properly). Mem region size = 512 MB.
>>>
>>
>> For CONFIG_NUMA=y on the same machine, the difference between the 2 kernels
>> was much lesser, but nevertheless, this patchset performed better. I wouldn't
>> vouch that my patchset handles NUMA correctly, but here are the numbers from
>> that run anyway (at least to show that I really found the results to be
>> repeatable):
>>

I fixed up the NUMA case (I'll post the updated patch for that soon) and
ran a fresh set of kernbench runs. The difference between mainline and this
patchset is quite tiny; so we can't really say that this patchset shows a
performance improvement over mainline. However, I can safely conclude that
this patchset doesn't show any performance _degradation_ w.r.t mainline
in kernbench.

Results from one of the recent kernbench runs:
---------------------------------------------

Kernbench log for Vanilla 3.7-rc3
=================================
Kernel: 3.7.0-rc3
Average Optimal load -j 32 Run (std deviation):
Elapsed Time 330.39 (0.746257)
User Time 4283.63 (3.39617)
System Time 604.783 (2.72629)
Percent CPU 1479 (3.60555)
Context Switches 845634 (6031.22)
Sleeps 833655 (6652.17)


Kernbench log for Sorted-buddy
==============================
Kernel: 3.7.0-rc3-sorted-buddy
Average Optimal load -j 32 Run (std deviation):
Elapsed Time 329.967 (2.76789)
User Time 4230.02 (2.15324)
System Time 599.793 (1.09988)
Percent CPU 1463.33 (11.3725)
Context Switches 840530 (1646.75)
Sleeps 833732 (2227.68)

Regards,
Srivatsa S. Bhat


^ permalink raw reply

* [RFC PATCH UPDATED 4/8] mm: Add helpers to retrieve node region and zone region for a given page
From: Srivatsa S. Bhat @ 2012-11-16 18:39 UTC (permalink / raw)
  To: akpm, mgorman, mjg59, paulmck, dave, maxime.coquelin,
	loic.pallardy, arjan, kmpark, kamezawa.hiroyu, lenb, rjw
  Cc: Srivatsa S. Bhat, gargankita, amit.kachhap, svaidy,
	thomas.abraham, santosh.shilimkar, linux-pm, linux-mm,
	linux-kernel, andi, SrinivasPandruvada
In-Reply-To: <20121106195310.6941.91123.stgit@srivatsabhat.in.ibm.com>

This version of the patch includes a bug-fix for page_node_region_id()
which used to break the NUMA case.

--------------------------------------------------------------------->

From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Subject: mm: Add helpers to retrieve node region and zone region for a given page

Given a page, we would like to have an efficient mechanism to find out
the node memory region and the zone memory region to which it belongs.

Since the node is assumed to be divided into equal-sized node memory
regions, the node memory region index can be obtained by simply right-shifting
the page's pfn by 'mem_region_shift'.

But finding the corresponding zone memory region's index in the zone is
not that straight-forward. To have a O(1) algorithm to find it out, define a
zone_region_idx[] array to store the zone memory region indices for every
node memory region.

To illustrate, consider the following example:

	|<---------------------Node---------------------->|
	 _________________________________________________
	|      Node mem reg 0 	|      Node mem reg 1     |
	|_______________________|_________________________|

	 _________________________________________________
	|   ZONE_DMA    |	ZONE_NORMAL		  |
	|_______________|_________________________________|


In the above figure,

Node mem region 0:
------------------
This region corresponds to the first zone mem region in ZONE_DMA and also
the first zone mem region in ZONE_NORMAL. Hence its index array would look
like this:
    node_regions[0].zone_region_idx[ZONE_DMA]     == 0
    node_regions[0].zone_region_idx[ZONE_NORMAL]  == 0


Node mem region 1:
------------------
This region corresponds to the second zone mem region in ZONE_NORMAL. Hence
its index array would look like this:
    node_regions[1].zone_region_idx[ZONE_NORMAL]  == 1


Using this index array, we can quickly obtain the zone memory region to
which a given page belongs.

Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 include/linux/mm.h     |   24 ++++++++++++++++++++++++
 include/linux/mmzone.h |    7 +++++++
 mm/page_alloc.c        |    2 ++
 3 files changed, 33 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 19c4fb0..32457c7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -702,6 +702,30 @@ static inline struct zone *page_zone(const struct page *page)
 	return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
 }
 
+static inline int page_node_region_id(const struct page *page,
+				      const pg_data_t *pgdat)
+{
+	return (page_to_pfn(page) - pgdat->node_start_pfn) >> MEM_REGION_SHIFT;
+}
+
+/**
+ * Return the index of the region to which the page belongs, within its zone.
+ *
+ * Given a page, find the absolute (node) region as well as the zone to which
+ * it belongs. Then find the region within the zone that corresponds to that
+ * absolute (node) region, and return its index.
+ */
+static inline int page_zone_region_id(const struct page *page)
+{
+	pg_data_t *pgdat = NODE_DATA(page_to_nid(page));
+	enum zone_type z_num = page_zonenum(page);
+	unsigned long node_region_idx;
+
+	node_region_idx = page_node_region_id(page, pgdat);
+
+	return pgdat->node_regions[node_region_idx].zone_region_idx[z_num];
+}
+
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
 static inline void set_page_section(struct page *page, unsigned long section)
 {
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 9f923aa..3982354 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -336,6 +336,13 @@ struct node_mem_region {
 	unsigned long spanned_pages;
 	int idx;
 	int node;
+
+	/*
+	 * A physical (node) region could be split across multiple zones.
+	 * Store the indices of the corresponding regions of each such
+	 * zone for this physical (node) region.
+	 */
+	int zone_region_idx[MAX_NR_ZONES];
 	struct pglist_data *pgdat;
 };
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c00f72d..7fd89cd 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4621,6 +4621,8 @@ void init_zone_memory_regions(struct pglist_data *pgdat)
 						         end_pfn);
 			z->zone_mem_region[idx].present_pages =
 						end_pfn - start_pfn - absent;
+
+			region->zone_region_idx[zone_idx(z)] = idx;
 			idx++;
 		}
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* [Asus Eee PC 1215B] Resume doesn't work after suspend
From: Vincenzo Costa @ 2012-11-16 20:48 UTC (permalink / raw)
  To: linux-pm; +Cc: 1076103

[1.] [Asus Eee PC 1215B] Resume doesn't work after suspend

[2.]
Description:
I had this bug with kubuntu 11.10 and it is still present after
upgrade to 12.04. I have an Asus 1215b laptop with Amd C60 cpu.

If I try to suspend the laptop, suspend seems to work at first, but then:
1) most of the times, the attempt to resume it brings to a black
screen as a result.
2) After that, it is necessary to switch off the laptop by keeping the
power button pressed.
3) Trying to switch on the laptop again produces a black screen and no
boot, unless I first remove the power cord and the battery, and try
again after putting them back in place.
4) Sometimes the first suspend attempt works correctly, but then,
after a succesful resume, the second attempt reproduces the bug again.

I tried the followings to see if it could help:
1) Changed from radeon driver to ATI proprietary fglrx driver, same result.
2) Installed the kernel 3.5.7 from
http://kernel.ubuntu.com/~kernel-ppa/mainline, but I had problems with
the fglrx ATI driver, and the first suspend and resume attempt
immediatelly reproduced the bug

The bug has been present with all the kernel versions used with
kubuntu 11.10 to current kernel version in Kubuntu 12.0.4.1:
uname -r: 3.2.0-32-generic

Last, the bug is present also with upstream kernel:
uname -r:
3.7.0-030700rc5-generic

Link to launchpad report:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1076103


[3.] kernel


[4.] Linux version 3.7.0-030700rc5-generic (apw@gomeisa) (gcc version
4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #201211110835 SMP Sun Nov 11
13:35:49 UTC 2012

[5.]

[6.]

[7.] Description:    Ubuntu 12.04.1 LTS
Release:        12.04

[7.1] Linux teresapc 3.7.0-030700rc5-generic #201211110835 SMP Sun Nov
11 13:35:49 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

Gnu C                  4.6
Gnu make               3.81
binutils               2.22
util-linux             2.20.1
mount                  support
module-init-tools      3.16
e2fsprogs              1.42
pcmciautils            018
Linux C Library        2.15
Dynamic linker (ldd)   2.15
Procps                 3.2.8
Net-tools              1.60
Kbd                    1.15.2
Sh-utils               8.13
wireless-tools         30
Modules Loaded         rfcomm bnep parport_pc bluetooth ppdev
binfmt_misc dm_crypt joydev kvm_amd kvm eeepc_wmi asus_wmi
snd_hda_codec_realtek sparse_keymap snd_hda_codec_hdmi snd_seq_midi
snd_hda_intel snd_hda_codec uvcvideo arc4 snd_rawmidi
snd_seq_midi_event videobuf2_core snd_hwdep videodev ath9k snd_pcm
sp5100_tco snd_seq psmouse microcode videobuf2_vmalloc i2c_piix4
videobuf2_memops k10temp serio_raw mac80211 snd_timer snd_seq_device
ath9k_common ath9k_hw ath snd cfg80211 mac_hid soundcore msr
snd_page_alloc lp parport radeon ttm drm_kms_helper drm atl1c
i2c_algo_bit wmi video


[7.2.] processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 20
model           : 2
model name      : AMD C-60 APU with Radeon(tm) HD Graphics
stepping        : 0
microcode       : 0x5000101
cpu MHz         : 800.000
cache size      : 512 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 6
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge
mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext
fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc
extd_apicid aperfmperf pni monitor ssse3 cx16 popcnt lahf_lm
cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch
ibs skinit wdt arat cpb hw_pstate npt lbrv svm_lock nrip_save
pausefilter
bogomips        : 1995.87
TLB size        : 1024 4K pages
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate cpb

processor       : 1
vendor_id       : AuthenticAMD
cpu family      : 20
model           : 2
model name      : AMD C-60 APU with Radeon(tm) HD Graphics
stepping        : 0
microcode       : 0x5000101
cpu MHz         : 800.000
cache size      : 512 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fpu             : yes
fpu_exception   : yes
cpuid level     : 6
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge
mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext
fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc
extd_apicid aperfmperf pni monitor ssse3 cx16 popcnt lahf_lm
cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch
ibs skinit wdt arat cpb hw_pstate npt lbrv svm_lock nrip_save
pausefilter
bogomips        : 1995.87
TLB size        : 1024 4K pages
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate cpb

[7.3] rfcomm 47923 0 - Live 0x0000000000000000
bnep 18400 2 - Live 0x0000000000000000
parport_pc 32867 0 - Live 0x0000000000000000
bluetooth 219394 10 rfcomm,bnep, Live 0x0000000000000000
ppdev 17114 0 - Live 0x0000000000000000
binfmt_misc 17541 1 - Live 0x0000000000000000
dm_crypt 23073 0 - Live 0x0000000000000000
joydev 17614 0 - Live 0x0000000000000000
kvm_amd 60195 0 - Live 0x0000000000000000
kvm 441559 1 kvm_amd, Live 0x0000000000000000
eeepc_wmi 13152 0 - Live 0x0000000000000000
asus_wmi 24582 1 eeepc_wmi, Live 0x0000000000000000
snd_hda_codec_realtek 79808 1 - Live 0x0000000000000000
sparse_keymap 13891 1 asus_wmi, Live 0x0000000000000000
snd_hda_codec_hdmi 37116 1 - Live 0x0000000000000000
snd_seq_midi 13325 0 - Live 0x0000000000000000
snd_hda_intel 38522 5 - Live 0x0000000000000000
snd_hda_codec 140413 3
snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_intel, Live
0x0000000000000000
uvcvideo 82215 0 - Live 0x0000000000000000
arc4 12574 2 - Live 0x0000000000000000
snd_rawmidi 30750 1 snd_seq_midi, Live 0x0000000000000000
snd_seq_midi_event 14900 1 snd_seq_midi, Live 0x0000000000000000
videobuf2_core 36138 1 uvcvideo, Live 0x0000000000000000
snd_hwdep 17765 1 snd_hda_codec, Live 0x0000000000000000
videodev 130085 2 uvcvideo,videobuf2_core, Live 0x0000000000000000
ath9k 147526 0 - Live 0x0000000000000000
snd_pcm 102478 3 snd_hda_codec_hdmi,snd_hda_intel,snd_hda_codec, Live
0x0000000000000000
sp5100_tco 13792 0 - Live 0x0000000000000000
snd_seq 61931 2 snd_seq_midi,snd_seq_midi_event, Live 0x0000000000000000
psmouse 92405 0 - Live 0x0000000000000000
microcode 23076 0 - Live 0x0000000000000000
videobuf2_vmalloc 12861 1 uvcvideo, Live 0x0000000000000000
i2c_piix4 13505 0 - Live 0x0000000000000000
videobuf2_memops 13405 1 videobuf2_vmalloc, Live 0x0000000000000000
k10temp 13174 0 - Live 0x0000000000000000
serio_raw 13216 0 - Live 0x0000000000000000
mac80211 573599 1 ath9k, Live 0x0000000000000000
snd_timer 29990 2 snd_pcm,snd_seq, Live 0x0000000000000000
snd_seq_device 14498 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0x0000000000000000
ath9k_common 14054 1 ath9k, Live 0x0000000000000000
ath9k_hw 417643 2 ath9k,ath9k_common, Live 0x0000000000000000
ath 24124 3 ath9k,ath9k_common,ath9k_hw, Live 0x0000000000000000
snd 83674 20 snd_hda_codec_realtek,snd_hda_codec_hdmi,snd_hda_intel,snd_hda_codec,snd_rawmidi,snd_hwdep,snd_pcm,snd_seq,snd_timer,snd_seq_device,
Live 0x0000000000000000
cfg80211 217913 3 ath9k,mac80211,ath, Live 0x0000000000000000
mac_hid 13254 0 - Live 0x0000000000000000
soundcore 15092 1 snd, Live 0x0000000000000000
msr 12909 0 - Live 0x0000000000000000
snd_page_alloc 18799 2 snd_hda_intel,snd_pcm, Live 0x0000000000000000
lp 17800 0 - Live 0x0000000000000000
parport 46563 3 parport_pc,ppdev,lp, Live 0x0000000000000000
radeon 921927 0 - Live 0x0000000000000000
ttm 88493 1 radeon, Live 0x0000000000000000
drm_kms_helper 46934 1 radeon, Live 0x0000000000000000
drm 286536 3 radeon,ttm,drm_kms_helper, Live 0x0000000000000000
atl1c 46188 0 - Live 0x0000000000000000
i2c_algo_bit 13565 1 radeon, Live 0x0000000000000000
wmi 19257 1 asus_wmi, Live 0x0000000000000000
video 19413 1 asus_wmi, Live 0x0000000000000000

[7.4] cat /proc/ioports
0000-0cf7 : PCI Bus 0000:00
  0000-001f : dma1
  0020-0021 : pic1
  0040-0043 : timer0
  0050-0053 : timer1
  0060-0060 : keyboard
  0062-0062 : EC data
  0064-0064 : keyboard
  0066-0066 : EC cmd
  0070-0071 : rtc0
  0080-008f : dma page reg
  00a0-00a1 : pic2
  00c0-00df : dma2
  00f0-00ff : fpu
  03c0-03df : vga+
  040b-040b : pnp 00:02
    040b-040b : pnp 00:08
  04d0-04d1 : pnp 00:08
  04d6-04d6 : pnp 00:02
    04d6-04d6 : pnp 00:08
  0800-089f : pnp 00:02
    0800-089f : pnp 00:08
      0800-0803 : ACPI PM1a_EVT_BLK
      0804-0805 : ACPI PM1a_CNT_BLK
      0808-080b : ACPI PM_TMR
      0810-0815 : ACPI CPU throttle
      0820-0827 : ACPI GPE0_BLK
  0900-090f : pnp 00:02
    0900-090f : pnp 00:08
  0910-091f : pnp 00:02
    0910-091f : pnp 00:08
  0b00-0b0f : pnp 00:08
  0b20-0b3f : pnp 00:02
    0b20-0b3f : pnp 00:08
  0c00-0c01 : pnp 00:02
    0c00-0c01 : pnp 00:08
  0c14-0c14 : pnp 00:02
    0c14-0c14 : pnp 00:08
  0c50-0c51 : pnp 00:02
    0c50-0c51 : pnp 00:08
  0c52-0c52 : pnp 00:02
    0c52-0c52 : pnp 00:08
  0c6c-0c6c : pnp 00:02
    0c6c-0c6c : pnp 00:08
  0c6f-0c6f : pnp 00:02
    0c6f-0c6f : pnp 00:08
  0cd0-0cd1 : pnp 00:02
    0cd0-0cd1 : pnp 00:08
  0cd2-0cd3 : pnp 00:02
    0cd2-0cd3 : pnp 00:08
  0cd4-0cd5 : pnp 00:02
    0cd4-0cd5 : pnp 00:08
  0cd6-0cd7 : pnp 00:02
    0cd6-0cd7 : pnp 00:08
  0cd8-0cdf : pnp 00:02
    0cd8-0cdf : pnp 00:08
0cf8-0cff : PCI conf1
0d00-ffff : PCI Bus 0000:00
  d000-dfff : PCI Bus 0000:04
  e000-efff : PCI Bus 0000:02
    e000-e07f : 0000:02:00.0
      e000-e07f : atl1c
  f000-f0ff : 0000:00:01.0
  f100-f10f : 0000:00:11.0
    f100-f10f : ahci
  f110-f113 : 0000:00:11.0
    f110-f113 : ahci
  f120-f127 : 0000:00:11.0
    f120-f127 : ahci
  f130-f133 : 0000:00:11.0
    f130-f133 : ahci
  f140-f147 : 0000:00:11.0
    f140-f147 : ahci
  fe00-fefe : pnp 00:02
    fe00-fefe : pnp 00:08

cat /proc/iomem
00000000-0000ffff : reserved
00010000-0009ebff : System RAM
0009ec00-0009ffff : reserved
000a0000-000bffff : PCI Bus 0000:00
000c0000-000ce3ff : Video ROM
000e0000-000fffff : reserved
  000f0000-000fffff : System ROM
00100000-66c63fff : System RAM
  01000000-016d7380 : Kernel code
  016d7381-01ce6abf : Kernel data
  01de7000-01f46fff : Kernel bss
66c64000-66cb4fff : ACPI Non-volatile Storage
66cb5000-66cd5fff : reserved
66cd6000-66ce6fff : ACPI Non-volatile Storage
66ce7000-66d0afff : reserved
66d0b000-66d0bfff : System RAM
66d0c000-66d0cfff : ACPI Non-volatile Storage
66d0d000-66d10fff : System RAM
66d11000-66d15fff : ACPI Non-volatile Storage
66d16000-66d1cfff : reserved
66d1d000-66d23fff : ACPI Non-volatile Storage
66d24000-66d4afff : reserved
66d4b000-66d8dfff : ACPI Non-volatile Storage
66d8e000-66efffff : System RAM
66f00000-67ffffff : RAM buffer
7f000000-ffffffff : PCI Bus 0000:00
  c0000000-cfffffff : 0000:00:01.0
  d0000000-dfffffff : PCI Bus 0000:04
  e0000000-efffffff : PCI MMCONFIG 0000 [bus 00-ff]
    e0000000-efffffff : reserved
      e0000000-efffffff : pnp 00:01
  fdf00000-fe8fffff : PCI Bus 0000:04
  fe900000-fe9fffff : PCI Bus 0000:02
    fe900000-fe93ffff : 0000:02:00.0
      fe900000-fe93ffff : atl1c
  fea00000-feafffff : PCI Bus 0000:01
    fea00000-fea0ffff : 0000:01:00.0
      fea00000-fea0ffff : ath9k
  feb00000-feb3ffff : 0000:00:01.0
  feb40000-feb43fff : 0000:00:14.2
    feb40000-feb43fff : ICH HD audio
  feb44000-feb47fff : 0000:00:01.1
    feb44000-feb47fff : ICH HD audio
  feb48000-feb480ff : 0000:00:13.2
    feb48000-feb480ff : ehci_hcd
  feb49000-feb49fff : 0000:00:13.0
    feb49000-feb49fff : ohci_hcd
  feb4a000-feb4a0ff : 0000:00:12.2
    feb4a000-feb4a0ff : ehci_hcd
  feb4b000-feb4bfff : 0000:00:12.0
    feb4b000-feb4bfff : ohci_hcd
  feb4c000-feb4c3ff : 0000:00:11.0
    feb4c000-feb4c3ff : ahci
  fec00000-fec00fff : reserved
    fec00000-fec003ff : IOAPIC 0
  fec10000-fec10fff : reserved
    fec10000-fec10fff : pnp 00:02
      fec10000-fec1001f : pnp 00:08
  fed00000-fed00fff : reserved
    fed00000-fed00fff : pnp 00:02
      fed00000-fed003ff : HPET 0
  fed40000-fed44fff : pnp 00:08
  fed61000-fed70fff : reserved
    fed61000-fed70fff : pnp 00:02
  fed80000-fed8ffff : reserved
    fed80000-fed8ffff : pnp 00:02
      fed80000-fed80fff : pnp 00:08
  fee00000-fee00fff : Local APIC
    fee00000-fee00fff : pnp 00:02
  fef00000-ffffffff : reserved
    ffb80000-ffbfffff : pnp 00:08
    ffe00000-ffffffff : pnp 00:02

[7.5] lspci -vvv
00:00.0 Host bridge: Advanced Micro Devices [AMD] Family 14h Processor
Root Complex
        Subsystem: Advanced Micro Devices [AMD] Family 14h Processor
Root Complex
        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32

00:01.0 VGA compatible controller: Advanced Micro Devices [AMD] nee
ATI Wrestler [Radeon HD 6290] (prog-if 00 [VGA controller])
        Subsystem: ASUSTeK Computer Inc. Device 84e4
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 18
        Region 0: Memory at c0000000 (32-bit, prefetchable) [size=256M]
        Region 1: I/O ports at f000 [size=256]
        Region 2: Memory at feb00000 (32-bit, non-prefetchable) [size=256K]
        Expansion ROM at <unassigned> [disabled]
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0-,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Complex Integrated Endpoint, MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<4us, L1 unlimited
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 128 bytes
                DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
AuxPwr- TransPend-
                LnkCap: Port #0, Speed unknown, Width x0, ASPM
unknown, Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep- BwNot-
                LnkCtl: ASPM Disabled; Disabled- Retrain- CommClk-
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed unknown, Width x0, TrErr- Train-
SlotClk- DLActive- BWMgmt- ABWMgmt-
                DevCap2: Completion Timeout: Not Supported, TimeoutDis-
                DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis-, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [a0] MSI: Enable- Count=1/1 Maskable- 64bit+
                Address: 0000000000000000  Data: 0000
        Capabilities: [100 v1] Vendor Specific Information: ID=0001
Rev=1 Len=010 <?>
        Kernel modules: radeon

00:01.1 Audio device: Advanced Micro Devices [AMD] nee ATI Wrestler
HDMI Audio [Radeon HD 6250/6310]
        Subsystem: ASUSTeK Computer Inc. Device 84e4
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin B routed to IRQ 40
        Region 0: Memory at feb44000 (32-bit, non-prefetchable) [size=16K]
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0-,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Complex Integrated Endpoint, MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<4us, L1 unlimited
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 128 bytes
                DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
AuxPwr- TransPend-
                LnkCap: Port #0, Speed unknown, Width x0, ASPM
unknown, Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep- BwNot-
                LnkCtl: ASPM Disabled; Disabled- Retrain- CommClk-
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed unknown, Width x0, TrErr- Train-
SlotClk- DLActive- BWMgmt- ABWMgmt-
                DevCap2: Completion Timeout: Not Supported, TimeoutDis-
                DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis-, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit+
                Address: 00000000fee0200c  Data: 4181
        Capabilities: [100 v1] Vendor Specific Information: ID=0001
Rev=1 Len=010 <?>
        Kernel driver in use: snd_hda_intel
        Kernel modules: snd-hda-intel

00:04.0 PCI bridge: Advanced Micro Devices [AMD] Family 14h Processor
Root Port (prog-if 00 [Normal decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
        I/O behind bridge: 0000f000-00000fff
        Memory behind bridge: fea00000-feafffff
        Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
        Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ <SERR- <PERR-
        BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
                PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA
PME(D0+,D1-,D2-,D3hot+,D3cold+)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Port (Slot+), MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<64ns, L1 <1us
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 512 bytes
                DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
AuxPwr- TransPend-
                LnkCap: Port #1, Speed 2.5GT/s, Width x1, ASPM L0s L1,
Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep+ BwNot+
                LnkCtl: ASPM L1 Enabled; RCB 64 bytes Disabled-
Retrain- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train-
SlotClk+ DLActive+ BWMgmt- ABWMgmt-
                SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd-
HotPlug- Surprise-
                        Slot #4, PowerLimit 75.000W; Interlock- NoCompl+
                SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet-
CmdCplt- HPIrq- LinkChg-
                        Control: AttnInd Unknown, PwrInd Unknown,
Power- Interlock-
                SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt-
PresDet+ Interlock-
                        Changed: MRL- PresDet+ LinkState+
                RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal-
PMEIntEna- CRSVisible-
                RootCap: CRSVisible-
                RootSta: PME ReqID 0000, PMEStatus- PMEPending-
                DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ ARIFwd-
                DevCtl2: Completion Timeout: 65ms to 210ms, TimeoutDis- ARIFwd-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis+, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [a0] MSI: Enable- Count=1/1 Maskable- 64bit+
                Address: 0000000000000000  Data: 0000
        Capabilities: [b0] Subsystem: Advanced Micro Devices [AMD] Device 1234
        Capabilities: [b8] HyperTransport: MSI Mapping Enable+ Fixed+
        Capabilities: [100 v1] Vendor Specific Information: ID=0001
Rev=1 Len=010 <?>
        Kernel driver in use: pcieport
        Kernel modules: shpchp

00:05.0 PCI bridge: Advanced Micro Devices [AMD] Family 14h Processor
Root Port (prog-if 00 [Normal decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Bus: primary=00, secondary=02, subordinate=02, sec-latency=0
        I/O behind bridge: 0000e000-0000efff
        Memory behind bridge: fe900000-fe9fffff
        Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
        Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
        BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
                PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA
PME(D0+,D1-,D2-,D3hot+,D3cold+)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Port (Slot+), MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<64ns, L1 <1us
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 512 bytes
                DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
AuxPwr- TransPend-
                LnkCap: Port #2, Speed 2.5GT/s, Width x1, ASPM L0s L1,
Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep+ BwNot+
                LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled-
Retrain- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train-
SlotClk+ DLActive+ BWMgmt- ABWMgmt-
                SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd-
HotPlug- Surprise-
                        Slot #5, PowerLimit 75.000W; Interlock- NoCompl+
                SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet-
CmdCplt- HPIrq- LinkChg-
                        Control: AttnInd Unknown, PwrInd Unknown,
Power- Interlock-
                SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt-
PresDet+ Interlock-
                        Changed: MRL- PresDet+ LinkState+
                RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal-
PMEIntEna- CRSVisible-
                RootCap: CRSVisible-
                RootSta: PME ReqID 0000, PMEStatus- PMEPending-
                DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ ARIFwd-
                DevCtl2: Completion Timeout: 65ms to 210ms, TimeoutDis- ARIFwd-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis+, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [a0] MSI: Enable- Count=1/1 Maskable- 64bit+
                Address: 0000000000000000  Data: 0000
        Capabilities: [b0] Subsystem: Advanced Micro Devices [AMD] Device 1234
        Capabilities: [b8] HyperTransport: MSI Mapping Enable+ Fixed+
        Capabilities: [100 v1] Vendor Specific Information: ID=0001
Rev=1 Len=010 <?>
        Kernel driver in use: pcieport
        Kernel modules: shpchp

00:11.0 SATA controller: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode] (prog-if 01 [AHCI 1.0])
        Subsystem: Advanced Micro Devices [AMD] nee ATI Device 4390
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32
        Interrupt: pin A routed to IRQ 19
        Region 0: I/O ports at f140 [size=8]
        Region 1: I/O ports at f130 [size=4]
        Region 2: I/O ports at f120 [size=8]
        Region 3: I/O ports at f110 [size=4]
        Region 4: I/O ports at f100 [size=16]
        Region 5: Memory at feb4c000 (32-bit, non-prefetchable) [size=1K]
        Capabilities: [70] SATA HBA v1.0 InCfgSpace
        Capabilities: [a4] PCI Advanced Features
                AFCap: TP+ FLR+
                AFCtrl: FLR-
                AFStatus: TP-
        Kernel driver in use: ahci

00:12.0 USB controller: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB OHCI0 Controller (prog-if 10 [OHCI])
        Subsystem: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 18
        Region 0: Memory at feb4b000 (32-bit, non-prefetchable) [size=4K]
        Kernel driver in use: ohci_hcd

00:12.2 USB controller: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB EHCI Controller (prog-if 20 [EHCI])
        Subsystem: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB EHCI Controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32, Cache Line Size: 64 bytes
        Interrupt: pin B routed to IRQ 17
        Region 0: Memory at feb4a000 (32-bit, non-prefetchable) [size=256]
        Capabilities: [c0] Power Management version 2
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
                Bridge: PM- B3+
        Capabilities: [e4] Debug port: BAR=1 offset=00e0
        Kernel driver in use: ehci_hcd

00:13.0 USB controller: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB OHCI0 Controller (prog-if 10 [OHCI])
        Subsystem: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 18
        Region 0: Memory at feb49000 (32-bit, non-prefetchable) [size=4K]
        Kernel driver in use: ohci_hcd

00:13.2 USB controller: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB EHCI Controller (prog-if 20 [EHCI])
        Subsystem: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 USB EHCI Controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32, Cache Line Size: 64 bytes
        Interrupt: pin B routed to IRQ 17
        Region 0: Memory at feb48000 (32-bit, non-prefetchable) [size=256]
        Capabilities: [c0] Power Management version 2
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
                Bridge: PM- B3+
        Capabilities: [e4] Debug port: BAR=1 offset=00e0
        Kernel driver in use: ehci_hcd

00:14.0 SMBus: Advanced Micro Devices [AMD] nee ATI SBx00 SMBus
Controller (rev 42)
        Subsystem: Advanced Micro Devices [AMD] nee ATI SBx00 SMBus Controller
        Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap- 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Kernel modules: sp5100_tco, i2c-piix4

00:14.2 Audio device: Advanced Micro Devices [AMD] nee ATI SBx00
Azalia (Intel HDA) (rev 40)
        Subsystem: ASUSTeK Computer Inc. Device 841c
        Control: I/O- Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=slow >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 32, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 16
        Region 0: Memory at feb40000 (64-bit, non-prefetchable)
[disabled] [size=16K]
        Capabilities: [50] Power Management version 2
                Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA
PME(D0+,D1-,D2-,D3hot+,D3cold+)
                Status: D3 NoSoftRst- PME-Enable+ DSel=0 DScale=0 PME-
        Kernel driver in use: snd_hda_intel
        Kernel modules: snd-hda-intel

00:14.3 ISA bridge: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 LPC host controller (rev 40)
        Subsystem: Advanced Micro Devices [AMD] nee ATI
SB7x0/SB8x0/SB9x0 LPC host controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle+ MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0

00:14.4 PCI bridge: Advanced Micro Devices [AMD] nee ATI SBx00 PCI to
PCI Bridge (rev 40) (prog-if 01 [Subtractive decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop+
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 64
        Bus: primary=00, secondary=03, subordinate=03, sec-latency=64
        I/O behind bridge: 0000f000-00000fff
        Memory behind bridge: fff00000-000fffff
        Prefetchable memory behind bridge: fff00000-000fffff
        Secondary status: 66MHz- FastB2B+ ParErr- DEVSEL=medium
>TAbort- <TAbort- <MAbort+ <SERR- <PERR-
        BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
                PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-

00:15.0 PCI bridge: Advanced Micro Devices [AMD] nee ATI
SB700/SB800/SB900 PCI to PCI bridge (PCIE port 0) (prog-if 00 [Normal
decode])
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Bus: primary=00, secondary=04, subordinate=06, sec-latency=0
        I/O behind bridge: 0000d000-0000dfff
        Memory behind bridge: fdf00000-fe8fffff
        Prefetchable memory behind bridge: 00000000d0000000-00000000dfffffff
        Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
        BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
                PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0-,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Port (Slot+), MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<64ns, L1 <1us
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 128 bytes
                DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq-
AuxPwr- TransPend-
                LnkCap: Port #247, Speed 2.5GT/s, Width x1, ASPM L0s
L1, Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep+ BwNot+
                LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed unknown, Width x16, TrErr- Train-
SlotClk+ DLActive- BWMgmt- ABWMgmt-
                SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd-
HotPlug+ Surprise-
                        Slot #0, PowerLimit 0.000W; Interlock- NoCompl+
                SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet-
CmdCplt- HPIrq- LinkChg-
                        Control: AttnInd Unknown, PwrInd Unknown,
Power- Interlock-
                SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt-
PresDet- Interlock-
                        Changed: MRL- PresDet- LinkState-
                RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal-
PMEIntEna- CRSVisible-
                RootCap: CRSVisible-
                RootSta: PME ReqID 0000, PMEStatus- PMEPending-
                DevCap2: Completion Timeout: Range ABCD, TimeoutDis+ ARIFwd-
                DevCtl2: Completion Timeout: 65ms to 210ms, TimeoutDis- ARIFwd-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis-, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [a0] MSI: Enable- Count=1/1 Maskable- 64bit+
                Address: 0000000000000000  Data: 0000
        Capabilities: [b0] Subsystem: Advanced Micro Devices [AMD] nee
ATI Device 0000
        Capabilities: [b8] HyperTransport: MSI Mapping Enable+ Fixed+
        Capabilities: [100 v1] Vendor Specific Information: ID=0001
Rev=1 Len=010 <?>
        Kernel driver in use: pcieport
        Kernel modules: shpchp

00:18.0 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 0 (rev 43)
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.1 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 1
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.2 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 2
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.3 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 3
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Capabilities: [f0] Secure device <?>
        Kernel driver in use: k10temp
        Kernel modules: k10temp

00:18.4 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 4
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.5 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 6
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.6 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 5
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

00:18.7 Host bridge: Advanced Micro Devices [AMD] Family 12h/14h
Processor Function 7
        Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-

01:00.0 Network controller: Atheros Communications Inc. AR9285
Wireless Network Adapter (PCI-Express) (rev 01)
        Subsystem: AzureWave AW-NE785 / AW-NE785H 802.11bgn Wireless
Full or Half-size Mini PCIe Card
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 16
        Region 0: Memory at fea00000 (64-bit, non-prefetchable) [size=64K]
        Capabilities: [40] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2- AuxCurrent=375mA
PME(D0+,D1+,D2-,D3hot+,D3cold+)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit-
                Address: 00000000  Data: 0000
        Capabilities: [60] Express (v2) Legacy Endpoint, MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<512ns, L1 <64us
                        ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
                DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal-
Unsupported-
                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
                        MaxPayload 128 bytes, MaxReadReq 512 bytes
                DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+
AuxPwr+ TransPend-
                LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1,
Latency L0 <512ns, L1 <64us
                        ClockPM- Surprise- LLActRep- BwNot-
                LnkCtl: ASPM L1 Enabled; RCB 64 bytes Disabled-
Retrain- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train-
SlotClk+ DLActive- BWMgmt- ABWMgmt-
                DevCap2: Completion Timeout: Not Supported, TimeoutDis+
                DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
SpeedDis-, Selectable De-emphasis: -6dB
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB
        Capabilities: [100 v1] Advanced Error Reporting
                UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt-
UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
                UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt-
UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
                UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt-
UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
                CESta:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
                CEMsk:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
                AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
        Capabilities: [140 v1] Virtual Channel
                Caps:   LPEVC=0 RefClk=100ns PATEntryBits=1
                Arb:    Fixed- WRR32- WRR64- WRR128-
                Ctrl:   ArbSelect=Fixed
                Status: InProgress-
                VC0:    Caps:   PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
                        Arb:    Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
                        Ctrl:   Enable+ ID=0 ArbSelect=Fixed TC/VC=01
                        Status: NegoPending- InProgress-
        Capabilities: [160 v1] Device Serial Number 00-15-17-ff-ff-24-14-12
        Capabilities: [170 v1] Power Budgeting <?>
        Kernel driver in use: ath9k
        Kernel modules: ath9k

02:00.0 Ethernet controller: Atheros Communications Inc. AR8152 v2.0
Fast Ethernet (rev c1)
        Subsystem: ASUSTeK Computer Inc. Device 8468
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 41
        Region 0: Memory at fe900000 (64-bit, non-prefetchable) [size=256K]
        Region 2: I/O ports at e000 [size=128]
        Capabilities: [40] Power Management version 3
                Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA
PME(D0+,D1+,D2+,D3hot+,D3cold+)
                Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [48] MSI: Enable+ Count=1/1 Maskable- 64bit+
                Address: 00000000fee0300c  Data: 4191
        Capabilities: [58] Express (v1) Endpoint, MSI 00
                DevCap: MaxPayload 4096 bytes, PhantFunc 0, Latency
L0s unlimited, L1 unlimited
                        ExtTag- AttnBtn+ AttnInd+ PwrInd+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
                        MaxPayload 128 bytes, MaxReadReq 512 bytes
                DevSta: CorrErr+ UncorrErr+ FatalErr- UnsuppReq-
AuxPwr+ TransPend-
                LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1,
Latency L0 unlimited, L1 unlimited
                        ClockPM+ Surprise- LLActRep- BwNot-
                LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled-
Retrain- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train-
SlotClk+ DLActive- BWMgmt- ABWMgmt-
        Capabilities: [6c] Vital Product Data
pcilib: sysfs_read_vpd: read failed: Connection timed out
                Not readable
        Capabilities: [100 v1] Advanced Error Reporting
                UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt+
UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq+ ACSViol-
                UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt-
UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
                UESvrt: DLP- SDES+ TLP- FCP- CmpltTO- CmpltAbrt-
UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
                CESta:  RxErr- BadTLP+ BadDLLP+ Rollover- Timeout- NonFatalErr-
                CEMsk:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
                AERCap: First Error Pointer: 14, GenCap+ CGenEn- ChkCap+ ChkEn-
        Capabilities: [180 v1] Device Serial Number ff-16-57-c8-54-04-a6-ff
        Kernel driver in use: atl1c
        Kernel modules: atl1c

[7.6] cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: ST9320325AS      Rev: 0003
  Type:   Direct-Access                    ANSI  SCSI revision: 05

[7.7] ls /proc/
1     1139  1636  1866  1933  2256  31   663  934        diskstats
kpageflags     slabinfo
10    1152  1637  1871  1934  23    32   7    935        dma
latency_stats  softirqs
1003  1182  1665  1874  1961  2360  33   70   957        dri
loadavg        stat
1006  12    1666  1888  1972  2380  34   71   967        driver
locks          swaps
1008  1238  1697  1895  1976  2381  392  735  972        execdomains
mdstat         sys
1012  1263  1698  1899  1985  2389  405  74   984        fb
meminfo        sysrq-trigger
1016  1266  1699  19    2     24    45   748  998        filesystems
misc           sysvipc
1024  13    17    1905  20    2402  47   759  acpi       fs
modules        timer_list
1082  14    1701  1908  2025  25    48   766  asound     interrupts
mounts         timer_stats
1087  1449  1706  1910  2026  26    5    8    buddyinfo  iomem
mtrr           tty
11    1492  1710  1913  2027  27    50   848  bus        ioports
net            uptime
1100  15    1712  1921  2059  28    587  873  cgroups    irq
pagetypeinfo   version
1105  1510  18    1924  21    29    59   876  cmdline    kallsyms
partitions     vmallocinfo
1111  1583  1818  1926  2158  3     625  877  consoles   kcore
sched_debug    vmstat
1128  16    1822  1928  2182  30    626  9    cpuinfo    key-users
schedstat      zoneinfo
1135  1632  1853  1929  2186  301   653  915  crypto     kmsg         scsi
1136  1633  1864  1930  22    302   654  919  devices    kpagecount   self

[X.] The bug behaves the same most of the times, but there have been
some changes in the behaviour as described in the launchpad link I
reported:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1076103
comment #9

I also followed the instructions on
http://www.kernel.org/doc/Documentation/power/basic-pm-debugging.txt
and performed some tests as follows:

first test:
# echo freezer > /sys/power/pm_test
# s2ram
Machine is unknown.
This machine can be identified by:
    sys_vendor   = "ASUSTeK Computer INC."
    sys_product  = "1215B"
    sys_version  = "x.x"
    bios_version = "0503"
# dmesg | tail -6
[   29.478205] type=1400 audit(1353088976.454:21): apparmor="STATUS"
operation="profile_replace" name="/usr/sbin/cupsd" pid=1005
comm="apparmor_parser"
[   29.782144] init: alsa-restore main process (1092) terminated with status 99
[   30.702350] init: anacron main process (1127) killed by TERM signal
[   80.344248] type=1400 audit(1353089027.350:22): apparmor="DENIED"
operation="capable" parent=1 profile="/usr/sbin/cupsd" pid=1008
comm="cupsd" pid=1008 comm="cupsd" capability=36
capname="block_suspend"
[  141.290233] type=1400 audit(1353089088.337:23): apparmor="DENIED"
operation="capable" parent=1 profile="/usr/sbin/cupsd" pid=1008
comm="cupsd" pid=1008 comm="cupsd" capability=36
capname="block_suspend"
[ 2666.084059] atl1c 0000:02:00.0: vpd r/w failed.  This is likely a
firmware bug on this device.  Contact the card vendor for a firmware
update.

second test:
# s2ram --force
..... ok the system tries the suspend test for 5 seconds, then it
resumes "almost"
successfully, but the screen now has a very strange problem. It is
"shifted" on the
right by about a half screen length, meaning that the right part of
the desktop is
on the left side of the screen, and the missing right part "follows"
on the left side of the screen.
It is really strange, because except for this image screw up, the
systems bahaves normally.
An attempt of doing Ctrl+Alt+F1 and then Ctrl+Alt+F7 causes the
displays to become almost black
and nothing is visible anymore.  Then Ctrl+Alt+Canc successfully
reboots the system cleanly. I report the dmesg output:

# dmesg |tail -8
[  745.790800] PM: Syncing filesystems ... done.
[  745.844128] PM: Preparing system for mem sleep
[  746.125395] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  746.140760] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[  746.156843] suspend debug: Waiting for 5 seconds.
[  751.117347] PM: Finishing wakeup.
[  751.117351] Restarting tasks ... done.
[  751.164134] video LNXVIDEO:00: Restoring backlight state

third test:
# echo "devices" > /sys/power/pm_test
# s2ram --force
... ok, the behaviour is exactly the same as before, with the screen
shift. Here is the
dmesg tail output:

[  362.360531] PM: Syncing filesystems ... done.
[  362.365945] PM: Preparing system for mem sleep
[  362.687149] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  362.701842] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[  362.717877] PM: Entering mem sleep
[  362.718044] Suspending console(s) (use no_console_suspend to debug)
[  362.779533] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  362.822732] sd 0:0:0:0: [sda] Stopping disk
[  363.214241] PM: suspend of devices complete after 448.059 msecs
[  363.214248] PM: suspend devices took 0.496 seconds
[  363.214250] suspend debug: Waiting for 5 seconds.
[  368.176767] ath: phy0: ASPM enabled: 0x42
[  368.191557] snd_hda_intel 0000:00:01.1: irq 40 for MSI/MSI-X
[  368.209082] atl1c 0000:02:00.0: irq 41 for MSI/MSI-X
[  368.667540] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  370.585608] ata1.00: failed to get Identify Device Data, Emask 0x1
[  370.588600] ata1.00: failed to get Identify Device Data, Emask 0x1
[  370.588615] ata1.00: configured for UDMA/133
[  370.589151] sd 0:0:0:0: [sda] Starting disk
[  370.595348] Extended CMOS year: 2000
[  370.642710] PM: resume of devices complete after 2467.028 msecs
[  370.656561] PM: resume devices took 2.484 seconds
[  370.656608] PM: Finishing wakeup.
[  370.656612] Restarting tasks ... done.
[  370.700080] video LNXVIDEO:00: Restoring backlight state


fourth test:
# echo "platform" > /sys/power/pm_test
# s2ram --force
....well! The same result as before, with the screen shift. The dmesg
tail output:
PM: Syncing filesystems ... done.
[  199.518626] PM: Preparing system for mem sleep
[  199.777851] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  199.792595] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[  199.808604] PM: Entering mem sleep
[  199.808768] Suspending console(s) (use no_console_suspend to debug)
[  199.870105] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  199.944959] sd 0:0:0:0: [sda] Stopping disk
[  200.334220] PM: suspend of devices complete after 477.814 msecs
[  200.334227] PM: suspend devices took 0.524 seconds
[  200.334583] PM: late suspend of devices complete after 0.349 msecs
[  200.364553] ehci_hcd 0000:00:13.2: wake-up capability enabled by ACPI
[  200.380161] ohci_hcd 0000:00:13.0: wake-up capability enabled by ACPI
[  200.380228] ehci_hcd 0000:00:12.2: wake-up capability enabled by ACPI
[  200.396153] ohci_hcd 0000:00:12.0: wake-up capability enabled by ACPI
[  200.396318] PM: noirq suspend of devices complete after 61.765 msecs
[  200.396379] ACPI: Preparing to enter system sleep state S3
[  200.396616] [Firmware Bug]: ACPI: BIOS _OSI(Linux) query ignored
[  200.528945] PM: Saving platform NVS memory
[  200.537526] suspend debug: Waiting for 5 seconds.
[  205.499138] ACPI: Waking up from system sleep state S3
[  205.664860] ohci_hcd 0000:00:12.0: wake-up capability disabled by ACPI
[  205.680523] ehci_hcd 0000:00:12.2: wake-up capability disabled by ACPI
[  205.680585] ohci_hcd 0000:00:13.0: wake-up capability disabled by ACPI
[  205.696535] ehci_hcd 0000:00:13.2: wake-up capability disabled by ACPI
[  205.744672] PM: noirq resume of devices complete after 95.805 msecs
[  205.745032] PM: early resume of devices complete after 0.227 msecs
[  205.745386] snd_hda_intel 0000:00:01.1: irq 40 for MSI/MSI-X
[  205.746611] ath: phy0: ASPM enabled: 0x42
[  205.778149] atl1c 0000:02:00.0: irq 41 for MSI/MSI-X
[  206.236196] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  208.160353] ata1.00: failed to get Identify Device Data, Emask 0x1
[  208.194584] ata1.00: failed to get Identify Device Data, Emask 0x1
[  208.194601] ata1.00: configured for UDMA/133
[  208.194842] sd 0:0:0:0: [sda] Starting disk
[  208.250551] PM: resume of devices complete after 2507.194 msecs
[  208.266979] PM: resume devices took 2.524 seconds
[  208.267071] PM: Finishing wakeup.
[  208.267076] Restarting tasks ... done.
[  208.315978] video LNXVIDEO:00: Restoring backlight state

5ft test:
# echo "processors" > /sys/power/pm_test
# s2ram --force
.... Nothing has changed, still resume with screen shift.
dmesg output:

[  191.458939] PM: Syncing filesystems ... done.
[  191.678113] PM: Preparing system for mem sleep
[  192.084380] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  192.100530] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[  192.116564] PM: Entering mem sleep
[  192.116734] Suspending console(s) (use no_console_suspend to debug)
[  192.178125] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  192.233492] sd 0:0:0:0: [sda] Stopping disk
[  192.631346] PM: suspend of devices complete after 466.467 msecs
[  192.631354] PM: suspend devices took 0.512 seconds
[  192.631709] PM: late suspend of devices complete after 0.349 msecs
[  192.661057] ehci_hcd 0000:00:13.2: wake-up capability enabled by ACPI
[  192.676675] ohci_hcd 0000:00:13.0: wake-up capability enabled by ACPI
[  192.676742] ehci_hcd 0000:00:12.2: wake-up capability enabled by ACPI
[  192.692684] ohci_hcd 0000:00:12.0: wake-up capability enabled by ACPI
[  192.692849] PM: noirq suspend of devices complete after 61.109 msecs
[  192.692910] ACPI: Preparing to enter system sleep state S3
[  192.693151] [Firmware Bug]: ACPI: BIOS _OSI(Linux) query ignored
[  192.781942] PM: Saving platform NVS memory
[  192.790461] Disabling non-boot CPUs ...
[  192.791030] Broke affinity for irq 9
[  192.892517] smpboot: CPU 1 is now offline
[  192.893423] suspend debug: Waiting for 5 seconds.
[  197.854290] Enabling non-boot CPUs ...
[  197.854403] smpboot: Booting Node 0 Processor 1 APIC 0x1
[  197.857934] [sched_delayed] sched: RT throttling activated
[  197.865486] LVT offset 0 assigned for vector 0x400
[  197.868398] CPU1 is up
[  197.869345] ACPI: Waking up from system sleep state S3
[  198.018661] ohci_hcd 0000:00:12.0: wake-up capability disabled by ACPI
[  198.034417] ehci_hcd 0000:00:12.2: wake-up capability disabled by ACPI
[  198.034481] ohci_hcd 0000:00:13.0: wake-up capability disabled by ACPI
[  198.050389] ehci_hcd 0000:00:13.2: wake-up capability disabled by ACPI
[  198.098552] PM: noirq resume of devices complete after 95.779 msecs
[  198.098906] PM: early resume of devices complete after 0.222 msecs
[  198.099221] snd_hda_intel 0000:00:01.1: irq 40 for MSI/MSI-X
[  198.100612] ath: phy0: ASPM enabled: 0x42
[  198.132006] atl1c 0000:02:00.0: irq 41 for MSI/MSI-X
[  198.590449] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  200.528251] ata1.00: failed to get Identify Device Data, Emask 0x1
[  200.531536] ata1.00: failed to get Identify Device Data, Emask 0x1
[  200.531551] ata1.00: configured for UDMA/133
[  200.531772] sd 0:0:0:0: [sda] Starting disk
[  200.586148] PM: resume of devices complete after 2486.423 msecs
[  200.599426] PM: resume devices took 2.500 seconds
[  200.599496] PM: Finishing wakeup.
[  200.599499] Restarting tasks ... done.
[  200.624835] type=1400 audit(1353097416.540:17): apparmor="DENIED"
operation="capable" parent=1 profile="/usr/sbin/cupsd" pid=1005
comm="cupsd" pid=1005 comm="cupsd" capability=36
capname="block_suspend"
[  200.641466] video LNXVIDEO:00: Restoring backlight state

sixt test:
# echo "core" > /sys/power/pm_test
# s2ram --force

The same results, resume and screen shift.
The dmesg output:

[  423.568156] PM: Syncing filesystems ... done.
[  423.880769] PM: Preparing system for mem sleep
[  424.192253] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  424.207865] Freezing remaining freezable tasks ... (elapsed 0.01
seconds) done.
[  424.223790] PM: Entering mem sleep
[  424.223964] Suspending console(s) (use no_console_suspend to debug)
[  424.285361] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  424.333574] sd 0:0:0:0: [sda] Stopping disk
[  424.723827] PM: suspend of devices complete after 451.848 msecs
[  424.723834] PM: suspend devices took 0.500 seconds
[  424.724187] PM: late suspend of devices complete after 0.347 msecs
[  424.756179] ehci_hcd 0000:00:13.2: wake-up capability enabled by ACPI
[  424.771736] ohci_hcd 0000:00:13.0: wake-up capability enabled by ACPI
[  424.771803] ehci_hcd 0000:00:12.2: wake-up capability enabled by ACPI
[  424.787732] ohci_hcd 0000:00:12.0: wake-up capability enabled by ACPI
[  424.787999] PM: noirq suspend of devices complete after 63.813 msecs
[  424.788060] ACPI: Preparing to enter system sleep state S3
[  424.872522] PM: Saving platform NVS memory
[  424.881014] Disabling non-boot CPUs ...
[  424.882067] Broke affinity for irq 17
[  424.882078] Broke affinity for irq 18
[  424.983501] smpboot: CPU 1 is now offline
[  424.984516] Extended CMOS year: 2000
[  424.984595] suspend debug: Waiting for 5 seconds.
[  429.945524] Extended CMOS year: 2000
[  429.945606] ------------[ cut here ]------------
[  429.945622] WARNING: at
/home/apw/COD/linux/drivers/base/syscore.c:104
syscore_resume+0x9e/0xe0()
[  429.945625] Hardware name: 1215B
[  429.945633] Interrupts enabled after ledtrig_cpu_syscore_resume+0x0/0x20
[  429.945704] Modules linked in: rfcomm bnep bluetooth parport_pc
ppdev binfmt_misc dm_crypt joydev kvm_amd kvm eeepc_wmi asus_wmi
snd_hda_codec_realtek snd_hda_codec_hdmi sparse_keymap snd_hda_intel
uvcvideo arc4 snd_hda_codec videobuf2_core ath9k snd_hwdep videodev
mac80211 videobuf2_vmalloc snd_seq_midi snd_pcm videobuf2_memops
psmouse sp5100_tco microcode ath9k_common snd_rawmidi serio_raw
i2c_piix4 ath9k_hw snd_seq_midi_event snd_seq k10temp hid_generic
snd_timer snd_seq_device ath snd cfg80211 mac_hid soundcore
snd_page_alloc msr lp parport usbhid hid radeon ttm drm_kms_helper drm
i2c_algo_bit atl1c video wmi
[  429.945710] Pid: 2350, comm: s2ram Not tainted
3.7.0-030700rc5-generic #201211110835
[  429.945711] Call Trace:
[  429.945722]  [<ffffffff810588cf>] warn_slowpath_common+0x7f/0xc0
[  429.945727]  [<ffffffff810589c6>] warn_slowpath_fmt+0x46/0x50
[  429.945733]  [<ffffffff81569d30>] ? ledtrig_cpu_syscore_shutdown+0x20/0x20
[  429.945737]  [<ffffffff8144356e>] syscore_resume+0x9e/0xe0
[  429.945742]  [<ffffffff810a210a>] suspend_enter+0x13a/0x170
[  429.945746]  [<ffffffff810a220b>] suspend_devices_and_enter+0xcb/0x200
[  429.945749]  [<ffffffff810a2411>] enter_state+0xd1/0x100
[  429.945753]  [<ffffffff810a245b>] pm_suspend+0x1b/0x60
[  429.945758]  [<ffffffff810a14b5>] state_store+0x45/0x70
[  429.945765]  [<ffffffff81342d2f>] kobj_attr_store+0xf/0x30
[  429.945771]  [<ffffffff812059ff>] sysfs_write_file+0xef/0x170
[  429.945777]  [<ffffffff81193433>] vfs_write+0xb3/0x180
[  429.945781]  [<ffffffff81193772>] sys_write+0x52/0xa0
[  429.945787]  [<ffffffff816d339d>] system_call_fastpath+0x1a/0x1f
[  429.945790] ---[ end trace 0a022cacb5d2ec92 ]---
[  429.945801] Enabling non-boot CPUs ...
[  429.945921] smpboot: Booting Node 0 Processor 1 APIC 0x1
[  429.957002] LVT offset 0 assigned for vector 0x400
[  429.959808] CPU1 is up
[  429.960906] ACPI: Waking up from system sleep state S3
[  430.112921] ohci_hcd 0000:00:12.0: wake-up capability disabled by ACPI
[  430.128633] ehci_hcd 0000:00:12.2: wake-up capability disabled by ACPI
[  430.128697] ohci_hcd 0000:00:13.0: wake-up capability disabled by ACPI
[  430.144664] ehci_hcd 0000:00:13.2: wake-up capability disabled by ACPI
[  430.192766] PM: noirq resume of devices complete after 95.907 msecs
[  430.193085] PM: early resume of devices complete after 0.223 msecs
[  430.193413] snd_hda_intel 0000:00:01.1: irq 40 for MSI/MSI-X
[  430.194806] ath: phy0: ASPM enabled: 0x42
[  430.226104] atl1c 0000:02:00.0: irq 41 for MSI/MSI-X
[  430.684448] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  432.573969] ata1.00: failed to get Identify Device Data, Emask 0x1
[  432.577131] ata1.00: failed to get Identify Device Data, Emask 0x1
[  432.577146] ata1.00: configured for UDMA/133
[  432.577378] sd 0:0:0:0: [sda] Starting disk
[  432.631101] PM: resume of devices complete after 2438.430 msecs
[  432.644440] PM: resume devices took 2.452 seconds
[  432.644590] PM: Finishing wakeup.
[  432.644595] Restarting tasks ... done.
[  432.689459] video LNXVIDEO:00: Restoring backlight state


7th test:
# echo "none" > /sys/power/pm_test
# s2ram --force

...ok this reproduced the Bug immediately. It was not possible to resume.
I don't know how to recover the dmesg output.


I hope I gave all the necessary informations to track down the bug,
but feel free to contact me for any other request, and thank you in
advance for any possible help.

Vincenzo Costa

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-11-17  4:04 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
	Mark Brown, David Woodhouse, Arnd Bergmann,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20121116103511.GB16084-NuALmloUBlrZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>

Hi Mark,

On Fri, Nov 16, 2012 at 7:35 PM, Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> wrote:
> Given there are several ARM platforms that may have an interest in this, please
> consider posting this to the ARM mailing list:
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XZu6nac5fYnt@public.gmane.org

That's right. New revision on the way.

>> +Similarly, each power sequence declares its steps as sub-nodes of itself. Steps
>> +must be named sequentially, with the first step named step0, the second step1,
>> +etc. Failure to follow this rule will result in a parsing error.
>
> Could we not encode the step number in the unit-address? i.e. step@N rather than
> stepN.

That was the way I did it initially, but it has been pointed out that
doing so would require to have #address-cells and #size-cells in every
power sequence, as well as a "reg" property in every step (see
https://lkml.org/lkml/2012/7/31/454 ). Although I'd prefer to use the
@ notation too (and neither dtc nor the kernel complained when I did
it), I tend to think the current solution is less burdensome than
having these redundant properties.

>> +"gpio" type required properties:
>> +  - gpio: phandle of the GPIO to use.
>> +  - value: value this GPIO should take. Must be 0 or 1.
>
> Is there any reason for id to be a name rather than a phandle? It seems
> inconsistent with the gpio case.

That's another long story. But to make it short, I'd like to make it
possible for power sequences to be referenced and shared between
devices of the same type (as everybody knows, copy/pasting is bad). If
we use phandles in steps, the power sequence becomes tied to the
referred resources and thus cannot be shared with another instance of
the same device. On the other hand, using an identifier that is
resolved at runtime (through e.g. regulator_get(device *, char *)
leverages the existing frameworks and makes things more flexible.

GPIO is currently the exception. It is the only framework for which
you cannot currently resolve a resource from a device and an
identifier. So at the moment we have to use a phandle - but we are
also working with Linus Walleij to provide an alternative GPIO API
that will be more like what we have for regulators/pinctrl/PWM/etc.

Another problem with phandles is that some of the functions that
resolve them are not publicly exported (i.e. AFAIK there is no public
function that returns a regulator from a phandle - the only to obtain
one is through regulator_get)

> I also see from the example below that the gpio property is not just a phandle,
> as it has the gpio-specifier appended. Is there a better way of describing this
> format in the documentation?

This is already clearly be defined in
Documentation/devicetree/bindings/gpio/, isn't it?

Thanks,
Alex.

^ permalink raw reply

* Re: [PATCH v8 3/3] Take maintainership of power sequences
From: Alexandre Courbot @ 2012-11-17  6:41 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Anton Vorontsov, Stephen Warren, Thierry Reding, Mark Zhang,
	Grant Likely, Rob Herring, Mark Brown, David Woodhouse,
	Arnd Bergmann,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Leela Krishna Amudala,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	Linux Kernel Mailing List,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <50A6733F.7020101-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>

On Sat, Nov 17, 2012 at 2:09 AM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
> Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Thanks!

>> +POWER SEQUENCES
>> +M:   Alexandre Courbot <acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>> +S:   Maintained
>
> Given you're presumably working on this on NVIDIA's time, perhaps make
> that "Supported" not "Maintained"?

Absolutely.

Alex.

^ permalink raw reply

* Re: [PATCH v8 1/3] Runtime Interpreted Power Sequences
From: Alexandre Courbot @ 2012-11-17 10:12 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Stephen Warren, Thierry Reding, Mark Zhang, Grant Likely,
	Rob Herring, Mark Brown, David Woodhouse, Arnd Bergmann,
	Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-pm@vger.kernel.org
In-Reply-To: <20121116122540.GA2198@lizard>

On Fri, Nov 16, 2012 at 9:25 PM, Anton Vorontsov <cbouatmailru@gmail.com> wrote:
>> The POWER_SEQ_*_TYPE macros are defined in the C files. It's the
>> simplest way to initialize this table, and the code inside these C
>> files is short and simple enough that I thought I would be forgiven.
>> :)
>
> I think in the header file you could just write
>
> extern ..... power_seq_delay_type;
> #ifndef ...
> #define power_seq_delay_type NULL
> #endif
>
> And then, in the .c file:
>
> static const struct power_seq_res_ops power_seq_ops[POWER_SEQ_NUM_TYPES] = {
>         [POWER_SEQ_DELAY] = power_seq_delay_type,
>         ...
> };
>
> And then you can stop including the .c files directly, and link them
> instead.

I have done something similar, but that avoids exporting resource ops
into the header file. I am still not satisfied with it though - I'd
rather have one init function per resource file that changes the
pointer of the ops table from NULL to its own set of functions. That
way the core could live without knowing anything about the different
resources, and that would be nicer. Unfortunately modules only support
one init function, so this is not doable here.

>> >nit: one variable declaration per line.
>>
>> Fair enough - but is that a convention? checkpatch.pl was happy with these.
>
> It's not a rule, although there is a small passage about it in CodingStyle
> file when it describes commenting style. Though, some folks choose to
> ignore this suggestion quite frequently, especially if variables have no
> comments.
>
> Often, the multiple declarations per line are used to hide ugly functions
> w/ tons of variables, or just to confuse the reader for the fun of it.
>
> There are exceptions, of course. E.g.
>
>         int i, j, k; /* Our iterators. */
>
> Is perfectly fine.
>
> But
>         int i, err;
>
> At least to me seems weird, this stuff is logically disjunct.
>
> Only human can truly differentiate when the stuff "looks better" together
> or apart, so that's why checkpatch doesn't complain. Personally, I use
> this rule of thumb: when in doubt, use just one declaration per line, it
> is always OK. :)

That totally makes sense - thanks for the precision.

Prepping another patchset with audience extended to linux-arm-kernel
as Mark suggested.

Alex.

^ permalink raw reply

* [RFC PATCH 0/7] Support for Multiple sensors per zone
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch series attempts to add support for multiple
sensors per zone. The work is based on the Thermal discussion
happened in plumbers conference 2012, here:
http://www.linuxplumbersconf.org/2012/schedule/
Title: "Enhancing the Thermal Management Infrastructure in Linux"

The intention is to make it easy for generic sensor drivers
to register with the framework, and let them participate in
platform thermal management. Another goal is to expose the
binding information in a consistent way so that user space
can consume the information and potentially manage platform thermals.

This series contains 7 patches:
Patch 1/7: Creates new sensor level APIs
Patch 2/7: Creates new zone level APIs. The existing tzd structure is
	   kept as such for clarity and compatibility purposes.
Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
	   existing tcd structure need not be modified.
Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
	   points for all sensors present in a zone.
Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
	   of the binding relationship between a sensor and a cdev,
	   within a zone.
Patch 6/7: Creates Documentation for the new APIs. A new file is
	   created for clarity. Final goal is to merge with the existing
	   file or refactor the files, as whatever seems appropriate.
Patch 7/7: A dummy driver that can be used for testing. This is not for merge.

Next steps:
 1. Move all the existing drivers to the new implementation model.
    Help welcomed from individual driver authors/maintainers for this.
 2. Make the thermal governors work with this new model.
 3. Remove old/unused code from thermal_sys.c.
 4. Add more detailed documentation

 I didn't want to submit patches for all these in one-go, since it
 might end-up being difficult to comprehend, besides delaying the
 review process. The other obvious reason being I cannot test all
 the changes on various drivers for 1.

 All these patches have been tested on a Core-i5 desktop running
 ubuntu 12.04 and an atom notebook running ubuntu 11.10.
 Kindly help review.

Durgadoss R (7):
  Thermal: Create sensor level APIs
  Thermal: Create zone level APIs
  Thermal: Add APIs to bind cdev to new zone structure
  Thermal: Add Thermal_trip sysfs node
  Thermal: Add 'thermal_map' sysfs node
  Thermal: Add Documentation to new APIs
  Thermal: Dummy driver used for testing

 Documentation/thermal/sysfs-api2.txt |  213 ++++++++
 drivers/thermal/Kconfig              |    5 +
 drivers/thermal/Makefile             |    3 +
 drivers/thermal/thermal_sys.c        |  915 ++++++++++++++++++++++++++++++++++
 drivers/thermal/thermal_test.c       |  321 ++++++++++++
 include/linux/thermal.h              |  118 +++++
 6 files changed, 1575 insertions(+)
 create mode 100644 Documentation/thermal/sysfs-api2.txt
 create mode 100644 drivers/thermal/thermal_test.c

-- 
1.7.9.5


^ permalink raw reply

* [RFC PATCH 1/7] Thermal: Create sensor level APIs
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R
In-Reply-To: <1353149158-19102-1-git-send-email-durgadoss.r@intel.com>

This patch creates sensor level APIs, in the
generic thermal framework. With this, thermal
sensor drivers can register/unregister themselves
with the thermal framework, and thus can participate
in platform thermal management.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  212 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |   27 ++++++
 2 files changed, 239 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 8f0f37b..e726c8b 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -45,13 +45,16 @@ MODULE_LICENSE("GPL");
 
 static DEFINE_IDR(thermal_tz_idr);
 static DEFINE_IDR(thermal_cdev_idr);
+static DEFINE_IDR(thermal_sensor_idr);
 static DEFINE_MUTEX(thermal_idr_lock);
 
 static LIST_HEAD(thermal_tz_list);
+static LIST_HEAD(thermal_sensor_list);
 static LIST_HEAD(thermal_cdev_list);
 static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
+static DEFINE_MUTEX(ts_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
 static struct thermal_governor *__find_governor(const char *name)
@@ -421,6 +424,66 @@ static void thermal_zone_device_check(struct work_struct *work)
 #define to_thermal_zone(_dev) \
 	container_of(_dev, struct thermal_zone_device, device)
 
+#define to_thermal_sensor(_dev) \
+	container_of(_dev, struct thermal_sensor, device)
+
+static ssize_t
+sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	return sprintf(buf, "%s\n", ts->name);
+}
+
+static ssize_t
+sensor_temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	ret = ts->ops->get_temp(ts, &val);
+
+	return ret ? ret : sprintf(buf, "%ld\n", val);
+}
+
+static ssize_t
+threshold_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int indx, ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	if (!sscanf(attr->attr.name, "threshold%d", &indx))
+		return -EINVAL;
+
+	ret = ts->ops->get_threshold(ts, indx, &val);
+
+	return ret ? ret : sprintf(buf, "%ld\n", val);
+}
+
+static ssize_t
+threshold_store(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int indx, ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	if (!ts->ops->set_threshold)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "threshold%d", &indx))
+		return -EINVAL;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	ret = ts->ops->set_threshold(ts, indx, val);
+
+	return ret ? ret : count;
+}
+
 static ssize_t
 type_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -705,6 +768,10 @@ static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
 static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
 static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 
+/* Thermal sensor attributes */
+static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
+static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
+
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -1491,6 +1558,151 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 }
 
 /**
+ * thermal_sensor_register - register a new thermal sensor
+ * @name:	name of the thermal sensor
+ * @ops:	standard thermal sensor callbacks
+ * @devdata:	private device data
+ */
+struct thermal_sensor *thermal_sensor_register(const char *name,
+			struct thermal_sensor_ops *ops, void *devdata)
+{
+	struct thermal_sensor *ts;
+	int ret;
+
+	if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
+		return ERR_PTR(-EINVAL);
+
+	if (!ops || !ops->get_temp)
+		return ERR_PTR(-EINVAL);
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return ERR_PTR(-ENOMEM);
+
+	idr_init(&ts->idr);
+	ret = get_idr(&thermal_sensor_idr, &thermal_idr_lock, &ts->id);
+	if (ret)
+		goto exit_free;
+
+	strcpy(ts->name, name);
+	ts->ops = ops;
+	ts->devdata = devdata;
+	ts->device.class = &thermal_class;
+
+	dev_set_name(&ts->device, "sensor%d", ts->id);
+	ret = device_register(&ts->device);
+	if (ret)
+		goto exit_idr;
+
+	ret = device_create_file(&ts->device, &dev_attr_sensor_name);
+	if (ret)
+		goto exit_unregister;
+
+	ret = device_create_file(&ts->device, &dev_attr_temp_input);
+	if (ret)
+		goto exit_name;
+
+	/* Add this sensor to the global list of sensors */
+	mutex_lock(&ts_list_lock);
+	list_add_tail(&ts->node, &thermal_sensor_list);
+	mutex_unlock(&ts_list_lock);
+
+	return ts;
+
+exit_name:
+	device_remove_file(&ts->device, &dev_attr_sensor_name);
+exit_unregister:
+	device_unregister(&ts->device);
+exit_idr:
+	release_idr(&thermal_sensor_idr, &thermal_idr_lock, ts->id);
+exit_free:
+	kfree(ts);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(thermal_sensor_register);
+
+void thermal_sensor_unregister(struct thermal_sensor *ts)
+{
+	int i;
+	struct thermal_sensor *pos, *next;
+	bool found = false;
+
+	if (!ts)
+		return;
+
+	mutex_lock(&ts_list_lock);
+	list_for_each_entry_safe(pos, next, &thermal_sensor_list, node) {
+		if (pos == ts) {
+			list_del(&ts->node);
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+
+	if (!found)
+		return;
+
+	for (i = 0; i < ts->thresholds; i++)
+		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
+
+	device_remove_file(&ts->device, &dev_attr_sensor_name);
+	device_remove_file(&ts->device, &dev_attr_temp_input);
+
+	release_idr(&thermal_sensor_idr, &thermal_idr_lock, ts->id);
+	idr_destroy(&ts->idr);
+
+	device_unregister(&ts->device);
+
+	kfree(ts);
+	return;
+}
+EXPORT_SYMBOL(thermal_sensor_unregister);
+
+int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
+{
+	int i, ret;
+	int size = sizeof(struct thermal_attr) * count;
+
+	if (count == 0)
+		return 0; /* Not an error */
+
+	if (unlikely(!ts) || !ts->ops->get_threshold)
+		return -EINVAL;
+
+	ts->thresh_attrs = kzalloc(size, GFP_KERNEL);
+	if (!ts->thresh_attrs)
+		return -ENOMEM;
+
+	ts->thresholds = count;
+
+	/* Create threshold attributes */
+	for (i = 0; i < count; i++) {
+		snprintf(ts->thresh_attrs[i].name, THERMAL_NAME_LENGTH,
+						 "threshold%d", i);
+
+		sysfs_attr_init(&ts->thresh_attrs[i].attr.attr);
+		ts->thresh_attrs[i].attr.attr.name =
+						ts->thresh_attrs[i].name;
+		ts->thresh_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
+		ts->thresh_attrs[i].attr.show = threshold_show;
+		ts->thresh_attrs[i].attr.store = threshold_store;
+
+		ret = device_create_file(&ts->device,
+					&ts->thresh_attrs[i].attr);
+		if (ret)
+			goto exit_fail;
+	}
+	return 0;
+
+exit_fail:
+	while (--i >= 0)
+		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
+	return ret;
+}
+EXPORT_SYMBOL(enable_sensor_thresholds);
+
+/**
  * thermal_zone_device_register - register a new thermal zone device
  * @type:	the thermal zone device type
  * @trips:	the number of trip points the thermal zone support
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 807f214..e2f85ec 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -49,6 +49,7 @@
 /* Default Thermal Governor: Does Linear Throttling */
 #define DEFAULT_THERMAL_GOVERNOR	"step_wise"
 
+struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
 
@@ -127,6 +128,13 @@ struct thermal_cooling_device_ops {
 	int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
 };
 
+struct thermal_sensor_ops {
+	int (*get_temp) (struct thermal_sensor *, long *);
+	int (*get_trend) (struct thermal_sensor *, int, enum thermal_trend *);
+	int (*set_threshold) (struct thermal_sensor *, int, long);
+	int (*get_threshold) (struct thermal_sensor *, int, long *);
+};
+
 struct thermal_cooling_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -144,6 +152,20 @@ struct thermal_attr {
 	char name[THERMAL_NAME_LENGTH];
 };
 
+struct thermal_sensor {
+	char name[THERMAL_NAME_LENGTH];
+	int id;
+	int temp;
+	int prev_temp;
+	int thresholds;
+	void *devdata;
+	struct idr idr;
+	struct device device;
+	struct list_head node;
+	struct thermal_sensor_ops *ops;
+	struct thermal_attr *thresh_attrs;
+};
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -237,6 +259,11 @@ void notify_thermal_framework(struct thermal_zone_device *, int);
 int thermal_register_governor(struct thermal_governor *);
 void thermal_unregister_governor(struct thermal_governor *);
 
+struct thermal_sensor *thermal_sensor_register(const char *,
+				struct thermal_sensor_ops *, void *);
+void thermal_sensor_unregister(struct thermal_sensor *);
+int enable_sensor_thresholds(struct thermal_sensor *, int);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH 2/7] Thermal: Create zone level APIs
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R
In-Reply-To: <1353149158-19102-1-git-send-email-durgadoss.r@intel.com>

This patch adds a new thermal_zone structure to
thermal.h. Also, adds zone level APIs to the thermal
framework.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  206 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |   25 +++++
 2 files changed, 231 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index e726c8b..9d386d7 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
 static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_zone_idr);
 static DEFINE_IDR(thermal_cdev_idr);
 static DEFINE_IDR(thermal_sensor_idr);
 static DEFINE_MUTEX(thermal_idr_lock);
 
 static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_sensor_list);
+static LIST_HEAD(thermal_zone_list);
 static LIST_HEAD(thermal_cdev_list);
 static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(ts_list_lock);
+static DEFINE_MUTEX(tz_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+#define for_each_thermal_sensor(pos) \
+	list_for_each_entry(pos, &thermal_sensor_list, node)
+
+#define for_each_thermal_zone(pos) \
+	list_for_each_entry(pos, &thermal_zone_list, node)
+
 static struct thermal_governor *__find_governor(const char *name)
 {
 	struct thermal_governor *pos;
@@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct work_struct *work)
 	thermal_zone_device_update(tz);
 }
 
+static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+	int i, indx = -EINVAL;
+
+	if (!tz || !ts)
+		return -EINVAL;
+
+	mutex_lock(&ts_list_lock);
+	for (i = 0; i < tz->sensor_indx; i++) {
+		if (tz->sensors[i] == ts) {
+			indx = i;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+	return indx;
+}
+
+static void remove_sensor_from_zone(struct thermal_zone *tz,
+				struct thermal_sensor *ts)
+{
+	int indx, j;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return;
+
+	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
+
+	/* Shift the entries in the tz->sensors array */
+	for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
+		tz->sensors[j] = tz->sensors[j + 1];
+
+	tz->sensor_indx--;
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
 	container_of(_dev, struct thermal_zone_device, device)
 
+#define to_zone(_dev) \
+	container_of(_dev, struct thermal_zone, device)
+
 #define to_thermal_sensor(_dev) \
 	container_of(_dev, struct thermal_sensor, device)
 
 static ssize_t
+zone_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone *tz = to_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->name);
+}
+
+static ssize_t
 sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_sensor *ts = to_thermal_sensor(dev);
@@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
 static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
 
+static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
+
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 	kfree(tz->trip_hyst_attrs);
 }
 
+struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
+{
+	struct thermal_zone *tz;
+	int ret;
+
+	if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
+		return ERR_PTR(-EINVAL);
+
+	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
+	if (!tz)
+		return ERR_PTR(-ENOMEM);
+
+	idr_init(&tz->idr);
+	ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
+	if (ret)
+		goto exit_free;
+
+	strcpy(tz->name, name);
+	tz->devdata = devdata;
+	tz->device.class = &thermal_class;
+
+	dev_set_name(&tz->device, "zone%d", tz->id);
+	ret = device_register(&tz->device);
+	if (ret)
+		goto exit_idr;
+
+	ret = device_create_file(&tz->device, &dev_attr_zone_name);
+	if (ret)
+		goto exit_unregister;
+
+	/* Add this zone to the global list of thermal zones */
+	mutex_lock(&tz_list_lock);
+	list_add_tail(&tz->node, &thermal_zone_list);
+	mutex_unlock(&tz_list_lock);
+	return tz;
+
+exit_unregister:
+	device_unregister(&tz->device);
+exit_idr:
+	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+exit_free:
+	kfree(tz);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(create_thermal_zone);
+
+void remove_thermal_zone(struct thermal_zone *tz)
+{
+	struct thermal_zone *pos, *next;
+	bool found = false;
+
+	if (!tz)
+		return;
+
+	mutex_lock(&tz_list_lock);
+
+	list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
+		if (pos == tz) {
+			list_del(&tz->node);
+			found = true;
+			break;
+		}
+	}
+
+	if (!found)
+		goto exit;
+
+	device_remove_file(&tz->device, &dev_attr_zone_name);
+
+	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+	idr_destroy(&tz->idr);
+
+	device_unregister(&tz->device);
+	kfree(tz);
+exit:
+	mutex_unlock(&tz_list_lock);
+	return;
+}
+EXPORT_SYMBOL(remove_thermal_zone);
+
+struct thermal_sensor *get_sensor_by_name(const char *name)
+{
+	struct thermal_sensor *pos;
+	struct thermal_sensor *ts = NULL;
+
+	mutex_lock(&ts_list_lock);
+	for_each_thermal_sensor(pos) {
+		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
+			ts = pos;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+	return ts;
+}
+EXPORT_SYMBOL(get_sensor_by_name);
+
+int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char *name)
+{
+	int ret;
+	struct thermal_sensor *ts = get_sensor_by_name(name);
+
+	if (!tz || !ts)
+		return -EINVAL;
+
+	mutex_lock(&tz_list_lock);
+
+	/* Ensure we are not adding the same sensor again!! */
+	ret = get_sensor_indx(tz, ts);
+	if (ret >= 0) {
+		ret = -EEXIST;
+		goto exit_zone;
+	}
+
+	mutex_lock(&ts_list_lock);
+
+	ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
+				kobject_name(&ts->device.kobj));
+	if (ret)
+		goto exit_sensor;
+
+	tz->sensors[tz->sensor_indx++] = ts;
+
+exit_sensor:
+	mutex_unlock(&ts_list_lock);
+exit_zone:
+	mutex_unlock(&tz_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_sensor_to_zone_by_name);
+
+int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+	if (!tz || !ts)
+		return -EINVAL;
+
+	return add_sensor_to_zone_by_name(tz, ts->name);
+}
+EXPORT_SYMBOL(add_sensor_to_zone);
+
 /**
  * thermal_sensor_register - register a new thermal sensor
  * @name:	name of the thermal sensor
@@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
 void thermal_sensor_unregister(struct thermal_sensor *ts)
 {
 	int i;
+	struct thermal_zone *tz;
 	struct thermal_sensor *pos, *next;
 	bool found = false;
 
@@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
 	if (!found)
 		return;
 
+	mutex_lock(&tz_list_lock);
+
+	for_each_thermal_zone(tz)
+		remove_sensor_from_zone(tz, ts);
+
+	mutex_unlock(&tz_list_lock);
+
 	for (i = 0; i < ts->thresholds; i++)
 		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e2f85ec..38438be 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -49,6 +49,11 @@
 /* Default Thermal Governor: Does Linear Throttling */
 #define DEFAULT_THERMAL_GOVERNOR	"step_wise"
 
+/* Maximum number of sensors, allowed in a thermal zone
+ * We will start with 5, and increase if needed.
+ */
+#define MAX_SENSORS_PER_ZONE		5
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -191,6 +196,21 @@ struct thermal_zone_device {
 	struct delayed_work poll_queue;
 };
 
+struct thermal_zone {
+	char name[THERMAL_NAME_LENGTH];
+	int id;
+	void *devdata;
+	struct thermal_zone *ops;
+	struct thermal_governor *governor;
+	struct idr idr;
+	struct device device;
+	struct list_head node;
+
+	/* Sensor level information */
+	int sensor_indx; /* index into 'sensors' array */
+	struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
+};
+
 /* Structure that holds thermal governor information */
 struct thermal_governor {
 	char name[THERMAL_NAME_LENGTH];
@@ -264,6 +284,11 @@ struct thermal_sensor *thermal_sensor_register(const char *,
 void thermal_sensor_unregister(struct thermal_sensor *);
 int enable_sensor_thresholds(struct thermal_sensor *, int);
 
+struct thermal_zone *create_thermal_zone(const char *, void *);
+void remove_thermal_zone(struct thermal_zone *);
+int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
+int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox