<div class="gmail_quote">On Wed, May 4, 2011 at 6:35 AM,  <span dir="ltr">&lt;<a href="mailto:jean.pihet@newoldbits.com">jean.pihet@newoldbits.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
...<br>
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c<br>
index 9bbda9a..1d075cb 100644<br>
--- a/arch/arm/plat-omap/omap_device.c<br>
+++ b/arch/arm/plat-omap/omap_device.c<br>
@@ -292,10 +292,196 @@ static void _add_optional_clock_clkdev(struct omap_device *od,<br>
        }<br>
 }<br>
<br>
+/* Spinlock that protects the constraints lists */<br>
+static spinlock_t _constraints_lock;<br>
+<br>
+/*<br>
+ * _store_constraint: add/update/remove a constraint from a plist. There is<br>
+ *  one plist per omap_device.<br>
+ *<br>
+ * @constraints_list: plist to use<br>
+ * @req_dev: constraint requester, used to track the requests<br>
+ * @dev: device constraint target, used to track the requests<br>
+ * @value: constraint value. The plist is sorted by the value. -1 remove the<br>
+ *  constraint from the list<br>
+ * @ascending: return the lowest constraint value if set to 1, return the<br>
+ *  highest value if not.<br>
+ *<br>
+ * Tracks the constraints by req_dev and dev.<br>
+ * Returns the strongest constraint value for the given device, 0 in the<br>
+ * case there is no constraint or a negative value in case of error.<br>
+ *<br>
+ * The caller must check the validity of the parameters.<br>
+ */<br>
+static long _store_constraint(struct plist_head *constraints_list,<br>
+                             struct device *req_dev, struct device *dev,<br>
+                             long value, int ascending)<br>
+{<br>
+       struct omap_device_constraints_entry *user = NULL, *tmp_user;<br>
+       int ret = 0;<br>
+       unsigned long flags;<br>
+<br>
+       /* Check if there already is a constraint for dev and req_dev */<br>
+       spin_lock_irqsave(&amp;_constraints_lock, flags);<br>
+       plist_for_each_entry(tmp_user, constraints_list, node) {<br>
+               if ((tmp_user-&gt;req_dev == req_dev) &amp;&amp; (tmp_user-&gt;dev == dev)) {<br>
+                       user = tmp_user;<br>
+                       break;<br>
+               }<br>
+       }<br>
+       spin_unlock_irqrestore(&amp;_constraints_lock, flags);<br>
+<br>
+       if (value &gt;= 0) {<br>
+               /* Nothing to update, job done */<br>
+               if (user &amp;&amp; (user-&gt;node.prio == value))<br>
+                       goto exit_ok;<br>
+<br>
+               /* Add new entry to the list or update existing request */<br>
+               if (!user) {<br>
+                       user = kzalloc(<br>
+                               sizeof(struct omap_device_constraints_entry),<br>
+                               GFP_KERNEL);<br>
+                       if (!user) {<br>
+                               pr_err(&quot;%s: FATAL ERROR: kzalloc failed\n&quot;,<br>
+                                      __func__);<br>
+                               ret = -ENOMEM;<br>
+                               goto exit_error;<br>
+                       }<br>
+                       user-&gt;req_dev = req_dev;<br>
+                       user-&gt;dev = dev;<br>
+               } else {<br>
+                       spin_lock_irqsave(&amp;_constraints_lock, flags);<br>
+                       plist_del(&amp;user-&gt;node, constraints_list);<br></blockquote><div><br></div><div>spinlock was dropped, no ref counting, not safe to assume user is still valid.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

+                       spin_unlock_irqrestore(&amp;_constraints_lock, flags);<br>
+               }<br>
+<br>
+               spin_lock_irqsave(&amp;_constraints_lock, flags);<br>
+               plist_node_init(&amp;user-&gt;node, value);<br></blockquote><div><br></div><div>and user may be invalid here</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

+               plist_add(&amp;user-&gt;node, constraints_list);<br>
+               spin_unlock_irqrestore(&amp;_constraints_lock, flags);<br>
+       } else {<br>
+               /* Remove the constraint from the list */<br>
+               if (!user) {<br>
+                       pr_err(&quot;%s: Error: no prior constraint to release\n&quot;,<br>
+                              __func__);<br>
+                       ret = -EINVAL;<br>
+                       goto exit_error;<br>
+               }<br>
+<br>
+               spin_lock_irqsave(&amp;_constraints_lock, flags);<br>
+               plist_del(&amp;user-&gt;node, constraints_list);<br></blockquote><div><br></div><div>and here</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

+               spin_unlock_irqrestore(&amp;_constraints_lock, flags);<br>
+               kfree(user);<br>
+       }<br>
+<br>
+exit_ok:<br>
+       /* Find the strongest constraint for the given device */<br>
+       if (!plist_head_empty(constraints_list)) {<br>
+               spin_lock_irqsave(&amp;_constraints_lock, flags);<br></blockquote><div><br></div><div>Deref of plist_first/last() should happen after a plist_head_empty() check with the spinlock held.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

+               if (ascending) {<br>
+                       /* Find the lowest (i.e. first) value */<br>
+                       ret = plist_first(constraints_list)-&gt;prio;<br>
+               } else {<br>
+                       /* Find the highest (i.e. last) value */<br>
+                       ret = plist_last(constraints_list)-&gt;prio;<br>
+               }<br>
+               spin_unlock_irqrestore(&amp;_constraints_lock, flags);<br>
+       }<br>
+<br>
+exit_error:<br>
+       return ret;<br>
+}<br>
...<br></blockquote><div><br></div><div>Todd</div><div><br></div></div>