I've been deliberately avoiding issues of simultaneous access, interference, and locking as being secondary to the main problem of figuring out how power management should work. But the issues are interrelated, so here are some general thoughts.
Let's take it as given that drivers need a guarantee that their probe(), release(), suspend(), and resume() routines will be mutually exclusive -- that is, no more than one of them will be called for any particular device at a time. Some drivers may have additional routines they would like to add to that list, particularly if they do some of their work in a separate kernel thread. (Routines that add or remove a child are a good example.) One way to guarantee this is to use a per-driver semaphore. It would do even more; it would prevent a driver from suspending one device while resuming another. I suspect that's more mutual exclusion than we want. Furthermore, this approach has a re-entrancy problem. It's not uncommon on non-hot-pluggable buses for child discovery and registration to take place during probe(). If a device's child (or grandchild, etc.) used the same driver as the device itself, we would have deadlock. The other natural possibilities are per-device semaphores or per-subsystem semaphores like the driver model uses now. Per-subsystem locking also involves re-entrancy problems (this causes difficulty for the USB hub driver, for example, which needs somehow to disconnect all the children when it is unbound from a hub). Moving on, drivers sometimes need a guarantee that children will not be added or removed beneath a particular node. David has suggested that a spinlock be used to protect the device-tree topology. Consider, however, that when we want to suspend a device, during the entire time that the device's children and then the device itself are suspended we need to guarantee that no new children will be added below the device. A spinlock can't accomplish this; some type of semaphore is needed. (You could use a spinlock in addition to a semaphore, like usbcore uses to protect device states, which sometimes need to change without waiting for a semaphore to be released.) The topology lock might be an rwsem instead of a regular semaphore. Either way, there are three natural choices for its scope: a single kernel-wide semaphore, a per-subsystem semaphore, and a per-device semaphore. The first choice is obviously not scalable, although on desktop-sized systems it would be acceptable. Using per-subsystem semaphores runs into problems when you carry out operations that affect multiple subsystems, like a system-wide suspend. At best it's more difficult, and at worst you would end up trying to acquire (or trying to acquire write access to) the same subsystem's semaphore multiple times. So now I've discussed the need for two classes of semaphores: to serialize access to drivers and to protect the tree topology. Many operations naturally will involve both classes. For example, registering a new child device (topology lock) involves probing for drivers (serialize lock). And unbinding a driver (serialize lock) may require unregistering some children (topology lock). This looks like a nice invitation to deadlock unless the two classes of semaphores are in fact one and the same. Putting it all together, this analysis indicates the best approach is for each struct device to include a semaphore (or possibly an rwsem) for general locking. The lock must be held when binding or unbinding a driver, suspending or resuming the device, registering or unregistering any children, and (presumably, although I didn't mentioned it above) registering or unregistering the device itself. It may be convenient to add some more restrictions; for example, it would make sense to require the device to be locked while resuming a child -- thereby preventing the possibility that the resume task could interfere with another task trying to suspend the device. And individual drivers might want to use the lock for other purposes too (such as device resets). Not by coincidence, the scheme I've arrived at is essentially the one used in usbcore. Basically, I'm suggesting that it be formalized and made to apply to the entire device-tree and power-hierarchy. I don't think _too_ many changes would be needed. There would have to be variants of device_add() and device_del() that require the caller to own the device lock. Probably a number of bus drivers would need some updating, and who knows how many little alterations would have to sprinkled throughout the kernel. Alan Stern ------------------------------------------------------- This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170 Project Admins to receive an Apple iPod Mini FREE for your judgement on who ports your project to Linux PPC the best. Sponsored by IBM. Deadline: Sept. 24. Go here: http://sf.net/ppc_contest.php _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
