| Eric Holmberg | f9cfa8e | 2011-09-23 14:29:11 -0600 | [diff] [blame] | 1 | /* Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved. | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 2 | * | 
|  | 3 | * This program is free software; you can redistribute it and/or modify | 
|  | 4 | * it under the terms of the GNU General Public License version 2 and | 
|  | 5 | * only version 2 as published by the Free Software Foundation. | 
|  | 6 | * | 
|  | 7 | * This program is distributed in the hope that it will be useful, | 
|  | 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 10 | * GNU General Public License for more details. | 
|  | 11 | * | 
|  | 12 | */ | 
|  | 13 | #ifndef __LINUX_REMOTE_SPINLOCK_H | 
|  | 14 | #define __LINUX_REMOTE_SPINLOCK_H | 
|  | 15 |  | 
|  | 16 | #include <linux/spinlock.h> | 
|  | 17 | #include <linux/mutex.h> | 
|  | 18 |  | 
|  | 19 | #include <asm/remote_spinlock.h> | 
|  | 20 |  | 
|  | 21 | /* Grabbing a local spin lock before going for a remote lock has several | 
|  | 22 | * advantages: | 
|  | 23 | * 1. Get calls to preempt enable/disable and IRQ save/restore for free. | 
|  | 24 | * 2. For UP kernel, there is no overhead. | 
|  | 25 | * 3. Reduces the possibility of executing the remote spin lock code. This is | 
|  | 26 | *    especially useful when the remote CPUs' mutual exclusion instructions | 
|  | 27 | *    don't work with the local CPUs' instructions. In such cases, one has to | 
|  | 28 | *    use software based mutex algorithms (e.g. Lamport's bakery algorithm) | 
|  | 29 | *    which could get expensive when the no. of contending CPUs is high. | 
|  | 30 | * 4. In the case of software based mutex algorithm the exection time will be | 
|  | 31 | *    smaller since the no. of contending CPUs is reduced by having just one | 
|  | 32 | *    contender for all the local CPUs. | 
|  | 33 | * 5. Get most of the spin lock debug features for free. | 
|  | 34 | * 6. The code will continue to work "gracefully" even when the remote spin | 
|  | 35 | *    lock code is stubbed out for debug purposes or when there is no remote | 
|  | 36 | *    CPU in some board/machine types. | 
|  | 37 | */ | 
|  | 38 | typedef struct { | 
|  | 39 | spinlock_t local; | 
|  | 40 | _remote_spinlock_t remote; | 
|  | 41 | } remote_spinlock_t; | 
|  | 42 |  | 
|  | 43 | #define remote_spin_lock_init(lock, id) \ | 
|  | 44 | ({ \ | 
|  | 45 | spin_lock_init(&((lock)->local)); \ | 
|  | 46 | _remote_spin_lock_init(id, &((lock)->remote)); \ | 
|  | 47 | }) | 
|  | 48 | #define remote_spin_lock(lock) \ | 
|  | 49 | do { \ | 
|  | 50 | spin_lock(&((lock)->local)); \ | 
|  | 51 | _remote_spin_lock(&((lock)->remote)); \ | 
|  | 52 | } while (0) | 
|  | 53 | #define remote_spin_unlock(lock) \ | 
|  | 54 | do { \ | 
|  | 55 | _remote_spin_unlock(&((lock)->remote)); \ | 
|  | 56 | spin_unlock(&((lock)->local)); \ | 
|  | 57 | } while (0) | 
|  | 58 | #define remote_spin_lock_irqsave(lock, flags) \ | 
|  | 59 | do { \ | 
|  | 60 | spin_lock_irqsave(&((lock)->local), flags); \ | 
|  | 61 | _remote_spin_lock(&((lock)->remote)); \ | 
|  | 62 | } while (0) | 
|  | 63 | #define remote_spin_unlock_irqrestore(lock, flags) \ | 
|  | 64 | do { \ | 
|  | 65 | _remote_spin_unlock(&((lock)->remote)); \ | 
|  | 66 | spin_unlock_irqrestore(&((lock)->local), flags); \ | 
|  | 67 | } while (0) | 
|  | 68 | #define remote_spin_trylock(lock) \ | 
|  | 69 | ({ \ | 
|  | 70 | spin_trylock(&((lock)->local)) \ | 
|  | 71 | ? _remote_spin_trylock(&((lock)->remote)) \ | 
|  | 72 | ? 1 \ | 
|  | 73 | : ({ spin_unlock(&((lock)->local)); 0; }) \ | 
|  | 74 | : 0; \ | 
|  | 75 | }) | 
|  | 76 | #define remote_spin_trylock_irqsave(lock, flags) \ | 
|  | 77 | ({ \ | 
|  | 78 | spin_trylock_irqsave(&((lock)->local), flags) \ | 
|  | 79 | ? _remote_spin_trylock(&((lock)->remote)) \ | 
|  | 80 | ? 1 \ | 
|  | 81 | : ({ spin_unlock_irqrestore(&((lock)->local), flags); \ | 
|  | 82 | 0; }) \ | 
|  | 83 | : 0; \ | 
|  | 84 | }) | 
|  | 85 |  | 
| Eric Holmberg | f9cfa8e | 2011-09-23 14:29:11 -0600 | [diff] [blame] | 86 | #define remote_spin_release(lock, pid) \ | 
|  | 87 | _remote_spin_release(&((lock)->remote), pid) | 
|  | 88 |  | 
|  | 89 | #define remote_spin_release_all(pid) \ | 
|  | 90 | _remote_spin_release_all(pid) | 
| Bryan Huntsman | 3f2bc4d | 2011-08-16 17:27:22 -0700 | [diff] [blame] | 91 |  | 
|  | 92 | typedef struct { | 
|  | 93 | struct mutex local; | 
|  | 94 | _remote_mutex_t remote; | 
|  | 95 | } remote_mutex_t; | 
|  | 96 |  | 
|  | 97 | #define remote_mutex_init(lock, id) \ | 
|  | 98 | ({ \ | 
|  | 99 | mutex_init(&((lock)->local)); \ | 
|  | 100 | _remote_mutex_init(id, &((lock)->remote)); \ | 
|  | 101 | }) | 
|  | 102 | #define remote_mutex_lock(lock) \ | 
|  | 103 | do { \ | 
|  | 104 | mutex_lock(&((lock)->local)); \ | 
|  | 105 | _remote_mutex_lock(&((lock)->remote)); \ | 
|  | 106 | } while (0) | 
|  | 107 | #define remote_mutex_trylock(lock) \ | 
|  | 108 | ({ \ | 
|  | 109 | mutex_trylock(&((lock)->local)) \ | 
|  | 110 | ? _remote_mutex_trylock(&((lock)->remote)) \ | 
|  | 111 | ? 1 \ | 
|  | 112 | : ({mutex_unlock(&((lock)->local)); 0; }) \ | 
|  | 113 | : 0; \ | 
|  | 114 | }) | 
|  | 115 | #define remote_mutex_unlock(lock) \ | 
|  | 116 | do { \ | 
|  | 117 | _remote_mutex_unlock(&((lock)->remote)); \ | 
|  | 118 | mutex_unlock(&((lock)->local)); \ | 
|  | 119 | } while (0) | 
|  | 120 |  | 
|  | 121 | #endif |