#ifndef _KERNEL_H
#define _KERNEL_H

#ifndef __LITTLE_ENDIAN
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __LITTLE_ENDIAN
#else
#define __BIG_ENDIAN
#endif
#endif

#define __aligned(x)	__attribute__((aligned(x)))
#ifndef __always_inline
#define __always_inline	inline __attribute__((always_inline))
#endif
#define barrier()	asm volatile("" ::: "memory")
#define __pure		__attribute__((pure))

#define __branch_check__(x, expect, is_constant) ({			\
			int ______r;					\
			______r = __builtin_expect(!!(x), expect);	\
			______r;					\
		})
#define __force
#define likely(x)	(__branch_check__(x, 1, __builtin_constant_p(x)))
#define prefetchw(p)	(__builtin_prefetch((p), 1))
#define unreachable()	(__builtin_unreachable())

#define EXPORT_SYMBOL(n)

typedef	int		bool;
#define true		(1)
#define false		(0)

#define BUILD_BUG_ON(c)	_Static_assert(!(c),"BUILD_BUG_ON")

typedef unsigned char		u8;
typedef unsigned short		u16;
typedef unsigned int		u32;
typedef unsigned long long	u64;

typedef struct {
	int counter;
} atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define __READ_ONCE_SIZE						\
({									\
	switch (size) {							\
	case 1: *(u8 *)res = *(volatile u8 *)p; break;		\
	case 2: *(u16 *)res = *(volatile u16 *)p; break;		\
	case 4: *(u32 *)res = *(volatile u32 *)p; break;		\
	case 8: *(u64 *)res = *(volatile u64 *)p; break;		\
	default:							\
		barrier();						\
		__builtin_memcpy((void *)res, (const void *)p, size);	\
		barrier();						\
	}								\
})

static __always_inline
void __read_once_size(const volatile void *p, void *res, int size)
{
	__READ_ONCE_SIZE;
}

#define __READ_ONCE(x)							\
({									\
	union { typeof(x) __val; char __c[1]; } __u;			\
	__read_once_size(&(x), __u.__c, sizeof(x));			\
	__u.__val;							\
})

#define READ_ONCE(x) __READ_ONCE(x)

static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
	switch (size) {
	case 1: *(volatile u8 *)p = *(u8 *)res; break;
	case 2: *(volatile u16 *)p = *(u16 *)res; break;
	case 4: *(volatile u32 *)p = *(u32 *)res; break;
	case 8: *(volatile u64 *)p = *(u64 *)res; break;
	default:
		barrier();
		__builtin_memcpy((void *)p, (const void *)res, size);
		barrier();
	}
}

#define WRITE_ONCE(x, val) \
({							\
	union { typeof(x) __val; char __c[1]; } __u =	\
		{ .__val = (typeof(x)) (val) }; \
	__write_once_size(&(x), __u.__c, sizeof(x));	\
	__u.__val;					\
})

#define atomic_read(v)		READ_ONCE((v)->counter)

#define CONFIG_NR_CPUS		MAX_THREADS
#define DEFINE_PER_CPU_ALIGNED(type, name)		\
	__aligned(64) __typeof__(type) name[CONFIG_NR_CPUS]

extern __thread int __smp_processor_id;
#define smp_processor_id()	(__smp_processor_id)
#define per_cpu_ptr(p,c)	(&((*p)[(c)]))
#define this_cpu_ptr(p)		(per_cpu_ptr((p), smp_processor_id()))

#define atomic_cond_read_acquire(p,c)				\
	smp_cond_load_acquire(&(p)->counter, c)

#ifdef __aarch64__
#include "arm64/kernel.h"
#else

#define atomic_cmpxchg_acquire(p,o,n)	({			\
	int *_p = &(p)->counter;				\
	int _o = (o);						\
	__atomic_compare_exchange_n(_p, &_o, (n), 0,		\
			__ATOMIC_ACQUIRE, __ATOMIC_RELAXED);	\
	_o;							\
})

#define atomic_fetch_or_acquire(v,p)	({			\
	int *_p = &(p)->counter;				\
	__atomic_fetch_or(_p, (v), __ATOMIC_ACQUIRE);		\
})

#define atomic_andnot(v,p)	({				\
	int *_p = &(p)->counter;				\
	(void)__atomic_fetch_nand(_p, (v), __ATOMIC_RELAXED);	\
})

#define smp_load_acquire(p)	__atomic_load_n(p, __ATOMIC_ACQUIRE)
#define smp_store_release(p,v)	__atomic_store_n(p, v, __ATOMIC_RELEASE)

#define smp_cond_load_acquire(ptr, cond_expr)	({		\
	typeof(ptr) __PTR = (ptr);				\
	typeof(*ptr) VAL;					\
	for (;;) {						\
		VAL = smp_load_acquire(__PTR);			\
		if (cond_expr)					\
			break;					\
	}							\
	VAL;							\
})

#define xchg_release(p,n)	(__atomic_exchange_n(p,n,__ATOMIC_RELEASE))

#define smp_cond_load_relaxed	smp_cond_load_acquire
#define atomic_cmpxchg_relaxed	atomic_cmpxchg_acquire
#endif

#endif	/* _KERNEL_H */
