diff options
| -rw-r--r-- | drivers/acpi/osl.c | 89 | ||||
| -rw-r--r-- | include/linux/semaphore.h | 6 | ||||
| -rw-r--r-- | kernel/semaphore.c | 42 |
3 files changed, 62 insertions, 75 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a697fb6cf050..a498a6cc68fe 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | * Copyright (C) 2000 Andrew Henroid | 4 | * Copyright (C) 2000 Andrew Henroid |
| 5 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 5 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
| 6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
| 7 | * Copyright (c) 2008 Intel Corporation | ||
| 8 | * Author: Matthew Wilcox <willy@linux.intel.com> | ||
| 7 | * | 9 | * |
| 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 9 | * | 11 | * |
| @@ -37,15 +39,18 @@ | |||
| 37 | #include <linux/workqueue.h> | 39 | #include <linux/workqueue.h> |
| 38 | #include <linux/nmi.h> | 40 | #include <linux/nmi.h> |
| 39 | #include <linux/acpi.h> | 41 | #include <linux/acpi.h> |
| 40 | #include <acpi/acpi.h> | ||
| 41 | #include <asm/io.h> | ||
| 42 | #include <acpi/acpi_bus.h> | ||
| 43 | #include <acpi/processor.h> | ||
| 44 | #include <asm/uaccess.h> | ||
| 45 | |||
| 46 | #include <linux/efi.h> | 42 | #include <linux/efi.h> |
| 47 | #include <linux/ioport.h> | 43 | #include <linux/ioport.h> |
| 48 | #include <linux/list.h> | 44 | #include <linux/list.h> |
| 45 | #include <linux/jiffies.h> | ||
| 46 | #include <linux/semaphore.h> | ||
| 47 | |||
| 48 | #include <asm/io.h> | ||
| 49 | #include <asm/uaccess.h> | ||
| 50 | |||
| 51 | #include <acpi/acpi.h> | ||
| 52 | #include <acpi/acpi_bus.h> | ||
| 53 | #include <acpi/processor.h> | ||
| 49 | 54 | ||
| 50 | #define _COMPONENT ACPI_OS_SERVICES | 55 | #define _COMPONENT ACPI_OS_SERVICES |
| 51 | ACPI_MODULE_NAME("osl"); | 56 | ACPI_MODULE_NAME("osl"); |
| @@ -764,7 +769,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) | |||
| 764 | { | 769 | { |
| 765 | struct semaphore *sem = NULL; | 770 | struct semaphore *sem = NULL; |
| 766 | 771 | ||
| 767 | |||
| 768 | sem = acpi_os_allocate(sizeof(struct semaphore)); | 772 | sem = acpi_os_allocate(sizeof(struct semaphore)); |
| 769 | if (!sem) | 773 | if (!sem) |
| 770 | return AE_NO_MEMORY; | 774 | return AE_NO_MEMORY; |
| @@ -791,12 +795,12 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) | |||
| 791 | { | 795 | { |
| 792 | struct semaphore *sem = (struct semaphore *)handle; | 796 | struct semaphore *sem = (struct semaphore *)handle; |
| 793 | 797 | ||
| 794 | |||
| 795 | if (!sem) | 798 | if (!sem) |
| 796 | return AE_BAD_PARAMETER; | 799 | return AE_BAD_PARAMETER; |
| 797 | 800 | ||
| 798 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); | 801 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); |
| 799 | 802 | ||
| 803 | BUG_ON(!list_empty(&sem->wait_list)); | ||
| 800 | kfree(sem); | 804 | kfree(sem); |
| 801 | sem = NULL; | 805 | sem = NULL; |
| 802 | 806 | ||
| @@ -804,21 +808,15 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle) | |||
| 804 | } | 808 | } |
| 805 | 809 | ||
| 806 | /* | 810 | /* |
| 807 | * TODO: The kernel doesn't have a 'down_timeout' function -- had to | ||
| 808 | * improvise. The process is to sleep for one scheduler quantum | ||
| 809 | * until the semaphore becomes available. Downside is that this | ||
| 810 | * may result in starvation for timeout-based waits when there's | ||
| 811 | * lots of semaphore activity. | ||
| 812 | * | ||
| 813 | * TODO: Support for units > 1? | 811 | * TODO: Support for units > 1? |
| 814 | */ | 812 | */ |
| 815 | acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) | 813 | acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) |
| 816 | { | 814 | { |
| 817 | acpi_status status = AE_OK; | 815 | acpi_status status = AE_OK; |
| 818 | struct semaphore *sem = (struct semaphore *)handle; | 816 | struct semaphore *sem = (struct semaphore *)handle; |
| 817 | long jiffies; | ||
| 819 | int ret = 0; | 818 | int ret = 0; |
| 820 | 819 | ||
| 821 | |||
| 822 | if (!sem || (units < 1)) | 820 | if (!sem || (units < 1)) |
| 823 | return AE_BAD_PARAMETER; | 821 | return AE_BAD_PARAMETER; |
| 824 | 822 | ||
| @@ -828,58 +826,14 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) | |||
| 828 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", | 826 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", |
| 829 | handle, units, timeout)); | 827 | handle, units, timeout)); |
| 830 | 828 | ||
| 831 | /* | 829 | if (timeout == ACPI_WAIT_FOREVER) |
| 832 | * This can be called during resume with interrupts off. | 830 | jiffies = MAX_SCHEDULE_TIMEOUT; |
| 833 | * Like boot-time, we should be single threaded and will | 831 | else |
| 834 | * always get the lock if we try -- timeout or not. | 832 | jiffies = msecs_to_jiffies(timeout); |
| 835 | * If this doesn't succeed, then we will oops courtesy of | 833 | |
| 836 | * might_sleep() in down(). | 834 | ret = down_timeout(sem, jiffies); |
| 837 | */ | 835 | if (ret) |
| 838 | if (!down_trylock(sem)) | 836 | status = AE_TIME; |
| 839 | return AE_OK; | ||
| 840 | |||
| 841 | switch (timeout) { | ||
| 842 | /* | ||
| 843 | * No Wait: | ||
| 844 | * -------- | ||
| 845 | * A zero timeout value indicates that we shouldn't wait - just | ||
| 846 | * acquire the semaphore if available otherwise return AE_TIME | ||
| 847 | * (a.k.a. 'would block'). | ||
| 848 | */ | ||
| 849 | case 0: | ||
| 850 | if (down_trylock(sem)) | ||
| 851 | status = AE_TIME; | ||
| 852 | break; | ||
| 853 | |||
| 854 | /* | ||
| 855 | * Wait Indefinitely: | ||
| 856 | * ------------------ | ||
| 857 | */ | ||
| 858 | case ACPI_WAIT_FOREVER: | ||
| 859 | down(sem); | ||
| 860 | break; | ||
| 861 | |||
| 862 | /* | ||
| 863 | * Wait w/ Timeout: | ||
| 864 | * ---------------- | ||
| 865 | */ | ||
| 866 | default: | ||
| 867 | // TODO: A better timeout algorithm? | ||
| 868 | { | ||
| 869 | int i = 0; | ||
| 870 | static const int quantum_ms = 1000 / HZ; | ||
| 871 | |||
| 872 | ret = down_trylock(sem); | ||
| 873 | for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) { | ||
| 874 | schedule_timeout_interruptible(1); | ||
| 875 | ret = down_trylock(sem); | ||
| 876 | } | ||
| 877 | |||
| 878 | if (ret != 0) | ||
| 879 | status = AE_TIME; | ||
| 880 | } | ||
| 881 | break; | ||
| 882 | } | ||
| 883 | 837 | ||
| 884 | if (ACPI_FAILURE(status)) { | 838 | if (ACPI_FAILURE(status)) { |
| 885 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | 839 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
| @@ -902,7 +856,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) | |||
| 902 | { | 856 | { |
| 903 | struct semaphore *sem = (struct semaphore *)handle; | 857 | struct semaphore *sem = (struct semaphore *)handle; |
| 904 | 858 | ||
| 905 | |||
| 906 | if (!sem || (units < 1)) | 859 | if (!sem || (units < 1)) |
| 907 | return AE_BAD_PARAMETER; | 860 | return AE_BAD_PARAMETER; |
| 908 | 861 | ||
diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index 88f2a28cc0f1..a107aebd9148 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h | |||
| @@ -75,6 +75,12 @@ extern int __must_check down_killable(struct semaphore *sem); | |||
| 75 | extern int __must_check down_trylock(struct semaphore *sem); | 75 | extern int __must_check down_trylock(struct semaphore *sem); |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| 78 | * As down(), except this function will return -ETIME if it fails to | ||
| 79 | * acquire the semaphore within the specified number of jiffies. | ||
| 80 | */ | ||
| 81 | extern int __must_check down_timeout(struct semaphore *sem, long jiffies); | ||
| 82 | |||
| 83 | /* | ||
| 78 | * Release the semaphore. Unlike mutexes, up() may be called from any | 84 | * Release the semaphore. Unlike mutexes, up() may be called from any |
| 79 | * context and even by tasks which have never called down(). | 85 | * context and even by tasks which have never called down(). |
| 80 | */ | 86 | */ |
diff --git a/kernel/semaphore.c b/kernel/semaphore.c index 2da2aed950f3..5a12a8558982 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | static noinline void __down(struct semaphore *sem); | 35 | static noinline void __down(struct semaphore *sem); |
| 36 | static noinline int __down_interruptible(struct semaphore *sem); | 36 | static noinline int __down_interruptible(struct semaphore *sem); |
| 37 | static noinline int __down_killable(struct semaphore *sem); | 37 | static noinline int __down_killable(struct semaphore *sem); |
| 38 | static noinline int __down_timeout(struct semaphore *sem, long jiffies); | ||
| 38 | static noinline void __up(struct semaphore *sem); | 39 | static noinline void __up(struct semaphore *sem); |
| 39 | 40 | ||
| 40 | void down(struct semaphore *sem) | 41 | void down(struct semaphore *sem) |
| @@ -104,6 +105,20 @@ int down_trylock(struct semaphore *sem) | |||
| 104 | } | 105 | } |
| 105 | EXPORT_SYMBOL(down_trylock); | 106 | EXPORT_SYMBOL(down_trylock); |
| 106 | 107 | ||
| 108 | int down_timeout(struct semaphore *sem, long jiffies) | ||
| 109 | { | ||
| 110 | unsigned long flags; | ||
| 111 | int result = 0; | ||
| 112 | |||
| 113 | spin_lock_irqsave(&sem->lock, flags); | ||
| 114 | if (unlikely(sem->count-- <= 0)) | ||
| 115 | result = __down_timeout(sem, jiffies); | ||
| 116 | spin_unlock_irqrestore(&sem->lock, flags); | ||
| 117 | |||
| 118 | return result; | ||
| 119 | } | ||
| 120 | EXPORT_SYMBOL(down_timeout); | ||
| 121 | |||
| 107 | void up(struct semaphore *sem) | 122 | void up(struct semaphore *sem) |
| 108 | { | 123 | { |
| 109 | unsigned long flags; | 124 | unsigned long flags; |
| @@ -142,10 +157,12 @@ static noinline void __sched __up_down_common(struct semaphore *sem) | |||
| 142 | } | 157 | } |
| 143 | 158 | ||
| 144 | /* | 159 | /* |
| 145 | * Because this function is inlined, the 'state' parameter will be constant, | 160 | * Because this function is inlined, the 'state' parameter will be |
| 146 | * and thus optimised away by the compiler. | 161 | * constant, and thus optimised away by the compiler. Likewise the |
| 162 | * 'timeout' parameter for the cases without timeouts. | ||
| 147 | */ | 163 | */ |
| 148 | static inline int __sched __down_common(struct semaphore *sem, long state) | 164 | static inline int __sched __down_common(struct semaphore *sem, long state, |
| 165 | long timeout) | ||
| 149 | { | 166 | { |
| 150 | int result = 0; | 167 | int result = 0; |
| 151 | struct task_struct *task = current; | 168 | struct task_struct *task = current; |
| @@ -160,14 +177,20 @@ static inline int __sched __down_common(struct semaphore *sem, long state) | |||
| 160 | goto interrupted; | 177 | goto interrupted; |
| 161 | if (state == TASK_KILLABLE && fatal_signal_pending(task)) | 178 | if (state == TASK_KILLABLE && fatal_signal_pending(task)) |
| 162 | goto interrupted; | 179 | goto interrupted; |
| 180 | if (timeout <= 0) | ||
| 181 | goto timed_out; | ||
| 163 | __set_task_state(task, state); | 182 | __set_task_state(task, state); |
| 164 | spin_unlock_irq(&sem->lock); | 183 | spin_unlock_irq(&sem->lock); |
| 165 | schedule(); | 184 | timeout = schedule_timeout(timeout); |
| 166 | spin_lock_irq(&sem->lock); | 185 | spin_lock_irq(&sem->lock); |
| 167 | if (waiter.up) | 186 | if (waiter.up) |
| 168 | goto woken; | 187 | goto woken; |
| 169 | } | 188 | } |
| 170 | 189 | ||
| 190 | timed_out: | ||
| 191 | list_del(&waiter.list); | ||
| 192 | result = -ETIME; | ||
| 193 | goto woken; | ||
| 171 | interrupted: | 194 | interrupted: |
| 172 | list_del(&waiter.list); | 195 | list_del(&waiter.list); |
| 173 | result = -EINTR; | 196 | result = -EINTR; |
| @@ -187,17 +210,22 @@ static inline int __sched __down_common(struct semaphore *sem, long state) | |||
| 187 | 210 | ||
| 188 | static noinline void __sched __down(struct semaphore *sem) | 211 | static noinline void __sched __down(struct semaphore *sem) |
| 189 | { | 212 | { |
| 190 | __down_common(sem, TASK_UNINTERRUPTIBLE); | 213 | __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); |
| 191 | } | 214 | } |
| 192 | 215 | ||
| 193 | static noinline int __sched __down_interruptible(struct semaphore *sem) | 216 | static noinline int __sched __down_interruptible(struct semaphore *sem) |
| 194 | { | 217 | { |
| 195 | return __down_common(sem, TASK_INTERRUPTIBLE); | 218 | return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); |
| 196 | } | 219 | } |
| 197 | 220 | ||
| 198 | static noinline int __sched __down_killable(struct semaphore *sem) | 221 | static noinline int __sched __down_killable(struct semaphore *sem) |
| 199 | { | 222 | { |
| 200 | return __down_common(sem, TASK_KILLABLE); | 223 | return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT); |
| 224 | } | ||
| 225 | |||
| 226 | static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies) | ||
| 227 | { | ||
| 228 | return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies); | ||
| 201 | } | 229 | } |
| 202 | 230 | ||
| 203 | static noinline void __sched __up(struct semaphore *sem) | 231 | static noinline void __sched __up(struct semaphore *sem) |
