18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Red Hat, Inc. 48c2ecf20Sopenharmony_ci * Author: Michael S. Tsirkin <mst@redhat.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Common macros and functions for ring benchmarking. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef MAIN_H 98c2ecf20Sopenharmony_ci#define MAIN_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <stdbool.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciextern int param; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciextern bool do_exit; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#if defined(__x86_64__) || defined(__i386__) 188c2ecf20Sopenharmony_ci#include "x86intrin.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline void wait_cycles(unsigned long long cycles) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci unsigned long long t; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci t = __rdtsc(); 258c2ecf20Sopenharmony_ci while (__rdtsc() - t < cycles) {} 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define VMEXIT_CYCLES 500 298c2ecf20Sopenharmony_ci#define VMENTRY_CYCLES 500 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#elif defined(__s390x__) 328c2ecf20Sopenharmony_cistatic inline void wait_cycles(unsigned long long cycles) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci asm volatile("0: brctg %0,0b" : : "d" (cycles)); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* tweak me */ 388c2ecf20Sopenharmony_ci#define VMEXIT_CYCLES 200 398c2ecf20Sopenharmony_ci#define VMENTRY_CYCLES 200 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#else 428c2ecf20Sopenharmony_cistatic inline void wait_cycles(unsigned long long cycles) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci _Exit(5); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci#define VMEXIT_CYCLES 0 478c2ecf20Sopenharmony_ci#define VMENTRY_CYCLES 0 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline void vmexit(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci if (!do_exit) 538c2ecf20Sopenharmony_ci return; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci wait_cycles(VMEXIT_CYCLES); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_cistatic inline void vmentry(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci if (!do_exit) 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci wait_cycles(VMENTRY_CYCLES); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* implemented by ring */ 668c2ecf20Sopenharmony_civoid alloc_ring(void); 678c2ecf20Sopenharmony_ci/* guest side */ 688c2ecf20Sopenharmony_ciint add_inbuf(unsigned, void *, void *); 698c2ecf20Sopenharmony_civoid *get_buf(unsigned *, void **); 708c2ecf20Sopenharmony_civoid disable_call(); 718c2ecf20Sopenharmony_cibool used_empty(); 728c2ecf20Sopenharmony_cibool enable_call(); 738c2ecf20Sopenharmony_civoid kick_available(); 748c2ecf20Sopenharmony_ci/* host side */ 758c2ecf20Sopenharmony_civoid disable_kick(); 768c2ecf20Sopenharmony_cibool avail_empty(); 778c2ecf20Sopenharmony_cibool enable_kick(); 788c2ecf20Sopenharmony_cibool use_buf(unsigned *, void **); 798c2ecf20Sopenharmony_civoid call_used(); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* implemented by main */ 828c2ecf20Sopenharmony_ciextern bool do_sleep; 838c2ecf20Sopenharmony_civoid kick(void); 848c2ecf20Sopenharmony_civoid wait_for_kick(void); 858c2ecf20Sopenharmony_civoid call(void); 868c2ecf20Sopenharmony_civoid wait_for_call(void); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciextern unsigned ring_size; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Compiler barrier - similar to what Linux uses */ 918c2ecf20Sopenharmony_ci#define barrier() asm volatile("" ::: "memory") 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Is there a portable way to do this? */ 948c2ecf20Sopenharmony_ci#if defined(__x86_64__) || defined(__i386__) 958c2ecf20Sopenharmony_ci#define cpu_relax() asm ("rep; nop" ::: "memory") 968c2ecf20Sopenharmony_ci#elif defined(__s390x__) 978c2ecf20Sopenharmony_ci#define cpu_relax() barrier() 988c2ecf20Sopenharmony_ci#else 998c2ecf20Sopenharmony_ci#define cpu_relax() assert(0) 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciextern bool do_relax; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline void busy_wait(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci if (do_relax) 1078c2ecf20Sopenharmony_ci cpu_relax(); 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci /* prevent compiler from removing busy loops */ 1108c2ecf20Sopenharmony_ci barrier(); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#if defined(__x86_64__) || defined(__i386__) 1148c2ecf20Sopenharmony_ci#define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc") 1158c2ecf20Sopenharmony_ci#else 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized 1188c2ecf20Sopenharmony_ci * with other __ATOMIC_SEQ_CST calls. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci#define smp_mb() __sync_synchronize() 1218c2ecf20Sopenharmony_ci#endif 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * This abuses the atomic builtins for thread fences, and 1258c2ecf20Sopenharmony_ci * adds a compiler barrier. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci#define smp_release() do { \ 1288c2ecf20Sopenharmony_ci barrier(); \ 1298c2ecf20Sopenharmony_ci __atomic_thread_fence(__ATOMIC_RELEASE); \ 1308c2ecf20Sopenharmony_ci} while (0) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define smp_acquire() do { \ 1338c2ecf20Sopenharmony_ci __atomic_thread_fence(__ATOMIC_ACQUIRE); \ 1348c2ecf20Sopenharmony_ci barrier(); \ 1358c2ecf20Sopenharmony_ci} while (0) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__) 1388c2ecf20Sopenharmony_ci#define smp_wmb() barrier() 1398c2ecf20Sopenharmony_ci#else 1408c2ecf20Sopenharmony_ci#define smp_wmb() smp_release() 1418c2ecf20Sopenharmony_ci#endif 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#ifdef __alpha__ 1448c2ecf20Sopenharmony_ci#define smp_read_barrier_depends() smp_acquire() 1458c2ecf20Sopenharmony_ci#else 1468c2ecf20Sopenharmony_ci#define smp_read_barrier_depends() do {} while(0) 1478c2ecf20Sopenharmony_ci#endif 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic __always_inline 1508c2ecf20Sopenharmony_civoid __read_once_size(const volatile void *p, void *res, int size) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci switch (size) { \ 1538c2ecf20Sopenharmony_ci case 1: *(unsigned char *)res = *(volatile unsigned char *)p; break; \ 1548c2ecf20Sopenharmony_ci case 2: *(unsigned short *)res = *(volatile unsigned short *)p; break; \ 1558c2ecf20Sopenharmony_ci case 4: *(unsigned int *)res = *(volatile unsigned int *)p; break; \ 1568c2ecf20Sopenharmony_ci case 8: *(unsigned long long *)res = *(volatile unsigned long long *)p; break; \ 1578c2ecf20Sopenharmony_ci default: \ 1588c2ecf20Sopenharmony_ci barrier(); \ 1598c2ecf20Sopenharmony_ci __builtin_memcpy((void *)res, (const void *)p, size); \ 1608c2ecf20Sopenharmony_ci barrier(); \ 1618c2ecf20Sopenharmony_ci } \ 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic __always_inline void __write_once_size(volatile void *p, void *res, int size) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci switch (size) { 1678c2ecf20Sopenharmony_ci case 1: *(volatile unsigned char *)p = *(unsigned char *)res; break; 1688c2ecf20Sopenharmony_ci case 2: *(volatile unsigned short *)p = *(unsigned short *)res; break; 1698c2ecf20Sopenharmony_ci case 4: *(volatile unsigned int *)p = *(unsigned int *)res; break; 1708c2ecf20Sopenharmony_ci case 8: *(volatile unsigned long long *)p = *(unsigned long long *)res; break; 1718c2ecf20Sopenharmony_ci default: 1728c2ecf20Sopenharmony_ci barrier(); 1738c2ecf20Sopenharmony_ci __builtin_memcpy((void *)p, (const void *)res, size); 1748c2ecf20Sopenharmony_ci barrier(); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define READ_ONCE(x) \ 1798c2ecf20Sopenharmony_ci({ \ 1808c2ecf20Sopenharmony_ci union { typeof(x) __val; char __c[1]; } __u; \ 1818c2ecf20Sopenharmony_ci __read_once_size(&(x), __u.__c, sizeof(x)); \ 1828c2ecf20Sopenharmony_ci smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \ 1838c2ecf20Sopenharmony_ci __u.__val; \ 1848c2ecf20Sopenharmony_ci}) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define WRITE_ONCE(x, val) \ 1878c2ecf20Sopenharmony_ci({ \ 1888c2ecf20Sopenharmony_ci union { typeof(x) __val; char __c[1]; } __u = \ 1898c2ecf20Sopenharmony_ci { .__val = (typeof(x)) (val) }; \ 1908c2ecf20Sopenharmony_ci __write_once_size(&(x), __u.__c, sizeof(x)); \ 1918c2ecf20Sopenharmony_ci __u.__val; \ 1928c2ecf20Sopenharmony_ci}) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#endif 195