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 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__) 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 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 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 } 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 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 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 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