Skip to contentSkip to conversation

power trees

RFC In review Adam Belay 7 participants 8 messages Aug 11, 2005 – Aug 31, 2005

Subsystems (4)
lore
Share & tools
lore

Adam Belay

author
#0 lore raw

RFC 1/1 power trees

Hi All,

I've been experimenting with a power object tree for handling power state dependencies. Many major bus specifications fit well in a power-state based model. They include PCI/Cardbus, ACPI, IDE, and probably even USB. More complex dependencies generally rely on out of tree elements (e.g. power planes, clocks, processor states, etc.) or are isolated to a specific parent and its child. Therefore, I think a power tree would be useful for a wide range of device drivers. Nonetheless, the power tree is provided as an optional library only.

My implementation has two primary goals:

1.) To help device drivers track and control their device's power state

2.) To bubble power state dependency changes from a leaf node to the last affected parent node in the chain.

The basic unit of the tree is referred to as a "pm_node". Each "pm_node" has a list of states it supports, a current state, and a driver to handle state transitions. Any "pm_node" can have children and therefore act as a power container.

struct pm_state {
	char			*name;
	unsigned long		index;
	unsigned long		link_req;
	void			*link_data;
};

"index" is a driver specific value that indicates the state. "link_req" is a set of flags that indicate requirements from the parent "pm_node". "link_data" provides additional requirement information.

struct pm_node {
	struct semaphore	sem;
	struct list_head	children;
	struct list_head	child_list;
	struct pm_node		*parent;
	struct pm_node		*tmp_path;
	struct device		*dev;

	struct pm_node_driver	*drv;
	unsigned int		current_state;
	unsigned int		target_state;

	unsigned int		num_states;
	struct pm_state		*states;
};

"states" is a list of power states sorted from most functional to least functional. "current_state" and "target_state" are index values for that list.

struct pm_node_driver {
	int (*set_state) 	(struct pm_node *node);
	int (*raise_event)	(struct pm_node *domain,
				 struct pm_node *child,
				 unsigned long *new_state);
	void (*lower_event)	(struct pm_node *domain);
};

"raise_event" notifies the power domain when a child has increased its state. "new_state" allows for a domain to pass an index of the new state it would need in response to the new requirements. "lower_event" is called when power is decreased. It is expected to return immediately and defer any power transitions for later (generally with a timeout value).

I apologize for the unpolished/untested state of the code as it's primarily intended to illustrate a concept. I'll need to look over the problem more carefully if we decide this is the right direction. Power dependency notifications are entirely iterative in this implementation. Locking is always from leaf nodes down. The "iterative" requirement seems to be a little inflexible with notifications, so we may want to start with a recursive algorithm if this proves to be too difficult. Are there any known cases of deep power trees? I look forward to any comments or suggestions.

Thanks,
Adam

drivers/base/power/Makefile +1 -1
@@ -1,5 +1,5 @@
 obj-y			:= shutdown.o
-obj-$(CONFIG_PM)	+= main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM)	+= main.o node.o suspend.o resume.o runtime.o sysfs.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
drivers/base/power/node.c +185 -0

185 lines not on this page · raw message

include/linux/pm.h +53 -0

65 lines not on this page · raw message

#1 lore raw
Quoted 8 lines · Adam Belay
struct pm_node {
	struct semaphore	sem;
	struct list_head	children;
	struct list_head	child_list;
	struct pm_node		*parent;
	struct pm_node		*tmp_path;
	struct device		*dev;
Quoted 7 lines
	struct pm_node_driver	*drv;
	unsigned int		current_state;
	unsigned int		target_state;

	unsigned int		num_states;
	struct pm_state		*states;
};

Shouldn't this structure contain a kobject? Or do you not want to represent the power node tree in sysfs?

thanks,

greg k-h

#2 lore raw
In reply to Adam Belay

Hi!

Quoted 23 lines

My implementation has two primary goals:

1.) To help device drivers track and control their device's power state

2.) To bubble power state dependency changes from a leaf node to the last affected parent node in the chain.

The basic unit of the tree is referred to as a "pm_node". Each "pm_node" has a list of states it supports, a current state, and a driver to handle state transitions. Any "pm_node" can have children and therefore act as a power container.

struct pm_state {
	char			*name;
	unsigned long		index;
	unsigned long		link_req;
	void			*link_data;
};

"index" is a driver specific value that indicates the state. "link_req" is a set of flags that indicate requirements from the parent "pm_node". "link_data" provides additional requirement information.

Quoted 11 lines
struct pm_node {
	struct semaphore	sem;
	struct list_head	children;
	struct list_head	child_list;
	struct pm_node		*parent;
	struct pm_node		*tmp_path;
	struct device		*dev;

	struct pm_node_driver	*drv;
	unsigned int		current_state;
	unsigned int		target_state;

Would not it be cleaner to have struct pm_state *current_state, target state?

Quoted 9 lines

"states" is a list of power states sorted from most functional to least functional. "current_state" and "target_state" are index values for that list.

struct pm_node_driver {
	int (*set_state) 	(struct pm_node *node);
	int (*raise_event)	(struct pm_node *domain,
				 struct pm_node *child,
				 unsigned long *new_state);

struct pm_state here, too?

Quoted 4 lines
	void (*lower_event)	(struct pm_node *domain);
};

"raise_event" notifies the power domain when a child has increased its

"Increase" == went more power hungry?

Quoted 3 lines

I apologize for the unpolished/untested state of the code as it's primarily intended to illustrate a concept. I'll need to look over the problem more carefully if we decide this is the right direction. Power

Seems ok to me.

Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         
#3 lore raw

Sorry it's taken me so long to respond to this.

Quoted 11 lines
Quoted 11 lines

My implementation has two primary goals:

1.) To help device drivers track and control their device's power state

2.) To bubble power state dependency changes from a leaf node to the last affected parent node in the chain.

The basic unit of the tree is referred to as a "pm_node". Each "pm_node" has a list of states it supports, a current state, and a driver to handle state transitions. Any "pm_node" can have children and therefore act as a power container.

I think it's a mistake to make this a tree. The natural structure is a DAG, where nodes can have multiple parents. It might not be worthwhile trying to store the parent/child/sibling pointers in the structures.

Quoted 10 lines
Quoted 10 lines
struct pm_state {
	char			*name;
	unsigned long		index;
	unsigned long		link_req;
	void			*link_data;
};

"index" is a driver specific value that indicates the state. "link_req" is a set of flags that indicate requirements from the parent "pm_node". "link_data" provides additional requirement information.

Given that there can be multiple parents, the link_* members of this structure won't be useful. Also, I don't see that index expresses any information not already present in name.

Quoted 8 lines
Quoted 8 lines
struct pm_node {
	struct semaphore	sem;
	struct list_head	children;
	struct list_head	child_list;
	struct pm_node		*parent;
	struct pm_node		*tmp_path;
	struct device		*dev;
Quoted 5 lines
Quoted 3 lines
	struct pm_node_driver	*drv;
	unsigned int		current_state;
	unsigned int		target_state;

Would not it be cleaner to have struct pm_state *current_state, target state?

I don't see the point of having target_state at all.

Quoted 2 lines
Quoted 2 lines

"states" is a list of power states sorted from most functional to least functional.

In general it's not possible to sort states in that way. Some states might permit one subset of the complete set of functions while other states permit a different, partially overlapping, subset.

Quoted 9 lines
Quoted 8 lines

"current_state" and "target_state" are index values for
that list.

struct pm_node_driver {
	int (*set_state) 	(struct pm_node *node);
	int (*raise_event)	(struct pm_node *domain,
				 struct pm_node *child,
				 unsigned long *new_state);
Quoted 8 lines

struct pm_state here, too?

Quoted 4 lines
	void (*lower_event)	(struct pm_node *domain);
};

"raise_event" notifies the power domain when a child has increased its

"Increase" == went more power hungry?

There's no need to have separate raise_event and lower_event entry points. In fact you might not want to have those entry points at all, since the information they convey will be so bus-specific. It might be better to rely on bus-specific entry points. I'm not sure about this.

Alan Stern

#4 lore raw

Hi!

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines

"states" is a list of power states sorted from most functional to least functional.

In general it's not possible to sort states in that way. Some states might permit one subset of the complete set of functions while other states permit a different, partially overlapping, subset.

How common is that? We should probably treat that as two different devices...

Pavel

Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         
#5 lore raw
Quoted 6 lines · Pavel Machek
Quoted 3 lines

In general it's not possible to sort states in that way. Some states might permit one subset of the complete set of functions while other states permit a different, partially overlapping, subset.

How common is that? We should probably treat that as two different devices...

I don't have any examples. Such things occur more in the embedded world than among regular PCs. Can anyone else provide some information?

Alan Stern

#6 lore raw
In reply to Alan Stern
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

My implementation has two primary goals:

1.) To help device drivers track and control their device's power state

What do you see happening with "struct dev_pm_info", which is the current (and needs-work) approach for this?

Quoted 11 lines
Quoted 7 lines
Quoted 7 lines

2.) To bubble power state dependency changes from a leaf node to the last affected parent node in the chain.

The basic unit of the tree is referred to as a "pm_node". Each "pm_node" has a list of states it supports, a current state, and a driver to handle state transitions. Any "pm_node" can have children and therefore act as a power container.

I think it's a mistake to make this a tree. The natural structure is a DAG, where nodes can have multiple parents. It might not be worthwhile trying to store the parent/child/sibling pointers in the structures.

Plus, the current driver model already builds a power tree, with node type "struct dev_pm_info". What would be the goal of adding another, normally parallel, tree? Rather than just sorting out how to use that one, and dev_pm_info.pm_parent. (Which we need to do anyway!)

My pet problem case can best be called "multiple parents". That's pretty common; one subassembly (part of a board, chip, etc) has PM interactions with a bunch of other components. For discussion, I'll say that uses a "composite driver" ... it's usually built out of a few other drivers. (One real-world example would be a USB OTG subsystem. Typically that combines drivers for an I2C transceiver, USB host, USB peripheral, OTG controller, and parts of a battery charger. They work together.)

The interesting question to me is then how to fit composite drivers into today's driver/PM core code ... such subassemblies will show up in more than one place in the driver model (e.g. four drivers, on platform and I2C busses), plus elsewhere (e.g. the clock tree), and per-device driver model PM calls normally need to access composite driver state ...

Maybe if the dev_pm_info.pm_parent pointed to a

	struct composite_device {
		struct device		container;
		struct list_head	components;
		/* plus private device-wide state */

		/* didn't someone propose a call like this recently?
		 * it'd be the child notifiying the container.
		 * container used component->{suspend,resume}?
		 */
		int (*notify_state_change)(
				struct composite_device *container,
				struct device *component,
				void *data);
	};

on some bus or other, would offer the right kind of structure. Especially if the PM core morphed component->suspend() to pm_parent->suspend(), and likewise for resume(), so individual components wouldn't need their own PM code.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
struct pm_state {
	char			*name;
	unsigned long		index;
	unsigned long		link_req;
	void			*link_data;
};
Quoted 7 lines
Quoted 3 lines
Quoted 3 lines

"index" is a driver specific value that indicates the state. "link_req" is a set of flags that indicate requirements from the parent "pm_node". "link_data" provides additional requirement information.

Given that there can be multiple parents, the link_* members of this structure won't be useful. Also, I don't see that index expresses any information not already present in name.

Better yet, the "struct pm_state" pointer could itself be the state identifier. We don't need to keep creating more of those. :)

Who would use these state cookies though? I think I'd like to see a "roles and responsibilities" description of these API components.

I consider defining PM states to be the responsibility of the device; and in some standardized environments (like PCI or USB), they may also be constrained by the bus. And while a bus may have some role in managing power for its devices, that's not always the case. (Example:
switching power for a platform device may involve some i2c requests. Neither bus -- platform or i2c -- has PM responsibilties there.)

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
struct pm_node {
	struct semaphore	sem;
	struct list_head	children;
	struct list_head	child_list;
	struct pm_node		*parent;
	struct pm_node		*tmp_path;
	struct device		*dev;
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
	struct pm_node_driver	*drv;
	unsigned int		current_state;
	unsigned int		target_state;

Would not it be cleaner to have struct pm_state *current_state, target state?

I don't see the point of having target_state at all.

In fact, I don't see any reason not to pass the "struct pm_state" pointer directly from whatever code has the "chooses device state transitions" role.

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines

"states" is a list of power states sorted from most functional to least functional.

In general it's not possible to sort states in that way. Some states might permit one subset of the complete set of functions while other states permit a different, partially overlapping, subset.

Why would you want to expose one particular ordering of states at the API level? Any code responsible for such states is going to know what the states mean, and how to order them for the task at hand. If it won't work with a randomized ordering, it's broken. :)

With multiple variables (start with two voltages, three frequencies, and four subcomponents to turn on/off) it's easy to see there can be multiple orderings that may be meaningful from a given state ... including states that can't currently be entered.

- Dave

#7 lore raw
Quoted 16 lines · David Brownell
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

My implementation has two primary goals:

1.) To help device drivers track and control their device's power state

What do you see happening with "struct dev_pm_info", which is the current (and needs-work) approach for this?

Quoted 8 lines
Quoted 7 lines
Quoted 7 lines

2.) To bubble power state dependency changes from a leaf node to the last affected parent node in the chain.

The basic unit of the tree is referred to as a "pm_node". Each "pm_node" has a list of states it supports, a current state, and a driver to handle state transitions. Any "pm_node" can have children and therefore act as a power container.

Quoted 8 lines
Quoted 3 lines

I think it's a mistake to make this a tree. The natural structure is a DAG, where nodes can have multiple parents. It might not be worthwhile trying to store the parent/child/sibling pointers in the structures.

Plus, the current driver model already builds a power tree, with node type "struct dev_pm_info". What would be the goal of adding another, normally parallel, tree? Rather than just sorting out how to use that one, and dev_pm_info.pm_parent. (Which we need to do anyway!)

I agree. I think we should do this in the driver model. And considering that a lot of the PM device states are machine specific, we should register the driver specific PM states and limitations as resources.

This allows defining machine specific driver PM states and limitations withouth having to shove them into the driver code. And it should be also easy to add new PM states via sysfs if needed.

Regards,

Tony