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