| // 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 | |
| #define BUG_ON(x) assert(x) | |
| 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); | |
| } |