1f08c3bdfSopenharmony_ci/* Unit tester for ring buffer code in mce.c */
2f08c3bdfSopenharmony_ci#define DEFINE_PER_CPU(a,b) a b
3f08c3bdfSopenharmony_ci#define __get_cpu_var(x) x
4f08c3bdfSopenharmony_ci#define barrier() asm volatile("" ::: "memory")
5f08c3bdfSopenharmony_ci#define rmb() barrier()
6f08c3bdfSopenharmony_ci#define wmb() barrier()
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*
9f08c3bdfSopenharmony_ci * Simple lockless ring to communicate PFNs from the exception handler with the
10f08c3bdfSopenharmony_ci * process context work function. This is vastly simplified because there's
11f08c3bdfSopenharmony_ci * only a single reader and a single writer.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci#define MCE_RING_SIZE 16	/* we use one entry less */
14f08c3bdfSopenharmony_ci
15f08c3bdfSopenharmony_cistruct mce_ring {
16f08c3bdfSopenharmony_ci	unsigned short start;
17f08c3bdfSopenharmony_ci	unsigned short end;
18f08c3bdfSopenharmony_ci	unsigned long ring[MCE_RING_SIZE];
19f08c3bdfSopenharmony_ci};
20f08c3bdfSopenharmony_cistatic DEFINE_PER_CPU(struct mce_ring, mce_ring);
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_cistatic int mce_ring_empty(void)
23f08c3bdfSopenharmony_ci{
24f08c3bdfSopenharmony_ci	struct mce_ring *r = &__get_cpu_var(mce_ring);
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci	return r->start == r->end;
27f08c3bdfSopenharmony_ci}
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic int mce_ring_get(unsigned long *pfn)
30f08c3bdfSopenharmony_ci{
31f08c3bdfSopenharmony_ci	struct mce_ring *r = &__get_cpu_var(mce_ring);
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci	if (r->start == r->end)
34f08c3bdfSopenharmony_ci		return 0;
35f08c3bdfSopenharmony_ci	*pfn = r->ring[r->start];
36f08c3bdfSopenharmony_ci	r->start = (r->start + 1) % MCE_RING_SIZE;
37f08c3bdfSopenharmony_ci	return 1;
38f08c3bdfSopenharmony_ci}
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic int mce_ring_add(unsigned long pfn)
41f08c3bdfSopenharmony_ci{
42f08c3bdfSopenharmony_ci	struct mce_ring *r = &__get_cpu_var(mce_ring);
43f08c3bdfSopenharmony_ci	unsigned next;
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	next = (r->end + 1) % MCE_RING_SIZE;
46f08c3bdfSopenharmony_ci	if (next == r->start)
47f08c3bdfSopenharmony_ci		return -1;
48f08c3bdfSopenharmony_ci	r->ring[r->end] = pfn;
49f08c3bdfSopenharmony_ci	wmb();
50f08c3bdfSopenharmony_ci	r->end = next;
51f08c3bdfSopenharmony_ci	return 0;
52f08c3bdfSopenharmony_ci}
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci#include <stdio.h>
55f08c3bdfSopenharmony_ci#include <assert.h>
56f08c3bdfSopenharmony_ci#include <pthread.h>
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_civoid *thread(void *arg)
59f08c3bdfSopenharmony_ci{
60f08c3bdfSopenharmony_ci	long i = 0;
61f08c3bdfSopenharmony_ci	for (;;) {
62f08c3bdfSopenharmony_ci		if (mce_ring_add(i) >= 0)
63f08c3bdfSopenharmony_ci			i++;
64f08c3bdfSopenharmony_ci	}
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ciint main(void)
68f08c3bdfSopenharmony_ci{
69f08c3bdfSopenharmony_ci	long k;
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	pthread_t thr;
72f08c3bdfSopenharmony_ci	pthread_create(&thr, NULL, thread, NULL);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	k = 0;
75f08c3bdfSopenharmony_ci	for (;;) {
76f08c3bdfSopenharmony_ci		while (!mce_ring_empty()) {
77f08c3bdfSopenharmony_ci			unsigned long pfn;
78f08c3bdfSopenharmony_ci			int r = mce_ring_get(&pfn);
79f08c3bdfSopenharmony_ci			assert(r != 0);
80f08c3bdfSopenharmony_ci			if (pfn != k)
81f08c3bdfSopenharmony_ci				printf("got %lu expected %lu delta %ld\n", pfn, k, k-pfn);
82f08c3bdfSopenharmony_ci			k++;
83f08c3bdfSopenharmony_ci		}
84f08c3bdfSopenharmony_ci	}
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	return 0;
87f08c3bdfSopenharmony_ci}
88