Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: add compile-time support for lbarx, lharx

ISA v2.06 (POWER7 and up) as well as e6500 support lbarx and lharx.
Add a compile option that allows code to use it, and add support in
cmpxchg and xchg 8 and 16 bit values without shifting and masking.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220909052312.63916-1-npiggin@gmail.com

authored by

Nicholas Piggin and committed by
Michael Ellerman
b86cf14f ff8fae94

+249 -11
+3
arch/powerpc/Kconfig
··· 293 293 default y 294 294 depends on PPC_BOOK3S_64 || PPC_E500 295 295 296 + config PPC_HAS_LBARX_LHARX 297 + bool 298 + 296 299 config EARLY_PRINTK 297 300 bool 298 301 default y
+230 -1
arch/powerpc/include/asm/cmpxchg.h
··· 77 77 * the previous value stored there. 78 78 */ 79 79 80 + #ifndef CONFIG_PPC_HAS_LBARX_LHARX 80 81 XCHG_GEN(u8, _local, "memory"); 81 82 XCHG_GEN(u8, _relaxed, "cc"); 82 83 XCHG_GEN(u16, _local, "memory"); 83 84 XCHG_GEN(u16, _relaxed, "cc"); 85 + #else 86 + static __always_inline unsigned long 87 + __xchg_u8_local(volatile void *p, unsigned long val) 88 + { 89 + unsigned long prev; 90 + 91 + __asm__ __volatile__( 92 + "1: lbarx %0,0,%2 # __xchg_u8_local\n" 93 + " stbcx. %3,0,%2 \n" 94 + " bne- 1b" 95 + : "=&r" (prev), "+m" (*(volatile unsigned char *)p) 96 + : "r" (p), "r" (val) 97 + : "cc", "memory"); 98 + 99 + return prev; 100 + } 101 + 102 + static __always_inline unsigned long 103 + __xchg_u8_relaxed(u8 *p, unsigned long val) 104 + { 105 + unsigned long prev; 106 + 107 + __asm__ __volatile__( 108 + "1: lbarx %0,0,%2 # __xchg_u8_relaxed\n" 109 + " stbcx. %3,0,%2\n" 110 + " bne- 1b" 111 + : "=&r" (prev), "+m" (*p) 112 + : "r" (p), "r" (val) 113 + : "cc"); 114 + 115 + return prev; 116 + } 117 + 118 + static __always_inline unsigned long 119 + __xchg_u16_local(volatile void *p, unsigned long val) 120 + { 121 + unsigned long prev; 122 + 123 + __asm__ __volatile__( 124 + "1: lharx %0,0,%2 # __xchg_u16_local\n" 125 + " sthcx. %3,0,%2\n" 126 + " bne- 1b" 127 + : "=&r" (prev), "+m" (*(volatile unsigned short *)p) 128 + : "r" (p), "r" (val) 129 + : "cc", "memory"); 130 + 131 + return prev; 132 + } 133 + 134 + static __always_inline unsigned long 135 + __xchg_u16_relaxed(u16 *p, unsigned long val) 136 + { 137 + unsigned long prev; 138 + 139 + __asm__ __volatile__( 140 + "1: lharx %0,0,%2 # __xchg_u16_relaxed\n" 141 + " sthcx. %3,0,%2\n" 142 + " bne- 1b" 143 + : "=&r" (prev), "+m" (*p) 144 + : "r" (p), "r" (val) 145 + : "cc"); 146 + 147 + return prev; 148 + } 149 + #endif 84 150 85 151 static __always_inline unsigned long 86 152 __xchg_u32_local(volatile void *p, unsigned long val) ··· 264 198 (__typeof__(*(ptr))) __xchg_relaxed((ptr), \ 265 199 (unsigned long)_x_, sizeof(*(ptr))); \ 266 200 }) 201 + 267 202 /* 268 203 * Compare and exchange - if *p == old, set it to new, 269 204 * and return the old value of *p. 270 205 */ 271 - 206 + #ifndef CONFIG_PPC_HAS_LBARX_LHARX 272 207 CMPXCHG_GEN(u8, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory"); 273 208 CMPXCHG_GEN(u8, _local, , , "memory"); 274 209 CMPXCHG_GEN(u8, _acquire, , PPC_ACQUIRE_BARRIER, "memory"); ··· 278 211 CMPXCHG_GEN(u16, _local, , , "memory"); 279 212 CMPXCHG_GEN(u16, _acquire, , PPC_ACQUIRE_BARRIER, "memory"); 280 213 CMPXCHG_GEN(u16, _relaxed, , , "cc"); 214 + #else 215 + static __always_inline unsigned long 216 + __cmpxchg_u8(volatile unsigned char *p, unsigned long old, unsigned long new) 217 + { 218 + unsigned int prev; 219 + 220 + __asm__ __volatile__ ( 221 + PPC_ATOMIC_ENTRY_BARRIER 222 + "1: lbarx %0,0,%2 # __cmpxchg_u8\n" 223 + " cmpw 0,%0,%3\n" 224 + " bne- 2f\n" 225 + " stbcx. %4,0,%2\n" 226 + " bne- 1b" 227 + PPC_ATOMIC_EXIT_BARRIER 228 + "\n\ 229 + 2:" 230 + : "=&r" (prev), "+m" (*p) 231 + : "r" (p), "r" (old), "r" (new) 232 + : "cc", "memory"); 233 + 234 + return prev; 235 + } 236 + 237 + static __always_inline unsigned long 238 + __cmpxchg_u8_local(volatile unsigned char *p, unsigned long old, 239 + unsigned long new) 240 + { 241 + unsigned int prev; 242 + 243 + __asm__ __volatile__ ( 244 + "1: lbarx %0,0,%2 # __cmpxchg_u8_local\n" 245 + " cmpw 0,%0,%3\n" 246 + " bne- 2f\n" 247 + " stbcx. %4,0,%2\n" 248 + " bne- 1b\n" 249 + "2:" 250 + : "=&r" (prev), "+m" (*p) 251 + : "r" (p), "r" (old), "r" (new) 252 + : "cc", "memory"); 253 + 254 + return prev; 255 + } 256 + 257 + static __always_inline unsigned long 258 + __cmpxchg_u8_relaxed(u8 *p, unsigned long old, unsigned long new) 259 + { 260 + unsigned long prev; 261 + 262 + __asm__ __volatile__ ( 263 + "1: lbarx %0,0,%2 # __cmpxchg_u8_relaxed\n" 264 + " cmpw 0,%0,%3\n" 265 + " bne- 2f\n" 266 + " stbcx. %4,0,%2\n" 267 + " bne- 1b\n" 268 + "2:" 269 + : "=&r" (prev), "+m" (*p) 270 + : "r" (p), "r" (old), "r" (new) 271 + : "cc"); 272 + 273 + return prev; 274 + } 275 + 276 + static __always_inline unsigned long 277 + __cmpxchg_u8_acquire(u8 *p, unsigned long old, unsigned long new) 278 + { 279 + unsigned long prev; 280 + 281 + __asm__ __volatile__ ( 282 + "1: lbarx %0,0,%2 # __cmpxchg_u8_acquire\n" 283 + " cmpw 0,%0,%3\n" 284 + " bne- 2f\n" 285 + " stbcx. %4,0,%2\n" 286 + " bne- 1b\n" 287 + PPC_ACQUIRE_BARRIER 288 + "2:" 289 + : "=&r" (prev), "+m" (*p) 290 + : "r" (p), "r" (old), "r" (new) 291 + : "cc", "memory"); 292 + 293 + return prev; 294 + } 295 + 296 + static __always_inline unsigned long 297 + __cmpxchg_u16(volatile unsigned short *p, unsigned long old, unsigned long new) 298 + { 299 + unsigned int prev; 300 + 301 + __asm__ __volatile__ ( 302 + PPC_ATOMIC_ENTRY_BARRIER 303 + "1: lharx %0,0,%2 # __cmpxchg_u16\n" 304 + " cmpw 0,%0,%3\n" 305 + " bne- 2f\n" 306 + " sthcx. %4,0,%2\n" 307 + " bne- 1b\n" 308 + PPC_ATOMIC_EXIT_BARRIER 309 + "2:" 310 + : "=&r" (prev), "+m" (*p) 311 + : "r" (p), "r" (old), "r" (new) 312 + : "cc", "memory"); 313 + 314 + return prev; 315 + } 316 + 317 + static __always_inline unsigned long 318 + __cmpxchg_u16_local(volatile unsigned short *p, unsigned long old, 319 + unsigned long new) 320 + { 321 + unsigned int prev; 322 + 323 + __asm__ __volatile__ ( 324 + "1: lharx %0,0,%2 # __cmpxchg_u16_local\n" 325 + " cmpw 0,%0,%3\n" 326 + " bne- 2f\n" 327 + " sthcx. %4,0,%2\n" 328 + " bne- 1b" 329 + "2:" 330 + : "=&r" (prev), "+m" (*p) 331 + : "r" (p), "r" (old), "r" (new) 332 + : "cc", "memory"); 333 + 334 + return prev; 335 + } 336 + 337 + static __always_inline unsigned long 338 + __cmpxchg_u16_relaxed(u16 *p, unsigned long old, unsigned long new) 339 + { 340 + unsigned long prev; 341 + 342 + __asm__ __volatile__ ( 343 + "1: lharx %0,0,%2 # __cmpxchg_u16_relaxed\n" 344 + " cmpw 0,%0,%3\n" 345 + " bne- 2f\n" 346 + " sthcx. %4,0,%2\n" 347 + " bne- 1b\n" 348 + "2:" 349 + : "=&r" (prev), "+m" (*p) 350 + : "r" (p), "r" (old), "r" (new) 351 + : "cc"); 352 + 353 + return prev; 354 + } 355 + 356 + static __always_inline unsigned long 357 + __cmpxchg_u16_acquire(u16 *p, unsigned long old, unsigned long new) 358 + { 359 + unsigned long prev; 360 + 361 + __asm__ __volatile__ ( 362 + "1: lharx %0,0,%2 # __cmpxchg_u16_acquire\n" 363 + " cmpw 0,%0,%3\n" 364 + " bne- 2f\n" 365 + " sthcx. %4,0,%2\n" 366 + " bne- 1b\n" 367 + PPC_ACQUIRE_BARRIER 368 + "2:" 369 + : "=&r" (prev), "+m" (*p) 370 + : "r" (p), "r" (old), "r" (new) 371 + : "cc", "memory"); 372 + 373 + return prev; 374 + } 375 + #endif 281 376 282 377 static __always_inline unsigned long 283 378 __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
+11 -10
arch/powerpc/lib/sstep.c
··· 2284 2284 op->type = MKOP(STCX, 0, 4); 2285 2285 break; 2286 2286 2287 - #ifdef __powerpc64__ 2288 - case 84: /* ldarx */ 2289 - op->type = MKOP(LARX, 0, 8); 2290 - break; 2291 - 2292 - case 214: /* stdcx. */ 2293 - op->type = MKOP(STCX, 0, 8); 2294 - break; 2295 - 2287 + #ifdef CONFIG_PPC_HAS_LBARX_LHARX 2296 2288 case 52: /* lbarx */ 2297 2289 op->type = MKOP(LARX, 0, 1); 2298 2290 break; ··· 2299 2307 2300 2308 case 726: /* sthcx. */ 2301 2309 op->type = MKOP(STCX, 0, 2); 2310 + break; 2311 + #endif 2312 + #ifdef __powerpc64__ 2313 + case 84: /* ldarx */ 2314 + op->type = MKOP(LARX, 0, 8); 2315 + break; 2316 + 2317 + case 214: /* stdcx. */ 2318 + op->type = MKOP(STCX, 0, 8); 2302 2319 break; 2303 2320 2304 2321 case 276: /* lqarx */ ··· 3335 3334 err = 0; 3336 3335 val = 0; 3337 3336 switch (size) { 3338 - #ifdef __powerpc64__ 3337 + #ifdef CONFIG_PPC_HAS_LBARX_LHARX 3339 3338 case 1: 3340 3339 __get_user_asmx(val, ea, err, "lbarx"); 3341 3340 break;
+5
arch/powerpc/platforms/Kconfig.cputype
··· 135 135 depends on PPC_BOOK3S_64 && CPU_LITTLE_ENDIAN 136 136 select ARCH_HAS_FAST_MULTIPLIER 137 137 select PPC_64S_HASH_MMU 138 + select PPC_HAS_LBARX_LHARX 138 139 139 140 config POWERPC_CPU 140 141 bool "Generic 32 bits powerpc" ··· 161 160 depends on PPC_BOOK3S_64 162 161 select ARCH_HAS_FAST_MULTIPLIER 163 162 select PPC_64S_HASH_MMU 163 + select PPC_HAS_LBARX_LHARX 164 164 165 165 config POWER8_CPU 166 166 bool "POWER8" 167 167 depends on PPC_BOOK3S_64 168 168 select ARCH_HAS_FAST_MULTIPLIER 169 169 select PPC_64S_HASH_MMU 170 + select PPC_HAS_LBARX_LHARX 170 171 171 172 config POWER9_CPU 172 173 bool "POWER9" 173 174 depends on PPC_BOOK3S_64 174 175 select ARCH_HAS_FAST_MULTIPLIER 176 + select PPC_HAS_LBARX_LHARX 175 177 176 178 config POWER10_CPU 177 179 bool "POWER10" ··· 188 184 config E6500_CPU 189 185 bool "Freescale e6500" 190 186 depends on PPC64 && PPC_E500 187 + select PPC_HAS_LBARX_LHARX 191 188 192 189 config 405_CPU 193 190 bool "40x family"