1 /* 2 * linux/include/asm-arm/proc-armo/locks.h 3 * 4 * Copyright (C) 2000 Russell King 5 * Fixes for 26 bit machines, (C) 2000 Dave Gilbert 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Interrupt safe locking assembler. 12 */ 13 #ifndef __ASM_PROC_LOCKS_H 14 #define __ASM_PROC_LOCKS_H 15 16 /* Decrements by 1, fails if value < 0 */ 17 #define __down_op(ptr,fail) \ 18 ({ \ 19 __asm__ __volatile__ ( \ 20 "@ atomic down operation\n" \ 21 " mov ip, pc\n" \ 22 " orr lr, ip, #0x08000000\n" \ 23 " teqp lr, #0\n" \ 24 " ldr lr, [%0]\n" \ 25 " and ip, ip, #0x0c000003\n" \ 26 " subs lr, lr, #1\n" \ 27 " str lr, [%0]\n" \ 28 " orrmi ip, ip, #0x80000000 @ set N\n" \ 29 " teqp ip, #0\n" \ 30 " movmi ip, %0\n" \ 31 " blmi " SYMBOL_NAME_STR(fail) \ 32 : \ 33 : "r" (ptr) \ 34 : "ip", "lr", "cc", "memory"); \ 35 }) 36 37 #define __down_op_ret(ptr,fail) \ 38 ({ \ 39 unsigned int result; \ 40 __asm__ __volatile__ ( \ 41 " @ down_op_ret\n" \ 42 " mov ip, pc\n" \ 43 " orr lr, ip, #0x08000000\n" \ 44 " teqp lr, #0\n" \ 45 " ldr lr, [%1]\n" \ 46 " and ip, ip, #0x0c000003\n" \ 47 " subs lr, lr, #1\n" \ 48 " str lr, [%1]\n" \ 49 " orrmi ip, ip, #0x80000000 @ set N\n" \ 50 " teqp ip, #0\n" \ 51 " movmi ip, %1\n" \ 52 " movpl ip, #0\n" \ 53 " blmi " SYMBOL_NAME_STR(fail) "\n" \ 54 " mov %0, ip" \ 55 : "=&r" (result) \ 56 : "r" (ptr) \ 57 : "ip", "lr", "cc", "memory"); \ 58 result; \ 59 }) 60 61 #define __up_op(ptr,wake) \ 62 ({ \ 63 __asm__ __volatile__ ( \ 64 "@ up_op\n" \ 65 " mov ip, pc\n" \ 66 " orr lr, ip, #0x08000000\n" \ 67 " teqp lr, #0\n" \ 68 " ldr lr, [%0]\n" \ 69 " and ip, ip, #0x0c000003\n" \ 70 " adds lr, lr, #1\n" \ 71 " str lr, [%0]\n" \ 72 " orrle ip, ip, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \ 73 " teqp ip, #0\n" \ 74 " movmi ip, %0\n" \ 75 " blmi " SYMBOL_NAME_STR(wake) \ 76 : \ 77 : "r" (ptr) \ 78 : "ip", "lr", "cc", "memory"); \ 79 }) 80 81 /* 82 * The value 0x01000000 supports up to 128 processors and 83 * lots of processes. BIAS must be chosen such that sub'ing 84 * BIAS once per CPU will result in the long remaining 85 * negative. 86 */ 87 #define RW_LOCK_BIAS 0x01000000 88 #define RW_LOCK_BIAS_STR "0x01000000" 89 90 /* Decrements by RW_LOCK_BIAS rather than 1, fails if value != 0 */ 91 #define __down_op_write(ptr,fail) \ 92 ({ \ 93 __asm__ __volatile__( \ 94 "@ down_op_write\n" \ 95 " mov ip, pc\n" \ 96 " orr lr, ip, #0x08000000\n" \ 97 " teqp lr, #0\n" \ 98 " and ip, ip, #0x0c000003\n" \ 99 \ 100 " ldr lr, [%0]\n" \ 101 " subs lr, lr, %1\n" \ 102 " str lr, [%0]\n" \ 103 \ 104 " orreq ip, ip, #0x40000000 @ set Z \n"\ 105 " teqp ip, #0\n" \ 106 " movne ip, %0\n" \ 107 " blne " SYMBOL_NAME_STR(fail) \ 108 : \ 109 : "r" (ptr), "I" (RW_LOCK_BIAS) \ 110 : "ip", "lr", "cc", "memory"); \ 111 }) 112 113 /* Increments by RW_LOCK_BIAS, wakes if value >= 0 */ 114 #define __up_op_write(ptr,wake) \ 115 ({ \ 116 __asm__ __volatile__( \ 117 "@ up_op_read\n" \ 118 " mov ip, pc\n" \ 119 " orr lr, ip, #0x08000000\n" \ 120 " teqp lr, #0\n" \ 121 \ 122 " ldr lr, [%0]\n" \ 123 " and ip, ip, #0x0c000003\n" \ 124 " adds lr, lr, %1\n" \ 125 " str lr, [%0]\n" \ 126 \ 127 " orrcs ip, ip, #0x20000000 @ set C\n" \ 128 " teqp ip, #0\n" \ 129 " movcs ip, %0\n" \ 130 " blcs " SYMBOL_NAME_STR(wake) \ 131 : \ 132 : "r" (ptr), "I" (RW_LOCK_BIAS) \ 133 : "ip", "lr", "cc", "memory"); \ 134 }) 135 136 #define __down_op_read(ptr,fail) \ 137 __down_op(ptr, fail) 138 139 #define __up_op_read(ptr,wake) \ 140 ({ \ 141 __asm__ __volatile__( \ 142 "@ up_op_read\n" \ 143 " mov ip, pc\n" \ 144 " orr lr, ip, #0x08000000\n" \ 145 " teqp lr, #0\n" \ 146 \ 147 " ldr lr, [%0]\n" \ 148 " and ip, ip, #0x0c000003\n" \ 149 " adds lr, lr, %1\n" \ 150 " str lr, [%0]\n" \ 151 \ 152 " orreq ip, ip, #0x40000000 @ Set Z \n" \ 153 " teqp ip, #0\n" \ 154 " moveq ip, %0\n" \ 155 " bleq " SYMBOL_NAME_STR(wake) \ 156 : \ 157 : "r" (ptr), "I" (1) \ 158 : "ip", "lr", "cc", "memory"); \ 159 }) 160 161 #endif 162