210 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| #define _GNU_SOURCE
 | |
| #include "main.h"
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <pthread.h>
 | |
| #include <malloc.h>
 | |
| #include <assert.h>
 | |
| #include <errno.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| #define SMP_CACHE_BYTES 64
 | |
| #define cache_line_size() SMP_CACHE_BYTES
 | |
| #define ____cacheline_aligned_in_smp __attribute__ ((aligned (SMP_CACHE_BYTES)))
 | |
| #define unlikely(x)    (__builtin_expect(!!(x), 0))
 | |
| #define likely(x)    (__builtin_expect(!!(x), 1))
 | |
| #define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a))
 | |
| #define SIZE_MAX        (~(size_t)0)
 | |
| #define KMALLOC_MAX_SIZE SIZE_MAX
 | |
| 
 | |
| typedef pthread_spinlock_t  spinlock_t;
 | |
| 
 | |
| typedef int gfp_t;
 | |
| #define __GFP_ZERO 0x1
 | |
| 
 | |
| static void *kmalloc(unsigned size, gfp_t gfp)
 | |
| {
 | |
| 	void *p = memalign(64, size);
 | |
| 	if (!p)
 | |
| 		return p;
 | |
| 
 | |
| 	if (gfp & __GFP_ZERO)
 | |
| 		memset(p, 0, size);
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| static inline void *kzalloc(unsigned size, gfp_t flags)
 | |
| {
 | |
| 	return kmalloc(size, flags | __GFP_ZERO);
 | |
| }
 | |
| 
 | |
| static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
 | |
| {
 | |
| 	if (size != 0 && n > SIZE_MAX / size)
 | |
| 		return NULL;
 | |
| 	return kmalloc(n * size, flags);
 | |
| }
 | |
| 
 | |
| static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
 | |
| {
 | |
| 	return kmalloc_array(n, size, flags | __GFP_ZERO);
 | |
| }
 | |
| 
 | |
| static void kfree(void *p)
 | |
| {
 | |
| 	if (p)
 | |
| 		free(p);
 | |
| }
 | |
| 
 | |
| #define kvmalloc_array kmalloc_array
 | |
| #define kvfree kfree
 | |
| 
 | |
| static void spin_lock_init(spinlock_t *lock)
 | |
| {
 | |
| 	int r = pthread_spin_init(lock, 0);
 | |
| 	assert(!r);
 | |
| }
 | |
| 
 | |
| static void spin_lock(spinlock_t *lock)
 | |
| {
 | |
| 	int ret = pthread_spin_lock(lock);
 | |
| 	assert(!ret);
 | |
| }
 | |
| 
 | |
| static void spin_unlock(spinlock_t *lock)
 | |
| {
 | |
| 	int ret = pthread_spin_unlock(lock);
 | |
| 	assert(!ret);
 | |
| }
 | |
| 
 | |
| static void spin_lock_bh(spinlock_t *lock)
 | |
| {
 | |
| 	spin_lock(lock);
 | |
| }
 | |
| 
 | |
| static void spin_unlock_bh(spinlock_t *lock)
 | |
| {
 | |
| 	spin_unlock(lock);
 | |
| }
 | |
| 
 | |
| static void spin_lock_irq(spinlock_t *lock)
 | |
| {
 | |
| 	spin_lock(lock);
 | |
| }
 | |
| 
 | |
| static void spin_unlock_irq(spinlock_t *lock)
 | |
| {
 | |
| 	spin_unlock(lock);
 | |
| }
 | |
| 
 | |
| static void spin_lock_irqsave(spinlock_t *lock, unsigned long f)
 | |
| {
 | |
| 	spin_lock(lock);
 | |
| }
 | |
| 
 | |
| static void spin_unlock_irqrestore(spinlock_t *lock, unsigned long f)
 | |
| {
 | |
| 	spin_unlock(lock);
 | |
| }
 | |
| 
 | |
| #include "../../../include/linux/ptr_ring.h"
 | |
| 
 | |
| static unsigned long long headcnt, tailcnt;
 | |
| static struct ptr_ring array ____cacheline_aligned_in_smp;
 | |
| 
 | |
| /* implemented by ring */
 | |
| void alloc_ring(void)
 | |
| {
 | |
| 	int ret = ptr_ring_init(&array, ring_size, 0);
 | |
| 	assert(!ret);
 | |
| 	/* Hacky way to poke at ring internals. Useful for testing though. */
 | |
| 	if (param)
 | |
| 		array.batch = param;
 | |
| }
 | |
| 
 | |
| /* guest side */
 | |
| int add_inbuf(unsigned len, void *buf, void *datap)
 | |
| {
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = __ptr_ring_produce(&array, buf);
 | |
| 	if (ret >= 0) {
 | |
| 		ret = 0;
 | |
| 		headcnt++;
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ptr_ring API provides no way for producer to find out whether a given
 | |
|  * buffer was consumed.  Our tests merely require that a successful get_buf
 | |
|  * implies that add_inbuf succeed in the past, and that add_inbuf will succeed,
 | |
|  * fake it accordingly.
 | |
|  */
 | |
| void *get_buf(unsigned *lenp, void **bufp)
 | |
| {
 | |
| 	void *datap;
 | |
| 
 | |
| 	if (tailcnt == headcnt || __ptr_ring_full(&array))
 | |
| 		datap = NULL;
 | |
| 	else {
 | |
| 		datap = "Buffer\n";
 | |
| 		++tailcnt;
 | |
| 	}
 | |
| 
 | |
| 	return datap;
 | |
| }
 | |
| 
 | |
| bool used_empty()
 | |
| {
 | |
| 	return (tailcnt == headcnt || __ptr_ring_full(&array));
 | |
| }
 | |
| 
 | |
| void disable_call()
 | |
| {
 | |
| 	assert(0);
 | |
| }
 | |
| 
 | |
| bool enable_call()
 | |
| {
 | |
| 	assert(0);
 | |
| }
 | |
| 
 | |
| void kick_available(void)
 | |
| {
 | |
| 	assert(0);
 | |
| }
 | |
| 
 | |
| /* host side */
 | |
| void disable_kick()
 | |
| {
 | |
| 	assert(0);
 | |
| }
 | |
| 
 | |
| bool enable_kick()
 | |
| {
 | |
| 	assert(0);
 | |
| }
 | |
| 
 | |
| bool avail_empty()
 | |
| {
 | |
| 	return __ptr_ring_empty(&array);
 | |
| }
 | |
| 
 | |
| bool use_buf(unsigned *lenp, void **bufp)
 | |
| {
 | |
| 	void *ptr;
 | |
| 
 | |
| 	ptr = __ptr_ring_consume(&array);
 | |
| 
 | |
| 	return ptr;
 | |
| }
 | |
| 
 | |
| void call_used(void)
 | |
| {
 | |
| 	assert(0);
 | |
| }
 |