aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2011-09-06 08:39:21 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2011-09-21 12:45:34 -0400
commit300bab9770e2bd10262bcc78e7249fdce2c74b38 (patch)
tree5c23d7dce82b96fa177ea7c854de7f4b36992c80
parentc536abfdf5227987b8a72ff955b64e62fd58fe91 (diff)
hwspinlock/core: register a bank of hwspinlocks in a single API call
Hardware Spinlock devices usually contain numerous locks (known devices today support between 32 to 256 locks). Originally hwspinlock core required drivers to register (and later, when needed, unregister) each lock separately. That worked, but required hwspinlocks drivers to do a bit extra work when they were probed/removed. This patch changes hwspin_lock_{un}register() to allow a bank of hwspinlocks to be {un}registered in a single invocation. A new 'struct hwspinlock_device', which contains an array of 'struct hwspinlock's is now being passed to the core upon registration (so instead of wrapping each struct hwspinlock, a priv member has been added to allow drivers to piggyback their private data with each hwspinlock). While at it, several per-lock members were moved to be per-device: 1. struct device *dev 2. struct hwspinlock_ops *ops In addition, now that the array of locks is handled by the core, there's no reason to maintain a per-lock 'int id' member: the id of the lock anyway equals to its index in the bank's array plus the bank's base_id. Remove this per-lock id member too, and instead use a simple pointers arithmetic to derive it. As a result of this change, hwspinlocks drivers are now simpler and smaller (about %20 code reduction) and the memory footprint of the hwspinlock framework is reduced. Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
-rw-r--r--Documentation/hwspinlock.txt58
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c165
-rw-r--r--drivers/hwspinlock/hwspinlock_internal.h38
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c86
-rw-r--r--include/linux/hwspinlock.h8
5 files changed, 211 insertions, 144 deletions
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
index 9171f9120143..a903ee5e9776 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -227,42 +227,62 @@ int hwspinlock_example2(void)
227 227
2284. API for implementors 2284. API for implementors
229 229
230 int hwspin_lock_register(struct hwspinlock *hwlock); 230 int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
231 const struct hwspinlock_ops *ops, int base_id, int num_locks);
231 - to be called from the underlying platform-specific implementation, in 232 - to be called from the underlying platform-specific implementation, in
232 order to register a new hwspinlock instance. Should be called from 233 order to register a new hwspinlock device (which is usually a bank of
233 a process context (this function might sleep). 234 numerous locks). Should be called from a process context (this function
235 might sleep).
234 Returns 0 on success, or appropriate error code on failure. 236 Returns 0 on success, or appropriate error code on failure.
235 237
236 struct hwspinlock *hwspin_lock_unregister(unsigned int id); 238 int hwspin_lock_unregister(struct hwspinlock_device *bank);
237 - to be called from the underlying vendor-specific implementation, in order 239 - to be called from the underlying vendor-specific implementation, in order
238 to unregister an existing (and unused) hwspinlock instance. 240 to unregister an hwspinlock device (which is usually a bank of numerous
241 locks).
239 Should be called from a process context (this function might sleep). 242 Should be called from a process context (this function might sleep).
240 Returns the address of hwspinlock on success, or NULL on error (e.g. 243 Returns the address of hwspinlock on success, or NULL on error (e.g.
241 if the hwspinlock is sill in use). 244 if the hwspinlock is sill in use).
242 245
2435. struct hwspinlock 2465. Important structs
244 247
245This struct represents an hwspinlock instance. It is registered by the 248struct hwspinlock_device is a device which usually contains a bank
246underlying hwspinlock implementation using the hwspin_lock_register() API. 249of hardware locks. It is registered by the underlying hwspinlock
250implementation using the hwspin_lock_register() API.
247 251
248/** 252/**
249 * struct hwspinlock - vendor-specific hwspinlock implementation 253 * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
250 * 254 * @dev: underlying device, will be used to invoke runtime PM api
251 * @dev: underlying device, will be used with runtime PM api 255 * @ops: platform-specific hwspinlock handlers
252 * @ops: vendor-specific hwspinlock handlers 256 * @base_id: id index of the first lock in this device
253 * @id: a global, unique, system-wide, index of the lock. 257 * @num_locks: number of locks in this device
254 * @lock: initialized and used by hwspinlock core 258 * @lock: dynamically allocated array of 'struct hwspinlock'
255 */ 259 */
256struct hwspinlock { 260struct hwspinlock_device {
257 struct device *dev; 261 struct device *dev;
258 const struct hwspinlock_ops *ops; 262 const struct hwspinlock_ops *ops;
259 int id; 263 int base_id;
264 int num_locks;
265 struct hwspinlock lock[0];
266};
267
268struct hwspinlock_device contains an array of hwspinlock structs, each
269of which represents a single hardware lock:
270
271/**
272 * struct hwspinlock - this struct represents a single hwspinlock instance
273 * @bank: the hwspinlock_device structure which owns this lock
274 * @lock: initialized and used by hwspinlock core
275 * @priv: private data, owned by the underlying platform-specific hwspinlock drv
276 */
277struct hwspinlock {
278 struct hwspinlock_device *bank;
260 spinlock_t lock; 279 spinlock_t lock;
280 void *priv;
261}; 281};
262 282
263The underlying implementation is responsible to assign the dev, ops and id 283When registering a bank of locks, the hwspinlock driver only needs to
264members. The lock member, OTOH, is initialized and used by the hwspinlock 284set the priv members of the locks. The rest of the members are set and
265core. 285initialized by the hwspinlock core itself.
266 286
2676. Implementation callbacks 2876. Implementation callbacks
268 288
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 0d20b82df0a7..61c9cf15fa52 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -117,7 +117,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
117 return -EBUSY; 117 return -EBUSY;
118 118
119 /* try to take the hwspinlock device */ 119 /* try to take the hwspinlock device */
120 ret = hwlock->ops->trylock(hwlock); 120 ret = hwlock->bank->ops->trylock(hwlock);
121 121
122 /* if hwlock is already taken, undo spin_trylock_* and exit */ 122 /* if hwlock is already taken, undo spin_trylock_* and exit */
123 if (!ret) { 123 if (!ret) {
@@ -199,8 +199,8 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
199 * Allow platform-specific relax handlers to prevent 199 * Allow platform-specific relax handlers to prevent
200 * hogging the interconnect (no sleeping, though) 200 * hogging the interconnect (no sleeping, though)
201 */ 201 */
202 if (hwlock->ops->relax) 202 if (hwlock->bank->ops->relax)
203 hwlock->ops->relax(hwlock); 203 hwlock->bank->ops->relax(hwlock);
204 } 204 }
205 205
206 return ret; 206 return ret;
@@ -245,7 +245,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
245 */ 245 */
246 mb(); 246 mb();
247 247
248 hwlock->ops->unlock(hwlock); 248 hwlock->bank->ops->unlock(hwlock);
249 249
250 /* Undo the spin_trylock{_irq, _irqsave} called while locking */ 250 /* Undo the spin_trylock{_irq, _irqsave} called while locking */
251 if (mode == HWLOCK_IRQSTATE) 251 if (mode == HWLOCK_IRQSTATE)
@@ -257,63 +257,32 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
257} 257}
258EXPORT_SYMBOL_GPL(__hwspin_unlock); 258EXPORT_SYMBOL_GPL(__hwspin_unlock);
259 259
260/** 260static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
261 * hwspin_lock_register() - register a new hw spinlock
262 * @hwlock: hwspinlock to register.
263 *
264 * This function should be called from the underlying platform-specific
265 * implementation, to register a new hwspinlock instance.
266 *
267 * Should be called from a process context (might sleep)
268 *
269 * Returns 0 on success, or an appropriate error code on failure
270 */
271int hwspin_lock_register(struct hwspinlock *hwlock)
272{ 261{
273 struct hwspinlock *tmp; 262 struct hwspinlock *tmp;
274 int ret; 263 int ret;
275 264
276 if (!hwlock || !hwlock->ops ||
277 !hwlock->ops->trylock || !hwlock->ops->unlock) {
278 pr_err("invalid parameters\n");
279 return -EINVAL;
280 }
281
282 spin_lock_init(&hwlock->lock);
283
284 mutex_lock(&hwspinlock_tree_lock); 265 mutex_lock(&hwspinlock_tree_lock);
285 266
286 ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock); 267 ret = radix_tree_insert(&hwspinlock_tree, id, hwlock);
287 if (ret == -EEXIST) 268 if (ret) {
288 pr_err("hwspinlock id %d already exists!\n", hwlock->id); 269 if (ret == -EEXIST)
289 if (ret) 270 pr_err("hwspinlock id %d already exists!\n", id);
290 goto out; 271 goto out;
272 }
291 273
292 /* mark this hwspinlock as available */ 274 /* mark this hwspinlock as available */
293 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id, 275 tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
294 HWSPINLOCK_UNUSED);
295 276
296 /* self-sanity check which should never fail */ 277 /* self-sanity check which should never fail */
297 WARN_ON(tmp != hwlock); 278 WARN_ON(tmp != hwlock);
298 279
299out: 280out:
300 mutex_unlock(&hwspinlock_tree_lock); 281 mutex_unlock(&hwspinlock_tree_lock);
301 return ret; 282 return 0;
302} 283}
303EXPORT_SYMBOL_GPL(hwspin_lock_register);
304 284
305/** 285static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
306 * hwspin_lock_unregister() - unregister an hw spinlock
307 * @id: index of the specific hwspinlock to unregister
308 *
309 * This function should be called from the underlying platform-specific
310 * implementation, to unregister an existing (and unused) hwspinlock.
311 *
312 * Should be called from a process context (might sleep)
313 *
314 * Returns the address of hwspinlock @id on success, or NULL on failure
315 */
316struct hwspinlock *hwspin_lock_unregister(unsigned int id)
317{ 286{
318 struct hwspinlock *hwlock = NULL; 287 struct hwspinlock *hwlock = NULL;
319 int ret; 288 int ret;
@@ -337,6 +306,88 @@ out:
337 mutex_unlock(&hwspinlock_tree_lock); 306 mutex_unlock(&hwspinlock_tree_lock);
338 return hwlock; 307 return hwlock;
339} 308}
309
310/**
311 * hwspin_lock_register() - register a new hw spinlock device
312 * @bank: the hwspinlock device, which usually provides numerous hw locks
313 * @dev: the backing device
314 * @ops: hwspinlock handlers for this device
315 * @base_id: id of the first hardware spinlock in this bank
316 * @num_locks: number of hwspinlocks provided by this device
317 *
318 * This function should be called from the underlying platform-specific
319 * implementation, to register a new hwspinlock device instance.
320 *
321 * Should be called from a process context (might sleep)
322 *
323 * Returns 0 on success, or an appropriate error code on failure
324 */
325int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
326 const struct hwspinlock_ops *ops, int base_id, int num_locks)
327{
328 struct hwspinlock *hwlock;
329 int ret = 0, i;
330
331 if (!bank || !ops || !dev || !num_locks || !ops->trylock ||
332 !ops->unlock) {
333 pr_err("invalid parameters\n");
334 return -EINVAL;
335 }
336
337 bank->dev = dev;
338 bank->ops = ops;
339 bank->base_id = base_id;
340 bank->num_locks = num_locks;
341
342 for (i = 0; i < num_locks; i++) {
343 hwlock = &bank->lock[i];
344
345 spin_lock_init(&hwlock->lock);
346 hwlock->bank = bank;
347
348 ret = hwspin_lock_register_single(hwlock, i);
349 if (ret)
350 goto reg_failed;
351 }
352
353 return 0;
354
355reg_failed:
356 while (--i >= 0)
357 hwspin_lock_unregister_single(i);
358 return ret;
359}
360EXPORT_SYMBOL_GPL(hwspin_lock_register);
361
362/**
363 * hwspin_lock_unregister() - unregister an hw spinlock device
364 * @bank: the hwspinlock device, which usually provides numerous hw locks
365 *
366 * This function should be called from the underlying platform-specific
367 * implementation, to unregister an existing (and unused) hwspinlock.
368 *
369 * Should be called from a process context (might sleep)
370 *
371 * Returns 0 on success, or an appropriate error code on failure
372 */
373int hwspin_lock_unregister(struct hwspinlock_device *bank)
374{
375 struct hwspinlock *hwlock, *tmp;
376 int i;
377
378 for (i = 0; i < bank->num_locks; i++) {
379 hwlock = &bank->lock[i];
380
381 tmp = hwspin_lock_unregister_single(bank->base_id + i);
382 if (!tmp)
383 return -EBUSY;
384
385 /* self-sanity check that should never fail */
386 WARN_ON(tmp != hwlock);
387 }
388
389 return 0;
390}
340EXPORT_SYMBOL_GPL(hwspin_lock_unregister); 391EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
341 392
342/** 393/**
@@ -351,24 +402,25 @@ EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
351 */ 402 */
352static int __hwspin_lock_request(struct hwspinlock *hwlock) 403static int __hwspin_lock_request(struct hwspinlock *hwlock)
353{ 404{
405 struct device *dev = hwlock->bank->dev;
354 struct hwspinlock *tmp; 406 struct hwspinlock *tmp;
355 int ret; 407 int ret;
356 408
357 /* prevent underlying implementation from being removed */ 409 /* prevent underlying implementation from being removed */
358 if (!try_module_get(hwlock->dev->driver->owner)) { 410 if (!try_module_get(dev->driver->owner)) {
359 dev_err(hwlock->dev, "%s: can't get owner\n", __func__); 411 dev_err(dev, "%s: can't get owner\n", __func__);
360 return -EINVAL; 412 return -EINVAL;
361 } 413 }
362 414
363 /* notify PM core that power is now needed */ 415 /* notify PM core that power is now needed */
364 ret = pm_runtime_get_sync(hwlock->dev); 416 ret = pm_runtime_get_sync(dev);
365 if (ret < 0) { 417 if (ret < 0) {
366 dev_err(hwlock->dev, "%s: can't power on device\n", __func__); 418 dev_err(dev, "%s: can't power on device\n", __func__);
367 return ret; 419 return ret;
368 } 420 }
369 421
370 /* mark hwspinlock as used, should not fail */ 422 /* mark hwspinlock as used, should not fail */
371 tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock->id, 423 tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock),
372 HWSPINLOCK_UNUSED); 424 HWSPINLOCK_UNUSED);
373 425
374 /* self-sanity check that should never fail */ 426 /* self-sanity check that should never fail */
@@ -390,7 +442,7 @@ int hwspin_lock_get_id(struct hwspinlock *hwlock)
390 return -EINVAL; 442 return -EINVAL;
391 } 443 }
392 444
393 return hwlock->id; 445 return hwlock_to_id(hwlock);
394} 446}
395EXPORT_SYMBOL_GPL(hwspin_lock_get_id); 447EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
396 448
@@ -465,7 +517,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
465 } 517 }
466 518
467 /* sanity check (this shouldn't happen) */ 519 /* sanity check (this shouldn't happen) */
468 WARN_ON(hwlock->id != id); 520 WARN_ON(hwlock_to_id(hwlock) != id);
469 521
470 /* make sure this hwspinlock is unused */ 522 /* make sure this hwspinlock is unused */
471 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); 523 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
@@ -500,6 +552,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
500 */ 552 */
501int hwspin_lock_free(struct hwspinlock *hwlock) 553int hwspin_lock_free(struct hwspinlock *hwlock)
502{ 554{
555 struct device *dev = hwlock->bank->dev;
503 struct hwspinlock *tmp; 556 struct hwspinlock *tmp;
504 int ret; 557 int ret;
505 558
@@ -511,28 +564,28 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
511 mutex_lock(&hwspinlock_tree_lock); 564 mutex_lock(&hwspinlock_tree_lock);
512 565
513 /* make sure the hwspinlock is used */ 566 /* make sure the hwspinlock is used */
514 ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id, 567 ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
515 HWSPINLOCK_UNUSED); 568 HWSPINLOCK_UNUSED);
516 if (ret == 1) { 569 if (ret == 1) {
517 dev_err(hwlock->dev, "%s: hwlock is already free\n", __func__); 570 dev_err(dev, "%s: hwlock is already free\n", __func__);
518 dump_stack(); 571 dump_stack();
519 ret = -EINVAL; 572 ret = -EINVAL;
520 goto out; 573 goto out;
521 } 574 }
522 575
523 /* notify the underlying device that power is not needed */ 576 /* notify the underlying device that power is not needed */
524 ret = pm_runtime_put(hwlock->dev); 577 ret = pm_runtime_put(dev);
525 if (ret < 0) 578 if (ret < 0)
526 goto out; 579 goto out;
527 580
528 /* mark this hwspinlock as available */ 581 /* mark this hwspinlock as available */
529 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id, 582 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
530 HWSPINLOCK_UNUSED); 583 HWSPINLOCK_UNUSED);
531 584
532 /* sanity check (this shouldn't happen) */ 585 /* sanity check (this shouldn't happen) */
533 WARN_ON(tmp != hwlock); 586 WARN_ON(tmp != hwlock);
534 587
535 module_put(hwlock->dev->driver->owner); 588 module_put(dev->driver->owner);
536 589
537out: 590out:
538 mutex_unlock(&hwspinlock_tree_lock); 591 mutex_unlock(&hwspinlock_tree_lock);
diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h
index fb25830c2ee7..d26f78b8f214 100644
--- a/drivers/hwspinlock/hwspinlock_internal.h
+++ b/drivers/hwspinlock/hwspinlock_internal.h
@@ -21,6 +21,8 @@
21#include <linux/spinlock.h> 21#include <linux/spinlock.h>
22#include <linux/device.h> 22#include <linux/device.h>
23 23
24struct hwspinlock_device;
25
24/** 26/**
25 * struct hwspinlock_ops - platform-specific hwspinlock handlers 27 * struct hwspinlock_ops - platform-specific hwspinlock handlers
26 * 28 *
@@ -39,21 +41,37 @@ struct hwspinlock_ops {
39 41
40/** 42/**
41 * struct hwspinlock - this struct represents a single hwspinlock instance 43 * struct hwspinlock - this struct represents a single hwspinlock instance
42 * 44 * @bank: the hwspinlock_device structure which owns this lock
43 * @dev: underlying device, will be used to invoke runtime PM api
44 * @ops: platform-specific hwspinlock handlers
45 * @id: a global, unique, system-wide, index of the lock.
46 * @lock: initialized and used by hwspinlock core 45 * @lock: initialized and used by hwspinlock core
47 * 46 * @priv: private data, owned by the underlying platform-specific hwspinlock drv
48 * Note: currently simplicity was opted for, but later we can squeeze some
49 * memory bytes by grouping dev, ops in a single
50 * per-platform struct, and have all hwspinlocks point at it.
51 */ 47 */
52struct hwspinlock { 48struct hwspinlock {
49 struct hwspinlock_device *bank;
50 spinlock_t lock;
51 void *priv;
52};
53
54/**
55 * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
56 * @dev: underlying device, will be used to invoke runtime PM api
57 * @ops: platform-specific hwspinlock handlers
58 * @base_id: id index of the first lock in this device
59 * @num_locks: number of locks in this device
60 * @lock: dynamically allocated array of 'struct hwspinlock'
61 */
62struct hwspinlock_device {
53 struct device *dev; 63 struct device *dev;
54 const struct hwspinlock_ops *ops; 64 const struct hwspinlock_ops *ops;
55 int id; 65 int base_id;
56 spinlock_t lock; 66 int num_locks;
67 struct hwspinlock lock[0];
57}; 68};
58 69
70static inline int hwlock_to_id(struct hwspinlock *hwlock)
71{
72 int local_id = hwlock - &hwlock->bank->lock[0];
73
74 return hwlock->bank->base_id + local_id;
75}
76
59#endif /* __HWSPINLOCK_HWSPINLOCK_H */ 77#endif /* __HWSPINLOCK_HWSPINLOCK_H */
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index 2044d181e49d..aec30064a466 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -41,34 +41,20 @@
41#define SPINLOCK_NOTTAKEN (0) /* free */ 41#define SPINLOCK_NOTTAKEN (0) /* free */
42#define SPINLOCK_TAKEN (1) /* locked */ 42#define SPINLOCK_TAKEN (1) /* locked */
43 43
44#define to_omap_hwspinlock(lock) \
45 container_of(lock, struct omap_hwspinlock, lock)
46
47struct omap_hwspinlock {
48 struct hwspinlock lock;
49 void __iomem *addr;
50};
51
52struct omap_hwspinlock_state {
53 int num_locks; /* Total number of locks in system */
54 void __iomem *io_base; /* Mapped base address */
55 struct omap_hwspinlock lock[0]; /* Array of 'num_locks' locks */
56};
57
58static int omap_hwspinlock_trylock(struct hwspinlock *lock) 44static int omap_hwspinlock_trylock(struct hwspinlock *lock)
59{ 45{
60 struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock); 46 void __iomem *lock_addr = lock->priv;
61 47
62 /* attempt to acquire the lock by reading its value */ 48 /* attempt to acquire the lock by reading its value */
63 return (SPINLOCK_NOTTAKEN == readl(omap_lock->addr)); 49 return (SPINLOCK_NOTTAKEN == readl(lock_addr));
64} 50}
65 51
66static void omap_hwspinlock_unlock(struct hwspinlock *lock) 52static void omap_hwspinlock_unlock(struct hwspinlock *lock)
67{ 53{
68 struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock); 54 void __iomem *lock_addr = lock->priv;
69 55
70 /* release the lock by writing 0 to it */ 56 /* release the lock by writing 0 to it */
71 writel(SPINLOCK_NOTTAKEN, omap_lock->addr); 57 writel(SPINLOCK_NOTTAKEN, lock_addr);
72} 58}
73 59
74/* 60/*
@@ -95,11 +81,11 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
95static int __devinit omap_hwspinlock_probe(struct platform_device *pdev) 81static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
96{ 82{
97 struct hwspinlock_pdata *pdata = pdev->dev.platform_data; 83 struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
98 struct omap_hwspinlock *omap_lock; 84 struct hwspinlock_device *bank;
99 struct omap_hwspinlock_state *state; 85 struct hwspinlock *hwlock;
100 struct resource *res; 86 struct resource *res;
101 void __iomem *io_base; 87 void __iomem *io_base;
102 int i, ret; 88 int num_locks, i, ret;
103 89
104 if (!pdata) 90 if (!pdata)
105 return -ENODEV; 91 return -ENODEV;
@@ -122,18 +108,18 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
122 goto iounmap_base; 108 goto iounmap_base;
123 } 109 }
124 110
125 i *= 32; /* actual number of locks in this device */ 111 num_locks = i * 32; /* actual number of locks in this device */
126 112
127 state = kzalloc(sizeof(*state) + i * sizeof(*omap_lock), GFP_KERNEL); 113 bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL);
128 if (!state) { 114 if (!bank) {
129 ret = -ENOMEM; 115 ret = -ENOMEM;
130 goto iounmap_base; 116 goto iounmap_base;
131 } 117 }
132 118
133 state->num_locks = i; 119 platform_set_drvdata(pdev, bank);
134 state->io_base = io_base;
135 120
136 platform_set_drvdata(pdev, state); 121 for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
122 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
137 123
138 /* 124 /*
139 * runtime PM will make sure the clock of this module is 125 * runtime PM will make sure the clock of this module is
@@ -141,26 +127,16 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
141 */ 127 */
142 pm_runtime_enable(&pdev->dev); 128 pm_runtime_enable(&pdev->dev);
143 129
144 for (i = 0; i < state->num_locks; i++) { 130 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
145 omap_lock = &state->lock[i]; 131 pdata->base_id, num_locks);
146 132 if (ret)
147 omap_lock->lock.dev = &pdev->dev; 133 goto reg_fail;
148 omap_lock->lock.id = pdata->base_id + i;
149 omap_lock->lock.ops = &omap_hwspinlock_ops;
150 omap_lock->addr = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
151
152 ret = hwspin_lock_register(&omap_lock->lock);
153 if (ret)
154 goto free_locks;
155 }
156 134
157 return 0; 135 return 0;
158 136
159free_locks: 137reg_fail:
160 while (--i >= 0)
161 hwspin_lock_unregister(i);
162 pm_runtime_disable(&pdev->dev); 138 pm_runtime_disable(&pdev->dev);
163 kfree(state); 139 kfree(bank);
164iounmap_base: 140iounmap_base:
165 iounmap(io_base); 141 iounmap(io_base);
166 return ret; 142 return ret;
@@ -168,23 +144,19 @@ iounmap_base:
168 144
169static int omap_hwspinlock_remove(struct platform_device *pdev) 145static int omap_hwspinlock_remove(struct platform_device *pdev)
170{ 146{
171 struct omap_hwspinlock_state *state = platform_get_drvdata(pdev); 147 struct hwspinlock_device *bank = platform_get_drvdata(pdev);
172 struct hwspinlock *lock; 148 void __iomem *io_base = bank->lock[0].priv - LOCK_BASE_OFFSET;
173 int i; 149 int ret;
174 150
175 for (i = 0; i < state->num_locks; i++) { 151 ret = hwspin_lock_unregister(bank);
176 lock = hwspin_lock_unregister(i); 152 if (ret) {
177 /* this shouldn't happen at this point. if it does, at least 153 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
178 * don't continue with the remove */ 154 return ret;
179 if (!lock) {
180 dev_err(&pdev->dev, "%s: failed on %d\n", __func__, i);
181 return -EBUSY;
182 }
183 } 155 }
184 156
185 pm_runtime_disable(&pdev->dev); 157 pm_runtime_disable(&pdev->dev);
186 iounmap(state->io_base); 158 iounmap(io_base);
187 kfree(state); 159 kfree(bank);
188 160
189 return 0; 161 return 0;
190} 162}
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index c246522a9551..08a2fee40659 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -20,12 +20,15 @@
20 20
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/sched.h> 22#include <linux/sched.h>
23#include <linux/device.h>
23 24
24/* hwspinlock mode argument */ 25/* hwspinlock mode argument */
25#define HWLOCK_IRQSTATE 0x01 /* Disable interrupts, save state */ 26#define HWLOCK_IRQSTATE 0x01 /* Disable interrupts, save state */
26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ 27#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
27 28
28struct hwspinlock; 29struct hwspinlock;
30struct hwspinlock_device;
31struct hwspinlock_ops;
29 32
30/** 33/**
31 * struct hwspinlock_pdata - platform data for hwspinlock drivers 34 * struct hwspinlock_pdata - platform data for hwspinlock drivers
@@ -57,8 +60,9 @@ struct hwspinlock_pdata {
57 60
58#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE) 61#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE)
59 62
60int hwspin_lock_register(struct hwspinlock *lock); 63int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
61struct hwspinlock *hwspin_lock_unregister(unsigned int id); 64 const struct hwspinlock_ops *ops, int base_id, int num_locks);
65int hwspin_lock_unregister(struct hwspinlock_device *bank);
62struct hwspinlock *hwspin_lock_request(void); 66struct hwspinlock *hwspin_lock_request(void);
63struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 67struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
64int hwspin_lock_free(struct hwspinlock *hwlock); 68int hwspin_lock_free(struct hwspinlock *hwlock);