Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _SPARC64_BACKOFF_H
0003 #define _SPARC64_BACKOFF_H
0004 
0005 /* The macros in this file implement an exponential backoff facility
0006  * for atomic operations.
0007  *
0008  * When multiple threads compete on an atomic operation, it is
0009  * possible for one thread to be continually denied a successful
0010  * completion of the compare-and-swap instruction.  Heavily
0011  * threaded cpu implementations like Niagara can compound this
0012  * problem even further.
0013  *
0014  * When an atomic operation fails and needs to be retried, we spin a
0015  * certain number of times.  At each subsequent failure of the same
0016  * operation we double the spin count, realizing an exponential
0017  * backoff.
0018  *
0019  * When we spin, we try to use an operation that will cause the
0020  * current cpu strand to block, and therefore make the core fully
0021  * available to any other runnable strands.  There are two
0022  * options, based upon cpu capabilities.
0023  *
0024  * On all cpus prior to SPARC-T4 we do three dummy reads of the
0025  * condition code register.  Each read blocks the strand for something
0026  * between 40 and 50 cpu cycles.
0027  *
0028  * For SPARC-T4 and later we have a special "pause" instruction
0029  * available.  This is implemented using writes to register %asr27.
0030  * The cpu will block the number of cycles written into the register,
0031  * unless a disrupting trap happens first.  SPARC-T4 specifically
0032  * implements pause with a granularity of 8 cycles.  Each strand has
0033  * an internal pause counter which decrements every 8 cycles.  So the
0034  * chip shifts the %asr27 value down by 3 bits, and writes the result
0035  * into the pause counter.  If a value smaller than 8 is written, the
0036  * chip blocks for 1 cycle.
0037  *
0038  * To achieve the same amount of backoff as the three %ccr reads give
0039  * on earlier chips, we shift the backoff value up by 7 bits.  (Three
0040  * %ccr reads block for about 128 cycles, 1 << 7 == 128) We write the
0041  * whole amount we want to block into the pause register, rather than
0042  * loop writing 128 each time.
0043  */
0044 
0045 #define BACKOFF_LIMIT   (4 * 1024)
0046 
0047 #ifdef CONFIG_SMP
0048 
0049 #define BACKOFF_SETUP(reg)  \
0050     mov 1, reg
0051 
0052 #define BACKOFF_LABEL(spin_label, continue_label) \
0053     spin_label
0054 
0055 #define BACKOFF_SPIN(reg, tmp, label)       \
0056     mov     reg, tmp;       \
0057 88: rd      %ccr, %g0;      \
0058     rd      %ccr, %g0;      \
0059     rd      %ccr, %g0;      \
0060     .section    .pause_3insn_patch,"ax";\
0061     .word       88b;            \
0062     sllx        tmp, 7, tmp;        \
0063     wr      tmp, 0, %asr27;     \
0064     clr     tmp;            \
0065     .previous;              \
0066     brnz,pt     tmp, 88b;       \
0067      sub        tmp, 1, tmp;        \
0068     set     BACKOFF_LIMIT, tmp; \
0069     cmp     reg, tmp;       \
0070     bg,pn       %xcc, label;        \
0071      nop;                   \
0072     ba,pt       %xcc, label;        \
0073      sllx       reg, 1, reg;
0074 
0075 #else
0076 
0077 #define BACKOFF_SETUP(reg)
0078 
0079 #define BACKOFF_LABEL(spin_label, continue_label) \
0080     continue_label
0081 
0082 #define BACKOFF_SPIN(reg, tmp, label)
0083 
0084 #endif
0085 
0086 #endif /* _SPARC64_BACKOFF_H */