1 2 3#ifndef __ASM_REGOPS_H__ 4#define __ASM_REGOPS_H__ 5 6#include <linux/types.h> 7 8#include <asm/war.h> 9 10#ifndef R10000_LLSC_WAR 11#define R10000_LLSC_WAR 0 12#endif 13 14#if R10000_LLSC_WAR == 1 15#define __beqz "beqzl " 16#else 17#define __beqz "beqz " 18#endif 19 20#ifndef _LINUX_TYPES_H 21typedef unsigned int u32; 22#endif 23 24/* 25 * Sets all the masked bits to the corresponding value bits 26 */ 27static inline void set_value_reg32(volatile u32 *const addr, 28 u32 const mask, 29 u32 const value) 30{ 31 u32 temp; 32 33 __asm__ __volatile__( 34 " .set push \n" 35 " .set mips3 \n" 36 "1: ll %0, %1 # set_value_reg32 \n" 37 " and %0, %2 \n" 38 " or %0, %3 \n" 39 " sc %0, %1 \n" 40 " "__beqz"%0, 1b \n" 41 " nop \n" 42 " .set pop \n" 43 : "=&r" (temp), "=m" (*addr) 44 : "ir" (~mask), "ir" (value), "m" (*addr)); 45} 46 47/* 48 * Sets all the masked bits to '1' 49 */ 50static inline void set_reg32(volatile u32 *const addr, 51 u32 const mask) 52{ 53 u32 temp; 54 55 __asm__ __volatile__( 56 " .set push \n" 57 " .set mips3 \n" 58 "1: ll %0, %1 # set_reg32 \n" 59 " or %0, %2 \n" 60 " sc %0, %1 \n" 61 " "__beqz"%0, 1b \n" 62 " nop \n" 63 " .set pop \n" 64 : "=&r" (temp), "=m" (*addr) 65 : "ir" (mask), "m" (*addr)); 66} 67 68/* 69 * Sets all the masked bits to '0' 70 */ 71static inline void clear_reg32(volatile u32 *const addr, 72 u32 const mask) 73{ 74 u32 temp; 75 76 __asm__ __volatile__( 77 " .set push \n" 78 " .set mips3 \n" 79 "1: ll %0, %1 # clear_reg32 \n" 80 " and %0, %2 \n" 81 " sc %0, %1 \n" 82 " "__beqz"%0, 1b \n" 83 " nop \n" 84 " .set pop \n" 85 : "=&r" (temp), "=m" (*addr) 86 : "ir" (~mask), "m" (*addr)); 87} 88 89/* 90 * Toggles all masked bits from '0' to '1' and '1' to '0' 91 */ 92static inline void toggle_reg32(volatile u32 *const addr, 93 u32 const mask) 94{ 95 u32 temp; 96 97 __asm__ __volatile__( 98 " .set push \n" 99 " .set mips3 \n" 100 "1: ll %0, %1 # toggle_reg32 \n" 101 " xor %0, %2 \n" 102 " sc %0, %1 \n" 103 " "__beqz"%0, 1b \n" 104 " nop \n" 105 " .set pop \n" 106 : "=&r" (temp), "=m" (*addr) 107 : "ir" (mask), "m" (*addr)); 108} 109 110/* 111 * Read all masked bits others are returned as '0' 112 */ 113static inline u32 read_reg32(volatile u32 *const addr, 114 u32 const mask) 115{ 116 u32 temp; 117 118 __asm__ __volatile__( 119 " .set push \n" 120 " .set noreorder \n" 121 " lw %0, %1 # read \n" 122 " and %0, %2 # mask \n" 123 " .set pop \n" 124 : "=&r" (temp) 125 : "m" (*addr), "ir" (mask)); 126 127 return temp; 128} 129 130/* 131 * blocking_read_reg32 - Read address with blocking load 132 * 133 * Uncached writes need to be read back to ensure they reach RAM. 134 * The returned value must be 'used' to prevent from becoming a 135 * non-blocking load. 136 */ 137static inline u32 blocking_read_reg32(volatile u32 *const addr) 138{ 139 u32 temp; 140 141 __asm__ __volatile__( 142 " .set push \n" 143 " .set noreorder \n" 144 " lw %0, %1 # read \n" 145 " move %0, %0 # block \n" 146 " .set pop \n" 147 : "=&r" (temp) 148 : "m" (*addr)); 149 150 return temp; 151} 152 153/* 154 * For special strange cases only: 155 * 156 * If you need custom processing within a ll/sc loop, use the following macros 157 * VERY CAREFULLY: 158 * 159 * u32 tmp; <-- Define a variable to hold the data 160 * 161 * custom_read_reg32(address, tmp); <-- Reads the address and put the value 162 * in the 'tmp' variable given 163 * 164 * From here on out, you are (basicly) atomic, so don't do anything too 165 * fancy! 166 * Also, this code may loop if the end of this block fails to write 167 * everything back safely due do the other CPU, so do NOT do anything 168 * with side-effects! 169 * 170 * custom_write_reg32(address, tmp); <-- Writes back 'tmp' safely. 171 */ 172#define custom_read_reg32(address, tmp) \ 173 __asm__ __volatile__( \ 174 " .set push \n" \ 175 " .set mips3 \n" \ 176 "1: ll %0, %1 #custom_read_reg32 \n" \ 177 " .set pop \n" \ 178 : "=r" (tmp), "=m" (*address) \ 179 : "m" (*address)) 180 181#define custom_write_reg32(address, tmp) \ 182 __asm__ __volatile__( \ 183 " .set push \n" \ 184 " .set mips3 \n" \ 185 " sc %0, %1 #custom_write_reg32 \n" \ 186 " "__beqz"%0, 1b \n" \ 187 " nop \n" \ 188 " .set pop \n" \ 189 : "=&r" (tmp), "=m" (*address) \ 190 : "0" (tmp), "m" (*address)) 191 192#endif /* __ASM_REGOPS_H__ */ 193