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