1
0

main.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2016 Red Hat, Inc.
  4. * Author: Michael S. Tsirkin <mst@redhat.com>
  5. *
  6. * Common macros and functions for ring benchmarking.
  7. */
  8. #ifndef MAIN_H
  9. #define MAIN_H
  10. #include <assert.h>
  11. #include <stdbool.h>
  12. extern int param;
  13. extern bool do_exit;
  14. #if defined(__x86_64__) || defined(__i386__)
  15. #include "x86intrin.h"
  16. static inline void wait_cycles(unsigned long long cycles)
  17. {
  18. unsigned long long t;
  19. t = __rdtsc();
  20. while (__rdtsc() - t < cycles) {}
  21. }
  22. #define VMEXIT_CYCLES 500
  23. #define VMENTRY_CYCLES 500
  24. #elif defined(__s390x__)
  25. static inline void wait_cycles(unsigned long long cycles)
  26. {
  27. asm volatile("0: brctg %0,0b" : : "d" (cycles));
  28. }
  29. /* tweak me */
  30. #define VMEXIT_CYCLES 200
  31. #define VMENTRY_CYCLES 200
  32. #else
  33. static inline void wait_cycles(unsigned long long cycles)
  34. {
  35. _Exit(5);
  36. }
  37. #define VMEXIT_CYCLES 0
  38. #define VMENTRY_CYCLES 0
  39. #endif
  40. static inline void vmexit(void)
  41. {
  42. if (!do_exit)
  43. return;
  44. wait_cycles(VMEXIT_CYCLES);
  45. }
  46. static inline void vmentry(void)
  47. {
  48. if (!do_exit)
  49. return;
  50. wait_cycles(VMENTRY_CYCLES);
  51. }
  52. /* implemented by ring */
  53. void alloc_ring(void);
  54. /* guest side */
  55. int add_inbuf(unsigned, void *, void *);
  56. void *get_buf(unsigned *, void **);
  57. void disable_call();
  58. bool used_empty();
  59. bool enable_call();
  60. void kick_available();
  61. /* host side */
  62. void disable_kick();
  63. bool avail_empty();
  64. bool enable_kick();
  65. bool use_buf(unsigned *, void **);
  66. void call_used();
  67. /* implemented by main */
  68. extern bool do_sleep;
  69. void kick(void);
  70. void wait_for_kick(void);
  71. void call(void);
  72. void wait_for_call(void);
  73. extern unsigned ring_size;
  74. /* Compiler barrier - similar to what Linux uses */
  75. #define barrier() asm volatile("" ::: "memory")
  76. /* Is there a portable way to do this? */
  77. #if defined(__x86_64__) || defined(__i386__)
  78. #define cpu_relax() asm ("rep; nop" ::: "memory")
  79. #elif defined(__s390x__)
  80. #define cpu_relax() barrier()
  81. #elif defined(__aarch64__)
  82. #define cpu_relax() asm ("yield" ::: "memory")
  83. #else
  84. #define cpu_relax() assert(0)
  85. #endif
  86. extern bool do_relax;
  87. static inline void busy_wait(void)
  88. {
  89. if (do_relax)
  90. cpu_relax();
  91. else
  92. /* prevent compiler from removing busy loops */
  93. barrier();
  94. }
  95. #if defined(__x86_64__) || defined(__i386__)
  96. #define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
  97. #elif defined(__aarch64__)
  98. #define smp_mb() asm volatile("dmb ish" ::: "memory")
  99. #else
  100. /*
  101. * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
  102. * with other __ATOMIC_SEQ_CST calls.
  103. */
  104. #define smp_mb() __sync_synchronize()
  105. #endif
  106. /*
  107. * This abuses the atomic builtins for thread fences, and
  108. * adds a compiler barrier.
  109. */
  110. #define smp_release() do { \
  111. barrier(); \
  112. __atomic_thread_fence(__ATOMIC_RELEASE); \
  113. } while (0)
  114. #define smp_acquire() do { \
  115. __atomic_thread_fence(__ATOMIC_ACQUIRE); \
  116. barrier(); \
  117. } while (0)
  118. #if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
  119. #define smp_wmb() barrier()
  120. #elif defined(__aarch64__)
  121. #define smp_wmb() asm volatile("dmb ishst" ::: "memory")
  122. #else
  123. #define smp_wmb() smp_release()
  124. #endif
  125. #ifndef __always_inline
  126. #define __always_inline inline __attribute__((always_inline))
  127. #endif
  128. static __always_inline
  129. void __read_once_size(const volatile void *p, void *res, int size)
  130. {
  131. switch (size) {
  132. case 1: *(unsigned char *)res = *(volatile unsigned char *)p; break;
  133. case 2: *(unsigned short *)res = *(volatile unsigned short *)p; break;
  134. case 4: *(unsigned int *)res = *(volatile unsigned int *)p; break;
  135. case 8: *(unsigned long long *)res = *(volatile unsigned long long *)p; break;
  136. default:
  137. barrier();
  138. __builtin_memcpy((void *)res, (const void *)p, size);
  139. barrier();
  140. }
  141. }
  142. static __always_inline void __write_once_size(volatile void *p, void *res, int size)
  143. {
  144. switch (size) {
  145. case 1: *(volatile unsigned char *)p = *(unsigned char *)res; break;
  146. case 2: *(volatile unsigned short *)p = *(unsigned short *)res; break;
  147. case 4: *(volatile unsigned int *)p = *(unsigned int *)res; break;
  148. case 8: *(volatile unsigned long long *)p = *(unsigned long long *)res; break;
  149. default:
  150. barrier();
  151. __builtin_memcpy((void *)p, (const void *)res, size);
  152. barrier();
  153. }
  154. }
  155. #ifdef __alpha__
  156. #define READ_ONCE(x) \
  157. ({ \
  158. union { typeof(x) __val; char __c[1]; } __u; \
  159. __read_once_size(&(x), __u.__c, sizeof(x)); \
  160. smp_mb(); /* Enforce dependency ordering from x */ \
  161. __u.__val; \
  162. })
  163. #else
  164. #define READ_ONCE(x) \
  165. ({ \
  166. union { typeof(x) __val; char __c[1]; } __u; \
  167. __read_once_size(&(x), __u.__c, sizeof(x)); \
  168. __u.__val; \
  169. })
  170. #endif
  171. #define WRITE_ONCE(x, val) \
  172. ({ \
  173. union { typeof(x) __val; char __c[1]; } __u = \
  174. { .__val = (typeof(x)) (val) }; \
  175. __write_once_size(&(x), __u.__c, sizeof(x)); \
  176. __u.__val; \
  177. })
  178. #endif