PM / Clocks: Do not acquire a mutex under a spinlock

Commit b7ab83e (PM: Use spinlock instead of mutex in clock
management functions) introduced a regression causing clocks_mutex
to be acquired under a spinlock. This happens because
pm_clk_suspend() and pm_clk_resume() call pm_clk_acquire() under
pcd->lock, but pm_clk_acquire() executes clk_get() which causes
clocks_mutex to be acquired. Similarly, __pm_clk_remove(),
executed under pcd->lock, calls clk_put(), which also causes
clocks_mutex to be acquired.

To fix those problems make pm_clk_add() call pm_clk_acquire(), so
that pm_clk_suspend() and pm_clk_resume() don't have to do that.
Change pm_clk_remove() and pm_clk_destroy() to separate
modifications of the pcd->clock_list list from the actual removal of
PM clock entry objects done by __pm_clk_remove().

Reported-and-tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>

Changed files
+38 -37
drivers
base
power
+38 -37
drivers/base/power/clock_ops.c
··· 42 42 } 43 43 44 44 /** 45 + * pm_clk_acquire - Acquire a device clock. 46 + * @dev: Device whose clock is to be acquired. 47 + * @ce: PM clock entry corresponding to the clock. 48 + */ 49 + static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) 50 + { 51 + ce->clk = clk_get(dev, ce->con_id); 52 + if (IS_ERR(ce->clk)) { 53 + ce->status = PCE_STATUS_ERROR; 54 + } else { 55 + ce->status = PCE_STATUS_ACQUIRED; 56 + dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); 57 + } 58 + } 59 + 60 + /** 45 61 * pm_clk_add - Start using a device clock for power management. 46 62 * @dev: Device whose clock is going to be used for power management. 47 63 * @con_id: Connection ID of the clock. ··· 89 73 } 90 74 } 91 75 76 + pm_clk_acquire(dev, ce); 77 + 92 78 spin_lock_irq(&pcd->lock); 93 79 list_add_tail(&ce->node, &pcd->clock_list); 94 80 spin_unlock_irq(&pcd->lock); ··· 100 82 /** 101 83 * __pm_clk_remove - Destroy PM clock entry. 102 84 * @ce: PM clock entry to destroy. 103 - * 104 - * This routine must be called under the spinlock protecting the PM list of 105 - * clocks corresponding the the @ce's device. 106 85 */ 107 86 static void __pm_clk_remove(struct pm_clock_entry *ce) 108 87 { 109 88 if (!ce) 110 89 return; 111 - 112 - list_del(&ce->node); 113 90 114 91 if (ce->status < PCE_STATUS_ERROR) { 115 92 if (ce->status == PCE_STATUS_ENABLED) ··· 139 126 spin_lock_irq(&pcd->lock); 140 127 141 128 list_for_each_entry(ce, &pcd->clock_list, node) { 142 - if (!con_id && !ce->con_id) { 143 - __pm_clk_remove(ce); 144 - break; 145 - } else if (!con_id || !ce->con_id) { 129 + if (!con_id && !ce->con_id) 130 + goto remove; 131 + else if (!con_id || !ce->con_id) 146 132 continue; 147 - } else if (!strcmp(con_id, ce->con_id)) { 148 - __pm_clk_remove(ce); 149 - break; 150 - } 133 + else if (!strcmp(con_id, ce->con_id)) 134 + goto remove; 151 135 } 152 136 153 137 spin_unlock_irq(&pcd->lock); 138 + return; 139 + 140 + remove: 141 + list_del(&ce->node); 142 + spin_unlock_irq(&pcd->lock); 143 + 144 + __pm_clk_remove(ce); 154 145 } 155 146 156 147 /** ··· 192 175 { 193 176 struct pm_clk_data *pcd = __to_pcd(dev); 194 177 struct pm_clock_entry *ce, *c; 178 + struct list_head list; 195 179 196 180 if (!pcd) 197 181 return; 198 182 199 183 dev->power.subsys_data = NULL; 184 + INIT_LIST_HEAD(&list); 200 185 201 186 spin_lock_irq(&pcd->lock); 202 187 203 188 list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) 204 - __pm_clk_remove(ce); 189 + list_move(&ce->node, &list); 205 190 206 191 spin_unlock_irq(&pcd->lock); 207 192 208 193 kfree(pcd); 194 + 195 + list_for_each_entry_safe_reverse(ce, c, &list, node) { 196 + list_del(&ce->node); 197 + __pm_clk_remove(ce); 198 + } 209 199 } 210 200 211 201 #endif /* CONFIG_PM */ 212 202 213 203 #ifdef CONFIG_PM_RUNTIME 214 - 215 - /** 216 - * pm_clk_acquire - Acquire a device clock. 217 - * @dev: Device whose clock is to be acquired. 218 - * @con_id: Connection ID of the clock. 219 - */ 220 - static void pm_clk_acquire(struct device *dev, 221 - struct pm_clock_entry *ce) 222 - { 223 - ce->clk = clk_get(dev, ce->con_id); 224 - if (IS_ERR(ce->clk)) { 225 - ce->status = PCE_STATUS_ERROR; 226 - } else { 227 - ce->status = PCE_STATUS_ACQUIRED; 228 - dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); 229 - } 230 - } 231 204 232 205 /** 233 206 * pm_clk_suspend - Disable clocks in a device's PM clock list. ··· 237 230 spin_lock_irqsave(&pcd->lock, flags); 238 231 239 232 list_for_each_entry_reverse(ce, &pcd->clock_list, node) { 240 - if (ce->status == PCE_STATUS_NONE) 241 - pm_clk_acquire(dev, ce); 242 - 243 233 if (ce->status < PCE_STATUS_ERROR) { 244 234 clk_disable(ce->clk); 245 235 ce->status = PCE_STATUS_ACQUIRED; ··· 266 262 spin_lock_irqsave(&pcd->lock, flags); 267 263 268 264 list_for_each_entry(ce, &pcd->clock_list, node) { 269 - if (ce->status == PCE_STATUS_NONE) 270 - pm_clk_acquire(dev, ce); 271 - 272 265 if (ce->status < PCE_STATUS_ERROR) { 273 266 clk_enable(ce->clk); 274 267 ce->status = PCE_STATUS_ENABLED;