18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#define _GNU_SOURCE
38c2ecf20Sopenharmony_ci#include "main.h"
48c2ecf20Sopenharmony_ci#include <stdlib.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <string.h>
78c2ecf20Sopenharmony_ci#include <pthread.h>
88c2ecf20Sopenharmony_ci#include <malloc.h>
98c2ecf20Sopenharmony_ci#include <assert.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <limits.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define SMP_CACHE_BYTES 64
148c2ecf20Sopenharmony_ci#define cache_line_size() SMP_CACHE_BYTES
158c2ecf20Sopenharmony_ci#define ____cacheline_aligned_in_smp __attribute__ ((aligned (SMP_CACHE_BYTES)))
168c2ecf20Sopenharmony_ci#define unlikely(x)    (__builtin_expect(!!(x), 0))
178c2ecf20Sopenharmony_ci#define likely(x)    (__builtin_expect(!!(x), 1))
188c2ecf20Sopenharmony_ci#define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a))
198c2ecf20Sopenharmony_ci#define SIZE_MAX        (~(size_t)0)
208c2ecf20Sopenharmony_ci#define KMALLOC_MAX_SIZE SIZE_MAX
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_citypedef pthread_spinlock_t  spinlock_t;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_citypedef int gfp_t;
258c2ecf20Sopenharmony_ci#define __GFP_ZERO 0x1
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic void *kmalloc(unsigned size, gfp_t gfp)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	void *p = memalign(64, size);
308c2ecf20Sopenharmony_ci	if (!p)
318c2ecf20Sopenharmony_ci		return p;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (gfp & __GFP_ZERO)
348c2ecf20Sopenharmony_ci		memset(p, 0, size);
358c2ecf20Sopenharmony_ci	return p;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline void *kzalloc(unsigned size, gfp_t flags)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return kmalloc(size, flags | __GFP_ZERO);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	if (size != 0 && n > SIZE_MAX / size)
468c2ecf20Sopenharmony_ci		return NULL;
478c2ecf20Sopenharmony_ci	return kmalloc(n * size, flags);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void *kcalloc(size_t n, size_t size, gfp_t flags)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	return kmalloc_array(n, size, flags | __GFP_ZERO);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void kfree(void *p)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	if (p)
588c2ecf20Sopenharmony_ci		free(p);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define kvmalloc_array kmalloc_array
628c2ecf20Sopenharmony_ci#define kvfree kfree
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void spin_lock_init(spinlock_t *lock)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	int r = pthread_spin_init(lock, 0);
678c2ecf20Sopenharmony_ci	assert(!r);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void spin_lock(spinlock_t *lock)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	int ret = pthread_spin_lock(lock);
738c2ecf20Sopenharmony_ci	assert(!ret);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic void spin_unlock(spinlock_t *lock)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	int ret = pthread_spin_unlock(lock);
798c2ecf20Sopenharmony_ci	assert(!ret);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic void spin_lock_bh(spinlock_t *lock)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	spin_lock(lock);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void spin_unlock_bh(spinlock_t *lock)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	spin_unlock(lock);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void spin_lock_irq(spinlock_t *lock)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	spin_lock(lock);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic void spin_unlock_irq(spinlock_t *lock)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	spin_unlock(lock);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void spin_lock_irqsave(spinlock_t *lock, unsigned long f)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	spin_lock(lock);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void spin_unlock_irqrestore(spinlock_t *lock, unsigned long f)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	spin_unlock(lock);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#include "../../../include/linux/ptr_ring.h"
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic unsigned long long headcnt, tailcnt;
1158c2ecf20Sopenharmony_cistatic struct ptr_ring array ____cacheline_aligned_in_smp;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* implemented by ring */
1188c2ecf20Sopenharmony_civoid alloc_ring(void)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int ret = ptr_ring_init(&array, ring_size, 0);
1218c2ecf20Sopenharmony_ci	assert(!ret);
1228c2ecf20Sopenharmony_ci	/* Hacky way to poke at ring internals. Useful for testing though. */
1238c2ecf20Sopenharmony_ci	if (param)
1248c2ecf20Sopenharmony_ci		array.batch = param;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/* guest side */
1288c2ecf20Sopenharmony_ciint add_inbuf(unsigned len, void *buf, void *datap)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	int ret;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ret = __ptr_ring_produce(&array, buf);
1338c2ecf20Sopenharmony_ci	if (ret >= 0) {
1348c2ecf20Sopenharmony_ci		ret = 0;
1358c2ecf20Sopenharmony_ci		headcnt++;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return ret;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/*
1428c2ecf20Sopenharmony_ci * ptr_ring API provides no way for producer to find out whether a given
1438c2ecf20Sopenharmony_ci * buffer was consumed.  Our tests merely require that a successful get_buf
1448c2ecf20Sopenharmony_ci * implies that add_inbuf succeed in the past, and that add_inbuf will succeed,
1458c2ecf20Sopenharmony_ci * fake it accordingly.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_civoid *get_buf(unsigned *lenp, void **bufp)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	void *datap;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (tailcnt == headcnt || __ptr_ring_full(&array))
1528c2ecf20Sopenharmony_ci		datap = NULL;
1538c2ecf20Sopenharmony_ci	else {
1548c2ecf20Sopenharmony_ci		datap = "Buffer\n";
1558c2ecf20Sopenharmony_ci		++tailcnt;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return datap;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cibool used_empty()
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return (tailcnt == headcnt || __ptr_ring_full(&array));
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_civoid disable_call()
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	assert(0);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cibool enable_call()
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	assert(0);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_civoid kick_available(void)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	assert(0);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/* host side */
1828c2ecf20Sopenharmony_civoid disable_kick()
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	assert(0);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cibool enable_kick()
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	assert(0);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cibool avail_empty()
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	return __ptr_ring_empty(&array);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cibool use_buf(unsigned *lenp, void **bufp)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	void *ptr;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	ptr = __ptr_ring_consume(&array);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return ptr;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_civoid call_used(void)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	assert(0);
2098c2ecf20Sopenharmony_ci}
210