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 " #fail \ 32 : \ 33 : "r" (ptr) \ 34 : "ip", "lr", "cc"); \ 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 " #fail "\n" \ 54" mov %0, ip" \ 55 : "=&r" (result) \ 56 : "r" (ptr) \ 57 : "ip", "lr", "cc"); \ 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 " #wake \ 76 : \ 77 : "r" (ptr) \ 78 : "ip", "lr", "cc"); \ 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 " #fail \ 108 : \ 109 : "r" (ptr), "I" (RW_LOCK_BIAS) \ 110 : "ip", "lr", "cc"); \ 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 " #wake \ 131 : \ 132 : "r" (ptr), "I" (RW_LOCK_BIAS) \ 133 : "ip", "lr", "cc"); \ 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 " #wake \ 156 : \ 157 : "r" (ptr), "I" (1) \ 158 : "ip", "lr", "cc"); \ 159 }) 160 161#endif 162