aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwspinlock.txt74
-rw-r--r--MAINTAINERS14
-rw-r--r--arch/arm/mach-omap2/hwspinlock.c9
-rw-r--r--drivers/hwspinlock/Kconfig27
-rw-r--r--drivers/hwspinlock/Makefile1
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c204
-rw-r--r--drivers/hwspinlock/hwspinlock_internal.h40
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c127
-rw-r--r--drivers/hwspinlock/u8500_hsem.c198
-rw-r--r--drivers/mmc/host/omap_hsmmc.c2
-rw-r--r--include/linux/hwspinlock.h46
11 files changed, 516 insertions, 226 deletions
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
index 7dcd1a4e726..a903ee5e977 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -39,23 +39,20 @@ independent, drivers.
39 in case an unused hwspinlock isn't available. Users of this 39 in case an unused hwspinlock isn't available. Users of this
40 API will usually want to communicate the lock's id to the remote core 40 API will usually want to communicate the lock's id to the remote core
41 before it can be used to achieve synchronization. 41 before it can be used to achieve synchronization.
42 Can be called from an atomic context (this function will not sleep) but 42 Should be called from a process context (might sleep).
43 not from within interrupt context.
44 43
45 struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 44 struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
46 - assign a specific hwspinlock id and return its address, or NULL 45 - assign a specific hwspinlock id and return its address, or NULL
47 if that hwspinlock is already in use. Usually board code will 46 if that hwspinlock is already in use. Usually board code will
48 be calling this function in order to reserve specific hwspinlock 47 be calling this function in order to reserve specific hwspinlock
49 ids for predefined purposes. 48 ids for predefined purposes.
50 Can be called from an atomic context (this function will not sleep) but 49 Should be called from a process context (might sleep).
51 not from within interrupt context.
52 50
53 int hwspin_lock_free(struct hwspinlock *hwlock); 51 int hwspin_lock_free(struct hwspinlock *hwlock);
54 - free a previously-assigned hwspinlock; returns 0 on success, or an 52 - free a previously-assigned hwspinlock; returns 0 on success, or an
55 appropriate error code on failure (e.g. -EINVAL if the hwspinlock 53 appropriate error code on failure (e.g. -EINVAL if the hwspinlock
56 is already free). 54 is already free).
57 Can be called from an atomic context (this function will not sleep) but 55 Should be called from a process context (might sleep).
58 not from within interrupt context.
59 56
60 int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); 57 int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
61 - lock a previously-assigned hwspinlock with a timeout limit (specified in 58 - lock a previously-assigned hwspinlock with a timeout limit (specified in
@@ -230,45 +227,62 @@ int hwspinlock_example2(void)
230 227
2314. API for implementors 2284. API for implementors
232 229
233 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);
234 - to be called from the underlying platform-specific implementation, in 232 - to be called from the underlying platform-specific implementation, in
235 order to register a new hwspinlock instance. Can be called from an atomic 233 order to register a new hwspinlock device (which is usually a bank of
236 context (this function will not sleep) but not from within interrupt 234 numerous locks). Should be called from a process context (this function
237 context. Returns 0 on success, or appropriate error code on failure. 235 might sleep).
236 Returns 0 on success, or appropriate error code on failure.
238 237
239 struct hwspinlock *hwspin_lock_unregister(unsigned int id); 238 int hwspin_lock_unregister(struct hwspinlock_device *bank);
240 - to be called from the underlying vendor-specific implementation, in order 239 - to be called from the underlying vendor-specific implementation, in order
241 to unregister an existing (and unused) hwspinlock instance. 240 to unregister an hwspinlock device (which is usually a bank of numerous
242 Can be called from an atomic context (will not sleep) but not from 241 locks).
243 within interrupt context. 242 Should be called from a process context (this function might sleep).
244 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.
245 if the hwspinlock is sill in use). 244 if the hwspinlock is sill in use).
246 245
2475. struct hwspinlock 2465. Important structs
248 247
249This struct represents an hwspinlock instance. It is registered by the 248struct hwspinlock_device is a device which usually contains a bank
250underlying 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.
251 251
252/** 252/**
253 * struct hwspinlock - vendor-specific hwspinlock implementation 253 * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
254 * 254 * @dev: underlying device, will be used to invoke runtime PM api
255 * @dev: underlying device, will be used with runtime PM api 255 * @ops: platform-specific hwspinlock handlers
256 * @ops: vendor-specific hwspinlock handlers 256 * @base_id: id index of the first lock in this device
257 * @id: a global, unique, system-wide, index of the lock. 257 * @num_locks: number of locks in this device
258 * @lock: initialized and used by hwspinlock core 258 * @lock: dynamically allocated array of 'struct hwspinlock'
259 * @owner: underlying implementation module, used to maintain module ref count
260 */ 259 */
261struct hwspinlock { 260struct hwspinlock_device {
262 struct device *dev; 261 struct device *dev;
263 const struct hwspinlock_ops *ops; 262 const struct hwspinlock_ops *ops;
264 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;
265 spinlock_t lock; 279 spinlock_t lock;
266 struct module *owner; 280 void *priv;
267}; 281};
268 282
269The underlying implementation is responsible to assign the dev, ops, id and 283When registering a bank of locks, the hwspinlock driver only needs to
270owner members. 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
271core. 285initialized by the hwspinlock core itself.
272 286
2736. Implementation callbacks 2876. Implementation callbacks
274 288
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cb8c51b479..ab776700128 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3018,6 +3018,13 @@ F: Documentation/hw_random.txt
3018F: drivers/char/hw_random/ 3018F: drivers/char/hw_random/
3019F: include/linux/hw_random.h 3019F: include/linux/hw_random.h
3020 3020
3021HARDWARE SPINLOCK CORE
3022M: Ohad Ben-Cohen <ohad@wizery.com>
3023S: Maintained
3024F: Documentation/hwspinlock.txt
3025F: drivers/hwspinlock/hwspinlock_*
3026F: include/linux/hwspinlock.h
3027
3021HARMONY SOUND DRIVER 3028HARMONY SOUND DRIVER
3022M: Kyle McMartin <kyle@mcmartin.ca> 3029M: Kyle McMartin <kyle@mcmartin.ca>
3023L: linux-parisc@vger.kernel.org 3030L: linux-parisc@vger.kernel.org
@@ -4714,6 +4721,13 @@ S: Maintained
4714F: drivers/video/omap2/ 4721F: drivers/video/omap2/
4715F: Documentation/arm/OMAP/DSS 4722F: Documentation/arm/OMAP/DSS
4716 4723
4724OMAP HARDWARE SPINLOCK SUPPORT
4725M: Ohad Ben-Cohen <ohad@wizery.com>
4726L: linux-omap@vger.kernel.org
4727S: Maintained
4728F: drivers/hwspinlock/omap_hwspinlock.c
4729F: arch/arm/mach-omap2/hwspinlock.c
4730
4717OMAP MMC SUPPORT 4731OMAP MMC SUPPORT
4718M: Jarkko Lavinen <jarkko.lavinen@nokia.com> 4732M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
4719L: linux-omap@vger.kernel.org 4733L: linux-omap@vger.kernel.org
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
index 36e21091b06..454dfce125c 100644
--- a/arch/arm/mach-omap2/hwspinlock.c
+++ b/arch/arm/mach-omap2/hwspinlock.c
@@ -19,10 +19,15 @@
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/hwspinlock.h>
22 23
23#include <plat/omap_hwmod.h> 24#include <plat/omap_hwmod.h>
24#include <plat/omap_device.h> 25#include <plat/omap_device.h>
25 26
27static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = {
28 .base_id = 0,
29};
30
26int __init hwspinlocks_init(void) 31int __init hwspinlocks_init(void)
27{ 32{
28 int retval = 0; 33 int retval = 0;
@@ -40,7 +45,9 @@ int __init hwspinlocks_init(void)
40 if (oh == NULL) 45 if (oh == NULL)
41 return -EINVAL; 46 return -EINVAL;
42 47
43 pdev = omap_device_build(dev_name, 0, oh, NULL, 0, NULL, 0, false); 48 pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata,
49 sizeof(struct hwspinlock_pdata),
50 NULL, 0, false);
44 if (IS_ERR(pdev)) { 51 if (IS_ERR(pdev)) {
45 pr_err("Can't build omap_device for %s:%s\n", dev_name, 52 pr_err("Can't build omap_device for %s:%s\n", dev_name,
46 oh_name); 53 oh_name);
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index 1f29bab6b3e..c7c3128393d 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -2,22 +2,31 @@
2# Generic HWSPINLOCK framework 2# Generic HWSPINLOCK framework
3# 3#
4 4
5# HWSPINLOCK always gets selected by whoever wants it.
5config HWSPINLOCK 6config HWSPINLOCK
6 tristate "Generic Hardware Spinlock framework" 7 tristate
7 depends on ARCH_OMAP4
8 help
9 Say y here to support the generic hardware spinlock framework.
10 You only need to enable this if you have hardware spinlock module
11 on your system (usually only relevant if your system has remote slave
12 coprocessors).
13 8
14 If unsure, say N. 9menu "Hardware Spinlock drivers"
15 10
16config HWSPINLOCK_OMAP 11config HWSPINLOCK_OMAP
17 tristate "OMAP Hardware Spinlock device" 12 tristate "OMAP Hardware Spinlock device"
18 depends on HWSPINLOCK && ARCH_OMAP4 13 depends on ARCH_OMAP4
14 select HWSPINLOCK
19 help 15 help
20 Say y here to support the OMAP Hardware Spinlock device (firstly 16 Say y here to support the OMAP Hardware Spinlock device (firstly
21 introduced in OMAP4). 17 introduced in OMAP4).
22 18
23 If unsure, say N. 19 If unsure, say N.
20
21config HSEM_U8500
22 tristate "STE Hardware Semaphore functionality"
23 depends on ARCH_U8500
24 select HWSPINLOCK
25 help
26 Say y here to support the STE Hardware Semaphore functionality, which
27 provides a synchronisation mechanism for the various processor on the
28 SoC.
29
30 If unsure, say N.
31
32endmenu
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
index 5729a3f7ed3..93eb64b6648 100644
--- a/drivers/hwspinlock/Makefile
+++ b/drivers/hwspinlock/Makefile
@@ -4,3 +4,4 @@
4 4
5obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o 5obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
6obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o 6obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
7obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 43a62714b4f..61c9cf15fa5 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -26,6 +26,7 @@
26#include <linux/radix-tree.h> 26#include <linux/radix-tree.h>
27#include <linux/hwspinlock.h> 27#include <linux/hwspinlock.h>
28#include <linux/pm_runtime.h> 28#include <linux/pm_runtime.h>
29#include <linux/mutex.h>
29 30
30#include "hwspinlock_internal.h" 31#include "hwspinlock_internal.h"
31 32
@@ -52,10 +53,12 @@
52static RADIX_TREE(hwspinlock_tree, GFP_KERNEL); 53static RADIX_TREE(hwspinlock_tree, GFP_KERNEL);
53 54
54/* 55/*
55 * Synchronization of access to the tree is achieved using this spinlock, 56 * Synchronization of access to the tree is achieved using this mutex,
56 * as the radix-tree API requires that users provide all synchronisation. 57 * as the radix-tree API requires that users provide all synchronisation.
58 * A mutex is needed because we're using non-atomic radix tree allocations.
57 */ 59 */
58static DEFINE_SPINLOCK(hwspinlock_tree_lock); 60static DEFINE_MUTEX(hwspinlock_tree_lock);
61
59 62
60/** 63/**
61 * __hwspin_trylock() - attempt to lock a specific hwspinlock 64 * __hwspin_trylock() - attempt to lock a specific hwspinlock
@@ -114,7 +117,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
114 return -EBUSY; 117 return -EBUSY;
115 118
116 /* try to take the hwspinlock device */ 119 /* try to take the hwspinlock device */
117 ret = hwlock->ops->trylock(hwlock); 120 ret = hwlock->bank->ops->trylock(hwlock);
118 121
119 /* if hwlock is already taken, undo spin_trylock_* and exit */ 122 /* if hwlock is already taken, undo spin_trylock_* and exit */
120 if (!ret) { 123 if (!ret) {
@@ -196,8 +199,8 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
196 * Allow platform-specific relax handlers to prevent 199 * Allow platform-specific relax handlers to prevent
197 * hogging the interconnect (no sleeping, though) 200 * hogging the interconnect (no sleeping, though)
198 */ 201 */
199 if (hwlock->ops->relax) 202 if (hwlock->bank->ops->relax)
200 hwlock->ops->relax(hwlock); 203 hwlock->bank->ops->relax(hwlock);
201 } 204 }
202 205
203 return ret; 206 return ret;
@@ -242,7 +245,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
242 */ 245 */
243 mb(); 246 mb();
244 247
245 hwlock->ops->unlock(hwlock); 248 hwlock->bank->ops->unlock(hwlock);
246 249
247 /* Undo the spin_trylock{_irq, _irqsave} called while locking */ 250 /* Undo the spin_trylock{_irq, _irqsave} called while locking */
248 if (mode == HWLOCK_IRQSTATE) 251 if (mode == HWLOCK_IRQSTATE)
@@ -254,68 +257,37 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
254} 257}
255EXPORT_SYMBOL_GPL(__hwspin_unlock); 258EXPORT_SYMBOL_GPL(__hwspin_unlock);
256 259
257/** 260static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
258 * hwspin_lock_register() - register a new hw spinlock
259 * @hwlock: hwspinlock to register.
260 *
261 * This function should be called from the underlying platform-specific
262 * implementation, to register a new hwspinlock instance.
263 *
264 * Can be called from an atomic context (will not sleep) but not from
265 * within interrupt context.
266 *
267 * Returns 0 on success, or an appropriate error code on failure
268 */
269int hwspin_lock_register(struct hwspinlock *hwlock)
270{ 261{
271 struct hwspinlock *tmp; 262 struct hwspinlock *tmp;
272 int ret; 263 int ret;
273 264
274 if (!hwlock || !hwlock->ops || 265 mutex_lock(&hwspinlock_tree_lock);
275 !hwlock->ops->trylock || !hwlock->ops->unlock) {
276 pr_err("invalid parameters\n");
277 return -EINVAL;
278 }
279
280 spin_lock_init(&hwlock->lock);
281
282 spin_lock(&hwspinlock_tree_lock);
283 266
284 ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock); 267 ret = radix_tree_insert(&hwspinlock_tree, id, hwlock);
285 if (ret) 268 if (ret) {
269 if (ret == -EEXIST)
270 pr_err("hwspinlock id %d already exists!\n", id);
286 goto out; 271 goto out;
272 }
287 273
288 /* mark this hwspinlock as available */ 274 /* mark this hwspinlock as available */
289 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id, 275 tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
290 HWSPINLOCK_UNUSED);
291 276
292 /* self-sanity check which should never fail */ 277 /* self-sanity check which should never fail */
293 WARN_ON(tmp != hwlock); 278 WARN_ON(tmp != hwlock);
294 279
295out: 280out:
296 spin_unlock(&hwspinlock_tree_lock); 281 mutex_unlock(&hwspinlock_tree_lock);
297 return ret; 282 return 0;
298} 283}
299EXPORT_SYMBOL_GPL(hwspin_lock_register);
300 284
301/** 285static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
302 * hwspin_lock_unregister() - unregister an hw spinlock
303 * @id: index of the specific hwspinlock to unregister
304 *
305 * This function should be called from the underlying platform-specific
306 * implementation, to unregister an existing (and unused) hwspinlock.
307 *
308 * Can be called from an atomic context (will not sleep) but not from
309 * within interrupt context.
310 *
311 * Returns the address of hwspinlock @id on success, or NULL on failure
312 */
313struct hwspinlock *hwspin_lock_unregister(unsigned int id)
314{ 286{
315 struct hwspinlock *hwlock = NULL; 287 struct hwspinlock *hwlock = NULL;
316 int ret; 288 int ret;
317 289
318 spin_lock(&hwspinlock_tree_lock); 290 mutex_lock(&hwspinlock_tree_lock);
319 291
320 /* make sure the hwspinlock is not in use (tag is set) */ 292 /* make sure the hwspinlock is not in use (tag is set) */
321 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); 293 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
@@ -331,9 +303,91 @@ struct hwspinlock *hwspin_lock_unregister(unsigned int id)
331 } 303 }
332 304
333out: 305out:
334 spin_unlock(&hwspinlock_tree_lock); 306 mutex_unlock(&hwspinlock_tree_lock);
335 return hwlock; 307 return hwlock;
336} 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}
337EXPORT_SYMBOL_GPL(hwspin_lock_unregister); 391EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
338 392
339/** 393/**
@@ -348,24 +402,25 @@ EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
348 */ 402 */
349static int __hwspin_lock_request(struct hwspinlock *hwlock) 403static int __hwspin_lock_request(struct hwspinlock *hwlock)
350{ 404{
405 struct device *dev = hwlock->bank->dev;
351 struct hwspinlock *tmp; 406 struct hwspinlock *tmp;
352 int ret; 407 int ret;
353 408
354 /* prevent underlying implementation from being removed */ 409 /* prevent underlying implementation from being removed */
355 if (!try_module_get(hwlock->owner)) { 410 if (!try_module_get(dev->driver->owner)) {
356 dev_err(hwlock->dev, "%s: can't get owner\n", __func__); 411 dev_err(dev, "%s: can't get owner\n", __func__);
357 return -EINVAL; 412 return -EINVAL;
358 } 413 }
359 414
360 /* notify PM core that power is now needed */ 415 /* notify PM core that power is now needed */
361 ret = pm_runtime_get_sync(hwlock->dev); 416 ret = pm_runtime_get_sync(dev);
362 if (ret < 0) { 417 if (ret < 0) {
363 dev_err(hwlock->dev, "%s: can't power on device\n", __func__); 418 dev_err(dev, "%s: can't power on device\n", __func__);
364 return ret; 419 return ret;
365 } 420 }
366 421
367 /* mark hwspinlock as used, should not fail */ 422 /* mark hwspinlock as used, should not fail */
368 tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock->id, 423 tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock),
369 HWSPINLOCK_UNUSED); 424 HWSPINLOCK_UNUSED);
370 425
371 /* self-sanity check that should never fail */ 426 /* self-sanity check that should never fail */
@@ -387,7 +442,7 @@ int hwspin_lock_get_id(struct hwspinlock *hwlock)
387 return -EINVAL; 442 return -EINVAL;
388 } 443 }
389 444
390 return hwlock->id; 445 return hwlock_to_id(hwlock);
391} 446}
392EXPORT_SYMBOL_GPL(hwspin_lock_get_id); 447EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
393 448
@@ -400,9 +455,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
400 * to the remote core before it can be used for synchronization (to get the 455 * to the remote core before it can be used for synchronization (to get the
401 * id of a given hwlock, use hwspin_lock_get_id()). 456 * id of a given hwlock, use hwspin_lock_get_id()).
402 * 457 *
403 * Can be called from an atomic context (will not sleep) but not from 458 * Should be called from a process context (might sleep)
404 * within interrupt context (simply because there is no use case for
405 * that yet).
406 * 459 *
407 * Returns the address of the assigned hwspinlock, or NULL on error 460 * Returns the address of the assigned hwspinlock, or NULL on error
408 */ 461 */
@@ -411,7 +464,7 @@ struct hwspinlock *hwspin_lock_request(void)
411 struct hwspinlock *hwlock; 464 struct hwspinlock *hwlock;
412 int ret; 465 int ret;
413 466
414 spin_lock(&hwspinlock_tree_lock); 467 mutex_lock(&hwspinlock_tree_lock);
415 468
416 /* look for an unused lock */ 469 /* look for an unused lock */
417 ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock, 470 ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock,
@@ -431,7 +484,7 @@ struct hwspinlock *hwspin_lock_request(void)
431 hwlock = NULL; 484 hwlock = NULL;
432 485
433out: 486out:
434 spin_unlock(&hwspinlock_tree_lock); 487 mutex_unlock(&hwspinlock_tree_lock);
435 return hwlock; 488 return hwlock;
436} 489}
437EXPORT_SYMBOL_GPL(hwspin_lock_request); 490EXPORT_SYMBOL_GPL(hwspin_lock_request);
@@ -445,9 +498,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request);
445 * Usually early board code will be calling this function in order to 498 * Usually early board code will be calling this function in order to
446 * reserve specific hwspinlock ids for predefined purposes. 499 * reserve specific hwspinlock ids for predefined purposes.
447 * 500 *
448 * Can be called from an atomic context (will not sleep) but not from 501 * Should be called from a process context (might sleep)
449 * within interrupt context (simply because there is no use case for
450 * that yet).
451 * 502 *
452 * Returns the address of the assigned hwspinlock, or NULL on error 503 * Returns the address of the assigned hwspinlock, or NULL on error
453 */ 504 */
@@ -456,7 +507,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
456 struct hwspinlock *hwlock; 507 struct hwspinlock *hwlock;
457 int ret; 508 int ret;
458 509
459 spin_lock(&hwspinlock_tree_lock); 510 mutex_lock(&hwspinlock_tree_lock);
460 511
461 /* make sure this hwspinlock exists */ 512 /* make sure this hwspinlock exists */
462 hwlock = radix_tree_lookup(&hwspinlock_tree, id); 513 hwlock = radix_tree_lookup(&hwspinlock_tree, id);
@@ -466,7 +517,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
466 } 517 }
467 518
468 /* sanity check (this shouldn't happen) */ 519 /* sanity check (this shouldn't happen) */
469 WARN_ON(hwlock->id != id); 520 WARN_ON(hwlock_to_id(hwlock) != id);
470 521
471 /* make sure this hwspinlock is unused */ 522 /* make sure this hwspinlock is unused */
472 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); 523 ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
@@ -482,7 +533,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
482 hwlock = NULL; 533 hwlock = NULL;
483 534
484out: 535out:
485 spin_unlock(&hwspinlock_tree_lock); 536 mutex_unlock(&hwspinlock_tree_lock);
486 return hwlock; 537 return hwlock;
487} 538}
488EXPORT_SYMBOL_GPL(hwspin_lock_request_specific); 539EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
@@ -495,14 +546,13 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
495 * Should only be called with an @hwlock that was retrieved from 546 * Should only be called with an @hwlock that was retrieved from
496 * an earlier call to omap_hwspin_lock_request{_specific}. 547 * an earlier call to omap_hwspin_lock_request{_specific}.
497 * 548 *
498 * Can be called from an atomic context (will not sleep) but not from 549 * Should be called from a process context (might sleep)
499 * within interrupt context (simply because there is no use case for
500 * that yet).
501 * 550 *
502 * Returns 0 on success, or an appropriate error code on failure 551 * Returns 0 on success, or an appropriate error code on failure
503 */ 552 */
504int hwspin_lock_free(struct hwspinlock *hwlock) 553int hwspin_lock_free(struct hwspinlock *hwlock)
505{ 554{
555 struct device *dev = hwlock->bank->dev;
506 struct hwspinlock *tmp; 556 struct hwspinlock *tmp;
507 int ret; 557 int ret;
508 558
@@ -511,34 +561,34 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
511 return -EINVAL; 561 return -EINVAL;
512 } 562 }
513 563
514 spin_lock(&hwspinlock_tree_lock); 564 mutex_lock(&hwspinlock_tree_lock);
515 565
516 /* make sure the hwspinlock is used */ 566 /* make sure the hwspinlock is used */
517 ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id, 567 ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
518 HWSPINLOCK_UNUSED); 568 HWSPINLOCK_UNUSED);
519 if (ret == 1) { 569 if (ret == 1) {
520 dev_err(hwlock->dev, "%s: hwlock is already free\n", __func__); 570 dev_err(dev, "%s: hwlock is already free\n", __func__);
521 dump_stack(); 571 dump_stack();
522 ret = -EINVAL; 572 ret = -EINVAL;
523 goto out; 573 goto out;
524 } 574 }
525 575
526 /* notify the underlying device that power is not needed */ 576 /* notify the underlying device that power is not needed */
527 ret = pm_runtime_put(hwlock->dev); 577 ret = pm_runtime_put(dev);
528 if (ret < 0) 578 if (ret < 0)
529 goto out; 579 goto out;
530 580
531 /* mark this hwspinlock as available */ 581 /* mark this hwspinlock as available */
532 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id, 582 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
533 HWSPINLOCK_UNUSED); 583 HWSPINLOCK_UNUSED);
534 584
535 /* sanity check (this shouldn't happen) */ 585 /* sanity check (this shouldn't happen) */
536 WARN_ON(tmp != hwlock); 586 WARN_ON(tmp != hwlock);
537 587
538 module_put(hwlock->owner); 588 module_put(dev->driver->owner);
539 589
540out: 590out:
541 spin_unlock(&hwspinlock_tree_lock); 591 mutex_unlock(&hwspinlock_tree_lock);
542 return ret; 592 return ret;
543} 593}
544EXPORT_SYMBOL_GPL(hwspin_lock_free); 594EXPORT_SYMBOL_GPL(hwspin_lock_free);
diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h
index 69935e6b93e..d26f78b8f21 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,23 +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 * @owner: underlying implementation module, used to maintain module ref count 46 * @priv: private data, owned by the underlying platform-specific hwspinlock drv
48 *
49 * Note: currently simplicity was opted for, but later we can squeeze some
50 * memory bytes by grouping the dev, ops and owner members in a single
51 * per-platform struct, and have all hwspinlocks point at it.
52 */ 47 */
53struct 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 {
54 struct device *dev; 63 struct device *dev;
55 const struct hwspinlock_ops *ops; 64 const struct hwspinlock_ops *ops;
56 int id; 65 int base_id;
57 spinlock_t lock; 66 int num_locks;
58 struct module *owner; 67 struct hwspinlock lock[0];
59}; 68};
60 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
61#endif /* __HWSPINLOCK_HWSPINLOCK_H */ 77#endif /* __HWSPINLOCK_HWSPINLOCK_H */
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index a8f02734c02..887d34effb3 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -41,33 +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};
56
57static int omap_hwspinlock_trylock(struct hwspinlock *lock) 44static int omap_hwspinlock_trylock(struct hwspinlock *lock)
58{ 45{
59 struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock); 46 void __iomem *lock_addr = lock->priv;
60 47
61 /* attempt to acquire the lock by reading its value */ 48 /* attempt to acquire the lock by reading its value */
62 return (SPINLOCK_NOTTAKEN == readl(omap_lock->addr)); 49 return (SPINLOCK_NOTTAKEN == readl(lock_addr));
63} 50}
64 51
65static void omap_hwspinlock_unlock(struct hwspinlock *lock) 52static void omap_hwspinlock_unlock(struct hwspinlock *lock)
66{ 53{
67 struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock); 54 void __iomem *lock_addr = lock->priv;
68 55
69 /* release the lock by writing 0 to it */ 56 /* release the lock by writing 0 to it */
70 writel(SPINLOCK_NOTTAKEN, omap_lock->addr); 57 writel(SPINLOCK_NOTTAKEN, lock_addr);
71} 58}
72 59
73/* 60/*
@@ -93,26 +80,23 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
93 80
94static int __devinit omap_hwspinlock_probe(struct platform_device *pdev) 81static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
95{ 82{
96 struct omap_hwspinlock *omap_lock; 83 struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
97 struct omap_hwspinlock_state *state; 84 struct hwspinlock_device *bank;
98 struct hwspinlock *lock; 85 struct hwspinlock *hwlock;
99 struct resource *res; 86 struct resource *res;
100 void __iomem *io_base; 87 void __iomem *io_base;
101 int i, ret; 88 int num_locks, i, ret;
89
90 if (!pdata)
91 return -ENODEV;
102 92
103 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 93 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
104 if (!res) 94 if (!res)
105 return -ENODEV; 95 return -ENODEV;
106 96
107 state = kzalloc(sizeof(*state), GFP_KERNEL);
108 if (!state)
109 return -ENOMEM;
110
111 io_base = ioremap(res->start, resource_size(res)); 97 io_base = ioremap(res->start, resource_size(res));
112 if (!io_base) { 98 if (!io_base)
113 ret = -ENOMEM; 99 return -ENOMEM;
114 goto free_state;
115 }
116 100
117 /* Determine number of locks */ 101 /* Determine number of locks */
118 i = readl(io_base + SYSSTATUS_OFFSET); 102 i = readl(io_base + SYSSTATUS_OFFSET);
@@ -124,10 +108,18 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
124 goto iounmap_base; 108 goto iounmap_base;
125 } 109 }
126 110
127 state->num_locks = i * 32; 111 num_locks = i * 32; /* actual number of locks in this device */
128 state->io_base = io_base; 112
113 bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL);
114 if (!bank) {
115 ret = -ENOMEM;
116 goto iounmap_base;
117 }
118
119 platform_set_drvdata(pdev, bank);
129 120
130 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;
131 123
132 /* 124 /*
133 * runtime PM will make sure the clock of this module is 125 * runtime PM will make sure the clock of this module is
@@ -135,79 +127,46 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
135 */ 127 */
136 pm_runtime_enable(&pdev->dev); 128 pm_runtime_enable(&pdev->dev);
137 129
138 for (i = 0; i < state->num_locks; i++) { 130 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
139 omap_lock = kzalloc(sizeof(*omap_lock), GFP_KERNEL); 131 pdata->base_id, num_locks);
140 if (!omap_lock) { 132 if (ret)
141 ret = -ENOMEM; 133 goto reg_fail;
142 goto free_locks;
143 }
144
145 omap_lock->lock.dev = &pdev->dev;
146 omap_lock->lock.owner = THIS_MODULE;
147 omap_lock->lock.id = i;
148 omap_lock->lock.ops = &omap_hwspinlock_ops;
149 omap_lock->addr = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
150
151 ret = hwspin_lock_register(&omap_lock->lock);
152 if (ret) {
153 kfree(omap_lock);
154 goto free_locks;
155 }
156 }
157 134
158 return 0; 135 return 0;
159 136
160free_locks: 137reg_fail:
161 while (--i >= 0) {
162 lock = hwspin_lock_unregister(i);
163 /* this should't happen, but let's give our best effort */
164 if (!lock) {
165 dev_err(&pdev->dev, "%s: cleanups failed\n", __func__);
166 continue;
167 }
168 omap_lock = to_omap_hwspinlock(lock);
169 kfree(omap_lock);
170 }
171 pm_runtime_disable(&pdev->dev); 138 pm_runtime_disable(&pdev->dev);
139 kfree(bank);
172iounmap_base: 140iounmap_base:
173 iounmap(io_base); 141 iounmap(io_base);
174free_state:
175 kfree(state);
176 return ret; 142 return ret;
177} 143}
178 144
179static int omap_hwspinlock_remove(struct platform_device *pdev) 145static int __devexit omap_hwspinlock_remove(struct platform_device *pdev)
180{ 146{
181 struct omap_hwspinlock_state *state = platform_get_drvdata(pdev); 147 struct hwspinlock_device *bank = platform_get_drvdata(pdev);
182 struct hwspinlock *lock; 148 void __iomem *io_base = bank->lock[0].priv - LOCK_BASE_OFFSET;
183 struct omap_hwspinlock *omap_lock; 149 int ret;
184 int i; 150
185 151 ret = hwspin_lock_unregister(bank);
186 for (i = 0; i < state->num_locks; i++) { 152 if (ret) {
187 lock = hwspin_lock_unregister(i); 153 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
188 /* this shouldn't happen at this point. if it does, at least 154 return ret;
189 * don't continue with the remove */
190 if (!lock) {
191 dev_err(&pdev->dev, "%s: failed on %d\n", __func__, i);
192 return -EBUSY;
193 }
194
195 omap_lock = to_omap_hwspinlock(lock);
196 kfree(omap_lock);
197 } 155 }
198 156
199 pm_runtime_disable(&pdev->dev); 157 pm_runtime_disable(&pdev->dev);
200 iounmap(state->io_base); 158 iounmap(io_base);
201 kfree(state); 159 kfree(bank);
202 160
203 return 0; 161 return 0;
204} 162}
205 163
206static struct platform_driver omap_hwspinlock_driver = { 164static struct platform_driver omap_hwspinlock_driver = {
207 .probe = omap_hwspinlock_probe, 165 .probe = omap_hwspinlock_probe,
208 .remove = omap_hwspinlock_remove, 166 .remove = __devexit_p(omap_hwspinlock_remove),
209 .driver = { 167 .driver = {
210 .name = "omap_hwspinlock", 168 .name = "omap_hwspinlock",
169 .owner = THIS_MODULE,
211 }, 170 },
212}; 171};
213 172
diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c
new file mode 100644
index 00000000000..143461a95ae
--- /dev/null
+++ b/drivers/hwspinlock/u8500_hsem.c
@@ -0,0 +1,198 @@
1/*
2 * u8500 HWSEM driver
3 *
4 * Copyright (C) 2010-2011 ST-Ericsson
5 *
6 * Implements u8500 semaphore handling for protocol 1, no interrupts.
7 *
8 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
9 * Heavily borrowed from the work of :
10 * Simon Que <sque@ti.com>
11 * Hari Kanigeri <h-kanigeri2@ti.com>
12 * Ohad Ben-Cohen <ohad@wizery.com>
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * version 2 as published by the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 */
23
24#include <linux/delay.h>
25#include <linux/io.h>
26#include <linux/pm_runtime.h>
27#include <linux/slab.h>
28#include <linux/spinlock.h>
29#include <linux/hwspinlock.h>
30#include <linux/platform_device.h>
31
32#include "hwspinlock_internal.h"
33
34/*
35 * Implementation of STE's HSem protocol 1 without interrutps.
36 * The only masterID we allow is '0x01' to force people to use
37 * HSems for synchronisation between processors rather than processes
38 * on the ARM core.
39 */
40
41#define U8500_MAX_SEMAPHORE 32 /* a total of 32 semaphore */
42#define RESET_SEMAPHORE (0) /* free */
43
44/*
45 * CPU ID for master running u8500 kernel.
46 * Hswpinlocks should only be used to synchonise operations
47 * between the Cortex A9 core and the other CPUs. Hence
48 * forcing the masterID to a preset value.
49 */
50#define HSEM_MASTER_ID 0x01
51
52#define HSEM_REGISTER_OFFSET 0x08
53
54#define HSEM_CTRL_REG 0x00
55#define HSEM_ICRALL 0x90
56#define HSEM_PROTOCOL_1 0x01
57
58static int u8500_hsem_trylock(struct hwspinlock *lock)
59{
60 void __iomem *lock_addr = lock->priv;
61
62 writel(HSEM_MASTER_ID, lock_addr);
63
64 /* get only first 4 bit and compare to masterID.
65 * if equal, we have the semaphore, otherwise
66 * someone else has it.
67 */
68 return (HSEM_MASTER_ID == (0x0F & readl(lock_addr)));
69}
70
71static void u8500_hsem_unlock(struct hwspinlock *lock)
72{
73 void __iomem *lock_addr = lock->priv;
74
75 /* release the lock by writing 0 to it */
76 writel(RESET_SEMAPHORE, lock_addr);
77}
78
79/*
80 * u8500: what value is recommended here ?
81 */
82static void u8500_hsem_relax(struct hwspinlock *lock)
83{
84 ndelay(50);
85}
86
87static const struct hwspinlock_ops u8500_hwspinlock_ops = {
88 .trylock = u8500_hsem_trylock,
89 .unlock = u8500_hsem_unlock,
90 .relax = u8500_hsem_relax,
91};
92
93static int __devinit u8500_hsem_probe(struct platform_device *pdev)
94{
95 struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
96 struct hwspinlock_device *bank;
97 struct hwspinlock *hwlock;
98 struct resource *res;
99 void __iomem *io_base;
100 int i, ret, num_locks = U8500_MAX_SEMAPHORE;
101 ulong val;
102
103 if (!pdata)
104 return -ENODEV;
105
106 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
107 if (!res)
108 return -ENODEV;
109
110 io_base = ioremap(res->start, resource_size(res));
111 if (!io_base) {
112 ret = -ENOMEM;
113 goto free_state;
114 }
115
116 /* make sure protocol 1 is selected */
117 val = readl(io_base + HSEM_CTRL_REG);
118 writel((val & ~HSEM_PROTOCOL_1), io_base + HSEM_CTRL_REG);
119
120 /* clear all interrupts */
121 writel(0xFFFF, io_base + HSEM_ICRALL);
122
123 bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL);
124 if (!bank) {
125 ret = -ENOMEM;
126 goto iounmap_base;
127 }
128
129 platform_set_drvdata(pdev, bank);
130
131 for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
132 hwlock->priv = io_base + HSEM_REGISTER_OFFSET + sizeof(u32) * i;
133
134 /* no pm needed for HSem but required to comply with hwspilock core */
135 pm_runtime_enable(&pdev->dev);
136
137 ret = hwspin_lock_register(bank, &pdev->dev, &u8500_hwspinlock_ops,
138 pdata->base_id, num_locks);
139 if (ret)
140 goto reg_fail;
141
142 return 0;
143
144reg_fail:
145 pm_runtime_disable(&pdev->dev);
146 kfree(bank);
147iounmap_base:
148 iounmap(io_base);
149 return ret;
150}
151
152static int __devexit u8500_hsem_remove(struct platform_device *pdev)
153{
154 struct hwspinlock_device *bank = platform_get_drvdata(pdev);
155 void __iomem *io_base = bank->lock[0].priv - HSEM_REGISTER_OFFSET;
156 int ret;
157
158 /* clear all interrupts */
159 writel(0xFFFF, io_base + HSEM_ICRALL);
160
161 ret = hwspin_lock_unregister(bank);
162 if (ret) {
163 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
164 return ret;
165 }
166
167 pm_runtime_disable(&pdev->dev);
168 iounmap(io_base);
169 kfree(bank);
170
171 return 0;
172}
173
174static struct platform_driver u8500_hsem_driver = {
175 .probe = u8500_hsem_probe,
176 .remove = __devexit_p(u8500_hsem_remove),
177 .driver = {
178 .name = "u8500_hsem",
179 .owner = THIS_MODULE,
180 },
181};
182
183static int __init u8500_hsem_init(void)
184{
185 return platform_driver_register(&u8500_hsem_driver);
186}
187/* board init code might need to reserve hwspinlocks for predefined purposes */
188postcore_initcall(u8500_hsem_init);
189
190static void __exit u8500_hsem_exit(void)
191{
192 platform_driver_unregister(&u8500_hsem_driver);
193}
194module_exit(u8500_hsem_exit);
195
196MODULE_LICENSE("GPL v2");
197MODULE_DESCRIPTION("Hardware Spinlock driver for u8500");
198MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index e8ff1239668..101cd31c822 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1270,7 +1270,7 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
1270 } 1270 }
1271 } else { 1271 } else {
1272 if (!host->protect_card) { 1272 if (!host->protect_card) {
1273 pr_info"%s: cover is open, " 1273 pr_info("%s: cover is open, "
1274 "card is now inaccessible\n", 1274 "card is now inaccessible\n",
1275 mmc_hostname(host->mmc)); 1275 mmc_hostname(host->mmc));
1276 host->protect_card = 1; 1276 host->protect_card = 1;
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index 8390efc457e..08a2fee4065 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -20,17 +20,49 @@
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;
32
33/**
34 * struct hwspinlock_pdata - platform data for hwspinlock drivers
35 * @base_id: base id for this hwspinlock device
36 *
37 * hwspinlock devices provide system-wide hardware locks that are used
38 * by remote processors that have no other way to achieve synchronization.
39 *
40 * To achieve that, each physical lock must have a system-wide id number
41 * that is agreed upon, otherwise remote processors can't possibly assume
42 * they're using the same hardware lock.
43 *
44 * Usually boards have a single hwspinlock device, which provides several
45 * hwspinlocks, and in this case, they can be trivially numbered 0 to
46 * (num-of-locks - 1).
47 *
48 * In case boards have several hwspinlocks devices, a different base id
49 * should be used for each hwspinlock device (they can't all use 0 as
50 * a starting id!).
51 *
52 * This platform data structure should be used to provide the base id
53 * for each device (which is trivially 0 when only a single hwspinlock
54 * device exists). It can be shared between different platforms, hence
55 * its location.
56 */
57struct hwspinlock_pdata {
58 int base_id;
59};
29 60
30#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE) 61#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE)
31 62
32int hwspin_lock_register(struct hwspinlock *lock); 63int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
33struct 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);
34struct hwspinlock *hwspin_lock_request(void); 66struct hwspinlock *hwspin_lock_request(void);
35struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 67struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
36int hwspin_lock_free(struct hwspinlock *hwlock); 68int hwspin_lock_free(struct hwspinlock *hwlock);
@@ -94,16 +126,6 @@ static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
94 return 0; 126 return 0;
95} 127}
96 128
97static inline int hwspin_lock_register(struct hwspinlock *hwlock)
98{
99 return -ENODEV;
100}
101
102static inline struct hwspinlock *hwspin_lock_unregister(unsigned int id)
103{
104 return NULL;
105}
106
107#endif /* !CONFIG_HWSPINLOCK */ 129#endif /* !CONFIG_HWSPINLOCK */
108 130
109/** 131/**