Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/*
  3 * Copyright (C) 2016 Red Hat, Inc.
  4 * Author: Michael S. Tsirkin <mst@redhat.com>
  5 *
  6 * Common macros and functions for ring benchmarking.
  7 */
  8#ifndef MAIN_H
  9#define MAIN_H
 10
 11#include <stdbool.h>
 12
 13extern int param;
 14
 15extern 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
 31#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
 41#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();
 71bool used_empty();
 72bool enable_call();
 73void kick_available();
 74/* host side */
 75void disable_kick();
 76bool avail_empty();
 77bool enable_kick();
 78bool use_buf(unsigned *, void **);
 79void call_used();
 80
 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")
 96#elif defined(__s390x__)
 97#define cpu_relax() barrier()
 98#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
113#if defined(__x86_64__) || defined(__i386__)
114#define smp_mb()     asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
115#else
116/*
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()
121#endif
122
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
137#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
194#endif