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