17a338472SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2481eaec3SMichael S. Tsirkin /*
3481eaec3SMichael S. Tsirkin * Copyright (C) 2016 Red Hat, Inc.
4481eaec3SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com>
5481eaec3SMichael S. Tsirkin *
6481eaec3SMichael S. Tsirkin * Common macros and functions for ring benchmarking.
7481eaec3SMichael S. Tsirkin */
8481eaec3SMichael S. Tsirkin #ifndef MAIN_H
9481eaec3SMichael S. Tsirkin #define MAIN_H
10481eaec3SMichael S. Tsirkin
11*57380fd1SRong Tao #include <assert.h>
12481eaec3SMichael S. Tsirkin #include <stdbool.h>
13481eaec3SMichael S. Tsirkin
14a4979505SMichael S. Tsirkin extern int param;
15a4979505SMichael S. Tsirkin
16481eaec3SMichael S. Tsirkin extern bool do_exit;
17481eaec3SMichael S. Tsirkin
18481eaec3SMichael S. Tsirkin #if defined(__x86_64__) || defined(__i386__)
19481eaec3SMichael S. Tsirkin #include "x86intrin.h"
20481eaec3SMichael S. Tsirkin
wait_cycles(unsigned long long cycles)21481eaec3SMichael S. Tsirkin static inline void wait_cycles(unsigned long long cycles)
22481eaec3SMichael S. Tsirkin {
23481eaec3SMichael S. Tsirkin unsigned long long t;
24481eaec3SMichael S. Tsirkin
25481eaec3SMichael S. Tsirkin t = __rdtsc();
26481eaec3SMichael S. Tsirkin while (__rdtsc() - t < cycles) {}
27481eaec3SMichael S. Tsirkin }
28481eaec3SMichael S. Tsirkin
29481eaec3SMichael S. Tsirkin #define VMEXIT_CYCLES 500
30481eaec3SMichael S. Tsirkin #define VMENTRY_CYCLES 500
31481eaec3SMichael S. Tsirkin
3247a4c49aSHalil Pasic #elif defined(__s390x__)
wait_cycles(unsigned long long cycles)3347a4c49aSHalil Pasic static inline void wait_cycles(unsigned long long cycles)
3447a4c49aSHalil Pasic {
3547a4c49aSHalil Pasic asm volatile("0: brctg %0,0b" : : "d" (cycles));
3647a4c49aSHalil Pasic }
3747a4c49aSHalil Pasic
3847a4c49aSHalil Pasic /* tweak me */
3947a4c49aSHalil Pasic #define VMEXIT_CYCLES 200
4047a4c49aSHalil Pasic #define VMENTRY_CYCLES 200
4147a4c49aSHalil Pasic
42481eaec3SMichael S. Tsirkin #else
wait_cycles(unsigned long long cycles)43481eaec3SMichael S. Tsirkin static inline void wait_cycles(unsigned long long cycles)
44481eaec3SMichael S. Tsirkin {
45481eaec3SMichael S. Tsirkin _Exit(5);
46481eaec3SMichael S. Tsirkin }
47481eaec3SMichael S. Tsirkin #define VMEXIT_CYCLES 0
48481eaec3SMichael S. Tsirkin #define VMENTRY_CYCLES 0
49481eaec3SMichael S. Tsirkin #endif
50481eaec3SMichael S. Tsirkin
vmexit(void)51481eaec3SMichael S. Tsirkin static inline void vmexit(void)
52481eaec3SMichael S. Tsirkin {
53481eaec3SMichael S. Tsirkin if (!do_exit)
54481eaec3SMichael S. Tsirkin return;
55481eaec3SMichael S. Tsirkin
56481eaec3SMichael S. Tsirkin wait_cycles(VMEXIT_CYCLES);
57481eaec3SMichael S. Tsirkin }
vmentry(void)58481eaec3SMichael S. Tsirkin static inline void vmentry(void)
59481eaec3SMichael S. Tsirkin {
60481eaec3SMichael S. Tsirkin if (!do_exit)
61481eaec3SMichael S. Tsirkin return;
62481eaec3SMichael S. Tsirkin
63481eaec3SMichael S. Tsirkin wait_cycles(VMENTRY_CYCLES);
64481eaec3SMichael S. Tsirkin }
65481eaec3SMichael S. Tsirkin
66481eaec3SMichael S. Tsirkin /* implemented by ring */
67481eaec3SMichael S. Tsirkin void alloc_ring(void);
68481eaec3SMichael S. Tsirkin /* guest side */
69481eaec3SMichael S. Tsirkin int add_inbuf(unsigned, void *, void *);
70481eaec3SMichael S. Tsirkin void *get_buf(unsigned *, void **);
71481eaec3SMichael S. Tsirkin void disable_call();
72d3c3589bSPaolo Bonzini bool used_empty();
73481eaec3SMichael S. Tsirkin bool enable_call();
74481eaec3SMichael S. Tsirkin void kick_available();
75481eaec3SMichael S. Tsirkin /* host side */
76481eaec3SMichael S. Tsirkin void disable_kick();
77d3c3589bSPaolo Bonzini bool avail_empty();
78481eaec3SMichael S. Tsirkin bool enable_kick();
79481eaec3SMichael S. Tsirkin bool use_buf(unsigned *, void **);
80481eaec3SMichael S. Tsirkin void call_used();
81481eaec3SMichael S. Tsirkin
82481eaec3SMichael S. Tsirkin /* implemented by main */
83481eaec3SMichael S. Tsirkin extern bool do_sleep;
84481eaec3SMichael S. Tsirkin void kick(void);
85481eaec3SMichael S. Tsirkin void wait_for_kick(void);
86481eaec3SMichael S. Tsirkin void call(void);
87481eaec3SMichael S. Tsirkin void wait_for_call(void);
88481eaec3SMichael S. Tsirkin
89481eaec3SMichael S. Tsirkin extern unsigned ring_size;
90481eaec3SMichael S. Tsirkin
91481eaec3SMichael S. Tsirkin /* Compiler barrier - similar to what Linux uses */
92481eaec3SMichael S. Tsirkin #define barrier() asm volatile("" ::: "memory")
93481eaec3SMichael S. Tsirkin
94481eaec3SMichael S. Tsirkin /* Is there a portable way to do this? */
95481eaec3SMichael S. Tsirkin #if defined(__x86_64__) || defined(__i386__)
96481eaec3SMichael S. Tsirkin #define cpu_relax() asm ("rep; nop" ::: "memory")
9747a4c49aSHalil Pasic #elif defined(__s390x__)
9847a4c49aSHalil Pasic #define cpu_relax() barrier()
99*57380fd1SRong Tao #elif defined(__aarch64__)
100*57380fd1SRong Tao #define cpu_relax() asm ("yield" ::: "memory")
101481eaec3SMichael S. Tsirkin #else
102481eaec3SMichael S. Tsirkin #define cpu_relax() assert(0)
103481eaec3SMichael S. Tsirkin #endif
104481eaec3SMichael S. Tsirkin
105481eaec3SMichael S. Tsirkin extern bool do_relax;
106481eaec3SMichael S. Tsirkin
busy_wait(void)107481eaec3SMichael S. Tsirkin static inline void busy_wait(void)
108481eaec3SMichael S. Tsirkin {
109481eaec3SMichael S. Tsirkin if (do_relax)
110481eaec3SMichael S. Tsirkin cpu_relax();
111481eaec3SMichael S. Tsirkin else
112481eaec3SMichael S. Tsirkin /* prevent compiler from removing busy loops */
113481eaec3SMichael S. Tsirkin barrier();
114481eaec3SMichael S. Tsirkin }
115481eaec3SMichael S. Tsirkin
116450cbdd0SMichael S. Tsirkin #if defined(__x86_64__) || defined(__i386__)
117491847f3SMichael S. Tsirkin #define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
118*57380fd1SRong Tao #elif defined(__aarch64__)
119*57380fd1SRong Tao #define smp_mb() asm volatile("dmb ish" ::: "memory")
120450cbdd0SMichael S. Tsirkin #else
121481eaec3SMichael S. Tsirkin /*
122481eaec3SMichael S. Tsirkin * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
123481eaec3SMichael S. Tsirkin * with other __ATOMIC_SEQ_CST calls.
124481eaec3SMichael S. Tsirkin */
125481eaec3SMichael S. Tsirkin #define smp_mb() __sync_synchronize()
126450cbdd0SMichael S. Tsirkin #endif
127481eaec3SMichael S. Tsirkin
128481eaec3SMichael S. Tsirkin /*
129481eaec3SMichael S. Tsirkin * This abuses the atomic builtins for thread fences, and
130481eaec3SMichael S. Tsirkin * adds a compiler barrier.
131481eaec3SMichael S. Tsirkin */
132481eaec3SMichael S. Tsirkin #define smp_release() do { \
133481eaec3SMichael S. Tsirkin barrier(); \
134481eaec3SMichael S. Tsirkin __atomic_thread_fence(__ATOMIC_RELEASE); \
135481eaec3SMichael S. Tsirkin } while (0)
136481eaec3SMichael S. Tsirkin
137481eaec3SMichael S. Tsirkin #define smp_acquire() do { \
138481eaec3SMichael S. Tsirkin __atomic_thread_fence(__ATOMIC_ACQUIRE); \
139481eaec3SMichael S. Tsirkin barrier(); \
140481eaec3SMichael S. Tsirkin } while (0)
141481eaec3SMichael S. Tsirkin
142b4eab7deSMichael S. Tsirkin #if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
143b4eab7deSMichael S. Tsirkin #define smp_wmb() barrier()
144*57380fd1SRong Tao #elif defined(__aarch64__)
145*57380fd1SRong Tao #define smp_wmb() asm volatile("dmb ishst" ::: "memory")
146b4eab7deSMichael S. Tsirkin #else
147b4eab7deSMichael S. Tsirkin #define smp_wmb() smp_release()
148b4eab7deSMichael S. Tsirkin #endif
149b4eab7deSMichael S. Tsirkin
150*57380fd1SRong Tao #ifndef __always_inline
151*57380fd1SRong Tao #define __always_inline inline __attribute__((always_inline))
152*57380fd1SRong Tao #endif
153*57380fd1SRong Tao
154b4eab7deSMichael S. Tsirkin static __always_inline
__read_once_size(const volatile void * p,void * res,int size)155b4eab7deSMichael S. Tsirkin void __read_once_size(const volatile void *p, void *res, int size)
156b4eab7deSMichael S. Tsirkin {
1578aeac42dSDavidlohr Bueso switch (size) {
1588aeac42dSDavidlohr Bueso case 1: *(unsigned char *)res = *(volatile unsigned char *)p; break;
1598aeac42dSDavidlohr Bueso case 2: *(unsigned short *)res = *(volatile unsigned short *)p; break;
1608aeac42dSDavidlohr Bueso case 4: *(unsigned int *)res = *(volatile unsigned int *)p; break;
1618aeac42dSDavidlohr Bueso case 8: *(unsigned long long *)res = *(volatile unsigned long long *)p; break;
1628aeac42dSDavidlohr Bueso default:
1638aeac42dSDavidlohr Bueso barrier();
1648aeac42dSDavidlohr Bueso __builtin_memcpy((void *)res, (const void *)p, size);
1658aeac42dSDavidlohr Bueso barrier();
1668aeac42dSDavidlohr Bueso }
167b4eab7deSMichael S. Tsirkin }
168b4eab7deSMichael S. Tsirkin
__write_once_size(volatile void * p,void * res,int size)169b4eab7deSMichael S. Tsirkin static __always_inline void __write_once_size(volatile void *p, void *res, int size)
170b4eab7deSMichael S. Tsirkin {
171b4eab7deSMichael S. Tsirkin switch (size) {
172b4eab7deSMichael S. Tsirkin case 1: *(volatile unsigned char *)p = *(unsigned char *)res; break;
173b4eab7deSMichael S. Tsirkin case 2: *(volatile unsigned short *)p = *(unsigned short *)res; break;
174b4eab7deSMichael S. Tsirkin case 4: *(volatile unsigned int *)p = *(unsigned int *)res; break;
175b4eab7deSMichael S. Tsirkin case 8: *(volatile unsigned long long *)p = *(unsigned long long *)res; break;
176b4eab7deSMichael S. Tsirkin default:
177b4eab7deSMichael S. Tsirkin barrier();
178b4eab7deSMichael S. Tsirkin __builtin_memcpy((void *)p, (const void *)res, size);
179b4eab7deSMichael S. Tsirkin barrier();
180b4eab7deSMichael S. Tsirkin }
181b4eab7deSMichael S. Tsirkin }
182b4eab7deSMichael S. Tsirkin
18381931012SDavidlohr Bueso #ifdef __alpha__
184b4eab7deSMichael S. Tsirkin #define READ_ONCE(x) \
185b4eab7deSMichael S. Tsirkin ({ \
186b4eab7deSMichael S. Tsirkin union { typeof(x) __val; char __c[1]; } __u; \
187b4eab7deSMichael S. Tsirkin __read_once_size(&(x), __u.__c, sizeof(x)); \
18881931012SDavidlohr Bueso smp_mb(); /* Enforce dependency ordering from x */ \
189b4eab7deSMichael S. Tsirkin __u.__val; \
190b4eab7deSMichael S. Tsirkin })
19181931012SDavidlohr Bueso #else
19281931012SDavidlohr Bueso #define READ_ONCE(x) \
19381931012SDavidlohr Bueso ({ \
19481931012SDavidlohr Bueso union { typeof(x) __val; char __c[1]; } __u; \
19581931012SDavidlohr Bueso __read_once_size(&(x), __u.__c, sizeof(x)); \
19681931012SDavidlohr Bueso __u.__val; \
19781931012SDavidlohr Bueso })
19881931012SDavidlohr Bueso #endif
199b4eab7deSMichael S. Tsirkin
200b4eab7deSMichael S. Tsirkin #define WRITE_ONCE(x, val) \
201b4eab7deSMichael S. Tsirkin ({ \
202b4eab7deSMichael S. Tsirkin union { typeof(x) __val; char __c[1]; } __u = \
203b4eab7deSMichael S. Tsirkin { .__val = (typeof(x)) (val) }; \
204b4eab7deSMichael S. Tsirkin __write_once_size(&(x), __u.__c, sizeof(x)); \
205b4eab7deSMichael S. Tsirkin __u.__val; \
206b4eab7deSMichael S. Tsirkin })
207b4eab7deSMichael S. Tsirkin
208481eaec3SMichael S. Tsirkin #endif
209