mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-30 00:00:15 +01:00
83 lines
2.1 KiB
C
83 lines
2.1 KiB
C
/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file */
|
|
#include <util/mmio.h>
|
|
#include <util/udma_barrier.h>
|
|
#include <config.h>
|
|
|
|
#include <pthread.h>
|
|
#include <stdbool.h>
|
|
|
|
#if SIZEOF_LONG != 8
|
|
|
|
static pthread_spinlock_t mmio_spinlock;
|
|
|
|
static __attribute__((constructor)) void lock_constructor(void)
|
|
{
|
|
pthread_spin_init(&mmio_spinlock, PTHREAD_PROCESS_PRIVATE);
|
|
}
|
|
|
|
/* When the arch does not have a 64 bit store we provide an emulation that
|
|
does two stores in address ascending order while holding a global
|
|
spinlock. */
|
|
static void pthread_mmio_write64_be(void *addr, __be64 val)
|
|
{
|
|
__be32 first_dword = htobe32(be64toh(val) >> 32);
|
|
__be32 second_dword = htobe32(be64toh(val));
|
|
|
|
/* The WC spinlock, by definition, provides global ordering for all UC
|
|
and WC stores within the critical region. */
|
|
mmio_wc_spinlock(&mmio_spinlock);
|
|
|
|
mmio_write32_be(addr, first_dword);
|
|
mmio_write32_be(addr + 4, second_dword);
|
|
|
|
mmio_wc_spinunlock(&mmio_spinlock);
|
|
}
|
|
|
|
#if defined(__i386__)
|
|
#include <xmmintrin.h>
|
|
#include <cpuid.h>
|
|
|
|
/* For ia32 we have historically emitted movlps SSE instructions to do the 64
|
|
bit operations. */
|
|
static void __attribute__((target("sse")))
|
|
sse_mmio_write64_be(void *addr, __be64 val)
|
|
{
|
|
__m128 tmp = {};
|
|
tmp = _mm_loadl_pi(tmp, (__force __m64 *)&val);
|
|
_mm_storel_pi((__m64 *)addr,tmp);
|
|
}
|
|
|
|
static bool have_sse(void)
|
|
{
|
|
unsigned int ax,bx,cx,dx;
|
|
|
|
if (!__get_cpuid(1,&ax,&bx,&cx,&dx))
|
|
return false;
|
|
return dx & bit_SSE;
|
|
}
|
|
|
|
#endif /* defined(__i386__) */
|
|
|
|
typedef void (*write64_fn_t)(void *, __be64);
|
|
|
|
/* This uses the STT_GNU_IFUNC extension to have the dynamic linker select the
|
|
best above implementations at runtime. */
|
|
#if HAVE_FUNC_ATTRIBUTE_IFUNC
|
|
void mmio_write64_be(void *addr, __be64 val)
|
|
__attribute__((ifunc("resolve_mmio_write64_be")));
|
|
static write64_fn_t resolve_mmio_write64_be(void);
|
|
#else
|
|
__asm__(".type mmio_write64_be, %gnu_indirect_function");
|
|
write64_fn_t resolve_mmio_write64_be(void) __asm__("mmio_write64_be");
|
|
#endif
|
|
|
|
write64_fn_t resolve_mmio_write64_be(void)
|
|
{
|
|
#if defined(__i386__)
|
|
if (have_sse())
|
|
return &sse_mmio_write64_be;
|
|
#endif
|
|
return &pthread_mmio_write64_be;
|
|
}
|
|
|
|
#endif /* SIZEOF_LONG != 8 */
|