2015-04-27 13:40:11 -04:00
|
|
|
/* Intel x86 GCC specific public inline assembler functions and macros */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015, Wind River Systems, Inc.
|
|
|
|
*
|
2017-01-18 17:01:01 -08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2015-04-27 13:40:11 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Either public functions or macros or invoked by public functions */
|
|
|
|
|
|
|
|
#ifndef _ASM_INLINE_GCC_PUBLIC_GCC_H
|
|
|
|
#define _ASM_INLINE_GCC_PUBLIC_GCC_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The file must not be included directly
|
2016-11-05 19:52:29 -04:00
|
|
|
* Include kernel.h instead
|
2015-04-27 13:40:11 -04:00
|
|
|
*/
|
|
|
|
|
2015-08-21 12:49:57 +03:00
|
|
|
#include <sys_io.h>
|
|
|
|
|
2016-01-22 12:38:49 -05:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2015-04-27 13:40:11 -04:00
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
|
|
|
*
|
2015-08-12 18:31:41 -04:00
|
|
|
* @internal
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-12 18:31:41 -04:00
|
|
|
* @brief Disable all interrupts on the CPU
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-12 18:31:41 -04:00
|
|
|
* GCC assembly internals of irq_lock(). See irq_lock() for a complete
|
|
|
|
* description.
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-07-01 17:29:04 -04:00
|
|
|
* @return An architecture-dependent lock-out key representing the
|
2015-07-01 17:22:39 -04:00
|
|
|
* "interrupt disable state" prior to the call.
|
|
|
|
*/
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE unsigned int _do_irq_lock(void)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
__asm__ volatile (
|
|
|
|
"pushfl;\n\t"
|
|
|
|
"cli;\n\t"
|
|
|
|
"popl %0;\n\t"
|
|
|
|
: "=g" (key)
|
|
|
|
:
|
|
|
|
: "memory"
|
|
|
|
);
|
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
2015-08-12 18:31:41 -04:00
|
|
|
*
|
|
|
|
* @internal
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-07-01 17:51:40 -04:00
|
|
|
* @brief Enable all interrupts on the CPU (inline)
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-12 18:31:41 -04:00
|
|
|
* GCC assembly internals of irq_lock_unlock(). See irq_lock_unlock() for a
|
|
|
|
* complete description.
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-07-01 17:29:04 -04:00
|
|
|
* @return N/A
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE void _do_irq_unlock(void)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
|
|
|
__asm__ volatile (
|
|
|
|
"sti;\n\t"
|
2016-12-02 12:18:39 -05:00
|
|
|
: : : "memory"
|
2015-04-27 13:40:11 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @brief find least significant bit set in a 32-bit word
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* This routine finds the first bit set starting from the least significant bit
|
|
|
|
* in the argument passed in and returns the index of that bit. Bits are
|
|
|
|
* numbered starting at 1 from the least significant bit. A return value of
|
|
|
|
* zero indicates that the value passed is zero.
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @return least significant bit set, 0 if @a op is 0
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @internal
|
|
|
|
* For Intel64 (x86_64) architectures, the 'cmovzl' can be removed and leverage
|
|
|
|
* the fact that the 'bsfl' doesn't modify the destination operand when the
|
|
|
|
* source operand is zero. The "bitpos" variable can be preloaded into the
|
|
|
|
* destination register, and given the unconditional ++bitpos that is performed
|
|
|
|
* after the 'cmovzl', the correct results are yielded.
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-08-14 17:22:50 -04:00
|
|
|
static ALWAYS_INLINE unsigned int find_lsb_set(uint32_t op)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2016-03-02 12:28:09 -08:00
|
|
|
unsigned int bitpos;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
|
|
|
__asm__ volatile (
|
|
|
|
|
2015-07-22 13:34:59 -04:00
|
|
|
#if defined(CONFIG_CMOV)
|
2015-04-27 13:40:11 -04:00
|
|
|
|
|
|
|
"bsfl %1, %0;\n\t"
|
|
|
|
"cmovzl %2, %0;\n\t"
|
|
|
|
: "=r" (bitpos)
|
|
|
|
: "rm" (op), "r" (-1)
|
|
|
|
: "cc"
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
"bsfl %1, %0;\n\t"
|
|
|
|
"jnz 1f;\n\t"
|
|
|
|
"movl $-1, %0;\n\t"
|
|
|
|
"1:\n\t"
|
|
|
|
: "=r" (bitpos)
|
|
|
|
: "rm" (op)
|
|
|
|
: "cc"
|
|
|
|
|
2015-07-22 13:34:59 -04:00
|
|
|
#endif /* CONFIG_CMOV */
|
2015-04-27 13:40:11 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
return (bitpos + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @brief find most significant bit set in a 32-bit word
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* This routine finds the first bit set starting from the most significant bit
|
|
|
|
* in the argument passed in and returns the index of that bit. Bits are
|
|
|
|
* numbered starting at 1 from the least significant bit. A return value of
|
|
|
|
* zero indicates that the value passed is zero.
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @return most significant bit set, 0 if @a op is 0
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-08-14 17:16:16 -04:00
|
|
|
* @internal
|
|
|
|
* For Intel64 (x86_64) architectures, the 'cmovzl' can be removed and leverage
|
|
|
|
* the fact that the 'bsfl' doesn't modify the destination operand when the
|
|
|
|
* source operand is zero. The "bitpos" variable can be preloaded into the
|
|
|
|
* destination register, and given the unconditional ++bitpos that is performed
|
|
|
|
* after the 'cmovzl', the correct results are yielded.
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-08-14 17:22:50 -04:00
|
|
|
static ALWAYS_INLINE unsigned int find_msb_set(uint32_t op)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2016-03-02 12:28:09 -08:00
|
|
|
unsigned int bitpos;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
|
|
|
__asm__ volatile (
|
|
|
|
|
2015-07-22 13:34:59 -04:00
|
|
|
#if defined(CONFIG_CMOV)
|
2015-04-27 13:40:11 -04:00
|
|
|
|
|
|
|
"bsrl %1, %0;\n\t"
|
|
|
|
"cmovzl %2, %0;\n\t"
|
|
|
|
: "=r" (bitpos)
|
|
|
|
: "rm" (op), "r" (-1)
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
"bsrl %1, %0;\n\t"
|
|
|
|
"jnz 1f;\n\t"
|
|
|
|
"movl $-1, %0;\n\t"
|
|
|
|
"1:\n\t"
|
|
|
|
: "=r" (bitpos)
|
|
|
|
: "rm" (op)
|
|
|
|
: "cc"
|
|
|
|
|
2015-07-22 13:34:59 -04:00
|
|
|
#endif /* CONFIG_CMOV */
|
2015-04-27 13:40:11 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
return (bitpos + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
2016-11-05 15:43:33 -04:00
|
|
|
* @brief read timestamp register ensuring serialization
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-11-05 15:43:33 -04:00
|
|
|
static inline uint64_t _tsc_read(void)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
uint32_t lo;
|
|
|
|
uint32_t hi;
|
|
|
|
};
|
|
|
|
uint64_t value;
|
|
|
|
} rv;
|
|
|
|
|
|
|
|
/* rdtsc & cpuid clobbers eax, ebx, ecx and edx registers */
|
|
|
|
__asm__ volatile (/* serialize */
|
|
|
|
"xorl %%eax,%%eax;\n\t"
|
|
|
|
"cpuid;\n\t"
|
|
|
|
:
|
|
|
|
:
|
|
|
|
: "%eax", "%ebx", "%ecx", "%edx"
|
|
|
|
);
|
|
|
|
/*
|
|
|
|
* We cannot use "=A", since this would use %rax on x86_64 and
|
|
|
|
* return only the lower 32bits of the TSC
|
|
|
|
*/
|
|
|
|
__asm__ volatile ("rdtsc" : "=a" (rv.lo), "=d" (rv.hi));
|
|
|
|
|
|
|
|
|
|
|
|
return rv.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
2015-04-27 13:40:11 -04:00
|
|
|
*
|
2015-07-01 17:51:40 -04:00
|
|
|
* @brief Get a 32 bit CPU timestamp counter
|
2015-04-27 13:40:11 -04:00
|
|
|
*
|
2015-07-01 17:29:04 -04:00
|
|
|
* @return a 32-bit number
|
2015-04-27 13:40:11 -04:00
|
|
|
*/
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-04-27 13:40:11 -04:00
|
|
|
uint32_t _do_read_cpu_timestamp32(void)
|
|
|
|
{
|
|
|
|
uint32_t rv;
|
|
|
|
|
|
|
|
__asm__ volatile("rdtsc" : "=a"(rv) : : "%edx");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-21 12:49:57 +03:00
|
|
|
/* Implementation of sys_io.h's documented functions */
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
|
|
|
void sys_out8(uint8_t data, io_port_t port)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("outb %b0, %w1;\n\t"
|
|
|
|
:
|
|
|
|
: "a"(data), "Nd"(port));
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint8_t sys_in8(io_port_t port)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-08-21 12:49:57 +03:00
|
|
|
uint8_t ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("inb %w1, %b0;\n\t"
|
|
|
|
: "=a"(ret)
|
|
|
|
: "Nd"(port));
|
2015-08-21 12:49:57 +03:00
|
|
|
return ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
void sys_out16(uint16_t data, io_port_t port)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("outw %w0, %w1;\n\t"
|
|
|
|
:
|
|
|
|
: "a"(data), "Nd"(port));
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint16_t sys_in16(io_port_t port)
|
|
|
|
{
|
|
|
|
uint16_t ret;
|
|
|
|
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("inw %w1, %w0;\n\t"
|
|
|
|
: "=a"(ret)
|
|
|
|
: "Nd"(port));
|
2015-08-21 12:49:57 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
void sys_out32(uint32_t data, io_port_t port)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("outl %0, %w1;\n\t"
|
|
|
|
:
|
|
|
|
: "a"(data), "Nd"(port));
|
2015-08-21 12:49:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint32_t sys_in32(io_port_t port)
|
|
|
|
{
|
|
|
|
uint32_t ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-11-11 13:33:43 +01:00
|
|
|
__asm__ volatile("inl %w1, %0;\n\t"
|
|
|
|
: "=a"(ret)
|
|
|
|
: "Nd"(port));
|
2015-08-21 12:49:57 +03:00
|
|
|
return ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
2015-10-02 17:28:18 -05:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
void sys_io_set_bit(io_port_t port, unsigned int bit)
|
2015-10-02 17:28:18 -05:00
|
|
|
{
|
|
|
|
uint32_t reg = 0;
|
|
|
|
|
2015-11-10 17:11:52 +01:00
|
|
|
__asm__ volatile("inl %w1, %0;\n\t"
|
|
|
|
"btsl %2, %0;\n\t"
|
|
|
|
"outl %0, %w1;\n\t"
|
2015-10-02 17:28:18 -05:00
|
|
|
:
|
2015-11-10 17:11:52 +01:00
|
|
|
: "a" (reg), "Nd" (port), "Ir" (bit));
|
2015-10-02 17:28:18 -05:00
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
void sys_io_clear_bit(io_port_t port, unsigned int bit)
|
2015-10-02 17:28:18 -05:00
|
|
|
{
|
|
|
|
uint32_t reg = 0;
|
|
|
|
|
2015-11-10 17:11:52 +01:00
|
|
|
__asm__ volatile("inl %w1, %0;\n\t"
|
|
|
|
"btrl %2, %0;\n\t"
|
|
|
|
"outl %0, %w1;\n\t"
|
2015-10-02 17:28:18 -05:00
|
|
|
:
|
2015-11-10 17:11:52 +01:00
|
|
|
: "a" (reg), "Nd" (port), "Ir" (bit));
|
2015-10-02 17:28:18 -05:00
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_io_test_bit(io_port_t port, unsigned int bit)
|
2015-10-02 17:28:18 -05:00
|
|
|
{
|
|
|
|
uint32_t ret;
|
|
|
|
|
2015-11-10 17:11:52 +01:00
|
|
|
__asm__ volatile("inl %w1, %0\n\t"
|
|
|
|
"btl %2, %0\n\t"
|
|
|
|
: "=a" (ret)
|
|
|
|
: "Nd" (port), "Ir" (bit));
|
2015-10-02 17:28:18 -05:00
|
|
|
|
|
|
|
return (ret & 1);
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_io_test_and_set_bit(io_port_t port, unsigned int bit)
|
2015-10-02 17:28:18 -05:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sys_io_test_bit(port, bit);
|
|
|
|
sys_io_set_bit(port, bit);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_io_test_and_clear_bit(io_port_t port, unsigned int bit)
|
2015-10-02 17:28:18 -05:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sys_io_test_bit(port, bit);
|
|
|
|
sys_io_clear_bit(port, bit);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
void sys_write8(uint8_t data, mm_reg_t addr)
|
|
|
|
{
|
|
|
|
__asm__ volatile("movb %0, %1;\n\t"
|
|
|
|
:
|
|
|
|
: "q"(data), "m" (*(volatile uint8_t *) addr)
|
|
|
|
: "memory");
|
|
|
|
}
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint8_t sys_read8(mm_reg_t addr)
|
|
|
|
{
|
|
|
|
uint8_t ret;
|
|
|
|
|
|
|
|
__asm__ volatile("movb %1, %0;\n\t"
|
|
|
|
: "=q"(ret)
|
|
|
|
: "m" (*(volatile uint8_t *) addr)
|
|
|
|
: "memory");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
void sys_write16(uint16_t data, mm_reg_t addr)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-08-21 12:49:57 +03:00
|
|
|
__asm__ volatile("movw %0, %1;\n\t"
|
|
|
|
:
|
|
|
|
: "r"(data), "m" (*(volatile uint16_t *) addr)
|
|
|
|
: "memory");
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint16_t sys_read16(mm_reg_t addr)
|
|
|
|
{
|
|
|
|
uint16_t ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-08-21 12:49:57 +03:00
|
|
|
__asm__ volatile("movw %1, %0;\n\t"
|
|
|
|
: "=r"(ret)
|
|
|
|
: "m" (*(volatile uint16_t *) addr)
|
|
|
|
: "memory");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
void sys_write32(uint32_t data, mm_reg_t addr)
|
|
|
|
{
|
|
|
|
__asm__ volatile("movl %0, %1;\n\t"
|
|
|
|
:
|
|
|
|
: "r"(data), "m" (*(volatile uint32_t *) addr)
|
|
|
|
: "memory");
|
|
|
|
}
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2015-08-21 12:49:57 +03:00
|
|
|
uint32_t sys_read32(mm_reg_t addr)
|
2015-04-27 13:40:11 -04:00
|
|
|
{
|
2015-08-21 12:49:57 +03:00
|
|
|
uint32_t ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
|
2015-08-21 12:49:57 +03:00
|
|
|
__asm__ volatile("movl %1, %0;\n\t"
|
|
|
|
: "=r"(ret)
|
|
|
|
: "m" (*(volatile uint32_t *) addr)
|
|
|
|
: "memory");
|
|
|
|
|
|
|
|
return ret;
|
2015-04-27 13:40:11 -04:00
|
|
|
}
|
|
|
|
|
2015-08-21 12:49:57 +03:00
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
void sys_set_bit(mem_addr_t addr, unsigned int bit)
|
2015-08-21 12:50:57 +03:00
|
|
|
{
|
|
|
|
__asm__ volatile("btsl %1, %0;\n\t"
|
|
|
|
: "+m" (*(volatile uint32_t *) (addr))
|
|
|
|
: "Ir" (bit)
|
|
|
|
: "memory");
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
void sys_clear_bit(mem_addr_t addr, unsigned int bit)
|
2015-08-21 12:50:57 +03:00
|
|
|
{
|
|
|
|
__asm__ volatile("btrl %1, %0;\n\t"
|
|
|
|
: "+m" (*(volatile uint32_t *) (addr))
|
|
|
|
: "Ir" (bit));
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_test_bit(mem_addr_t addr, unsigned int bit)
|
2015-08-21 12:50:57 +03:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
__asm__ volatile("btl %2, %1;\n\t"
|
|
|
|
"sbb %0, %0\n\t"
|
|
|
|
: "=r" (ret), "+m" (*(volatile uint32_t *) (addr))
|
|
|
|
: "Ir" (bit));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_test_and_set_bit(mem_addr_t addr, unsigned int bit)
|
2015-08-21 12:50:57 +03:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
__asm__ volatile("btsl %2, %1;\n\t"
|
|
|
|
"sbb %0, %0\n\t"
|
|
|
|
: "=r" (ret), "+m" (*(volatile uint32_t *) (addr))
|
|
|
|
: "Ir" (bit));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-14 18:35:13 -07:00
|
|
|
static ALWAYS_INLINE
|
2016-03-02 12:28:09 -08:00
|
|
|
int sys_test_and_clear_bit(mem_addr_t addr, unsigned int bit)
|
2015-08-21 12:50:57 +03:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
__asm__ volatile("btrl %2, %1;\n\t"
|
|
|
|
"sbb %0, %0\n\t"
|
|
|
|
: "=r" (ret), "+m" (*(volatile uint32_t *) (addr))
|
|
|
|
: "Ir" (bit));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
sys_bitfield*(): use 'void *' instead of memaddr_t
Current users of sys_bitfield*() are bending over backwards to cast
what is most of the times a pointer into an integer.
Bitfields can be better described with an void *, so
uint{8,16,32,64}_t or any other container can be used. Most
sys_bitfield*() operations, by extension, can do the same. Note void *
has byte arithmetic, like char *.
This change will also make it implicit, for any future split of the
address space between virtual (what the SW is seeing) and physical
(what the HW is seeing) way clearer, as the functions dealing with
physical, non directly referentiable/mappeable addreses to use an
integer type, like mem_addr_t.
- include/arch/ARCH/*asm_inline*:
- sys_bitfield*() all modified to take 'void *'
Note 'void *' arihtmethic is byte based, which makes some things
easier.
- include/sys_io.h:
- introduces DEFINE_BITFIELD
- update docs
- tests/kernel/bitfield: remove all the cast contortions, use DEFINE_BITFIELD
PENDING: update other TCs
- include/arch/nios/nios2.h, drivers/interrupt_controller/ioapic_intr.c:
remove cast contortions
Change-Id: I901e62c76af46f26ff0d29cdc37099597f884511
Jira: ZEP-1347
Signed-off-by: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
2017-01-11 14:49:41 -08:00
|
|
|
static ALWAYS_INLINE
|
|
|
|
void sys_bitfield_set_bit(void *addr, unsigned int bit)
|
|
|
|
{
|
|
|
|
mem_addr_t _addr = (unsigned long) addr;
|
|
|
|
|
|
|
|
/* Doing memory offsets in terms of 32-bit values to prevent
|
|
|
|
* alignment issues. The 4 * is needed because void *
|
|
|
|
* arithmethic is byte based and by dividing by 32, we have
|
|
|
|
* the index of the four-byte block where the bit is.
|
|
|
|
*/
|
|
|
|
sys_set_bit(_addr + 4 * (bit / 32), bit & 0x1F);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALWAYS_INLINE
|
|
|
|
void sys_bitfield_clear_bit(void *addr, unsigned int bit)
|
|
|
|
{
|
|
|
|
sys_clear_bit((unsigned long) addr, bit);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALWAYS_INLINE
|
|
|
|
int sys_bitfield_test_bit(void *addr, unsigned int bit)
|
|
|
|
{
|
|
|
|
return sys_test_bit((mem_addr_t) addr, bit);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ALWAYS_INLINE
|
|
|
|
int sys_bitfield_test_and_set_bit(void *addr, unsigned int bit)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sys_bitfield_test_bit(addr, bit);
|
|
|
|
sys_bitfield_set_bit(addr, bit);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALWAYS_INLINE
|
|
|
|
int sys_bitfield_test_and_clear_bit(void *addr, unsigned int bit)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = sys_bitfield_test_bit(addr, bit);
|
|
|
|
sys_bitfield_clear_bit(addr, bit);
|
|
|
|
return ret;
|
|
|
|
}
|
2016-03-02 10:36:17 -08:00
|
|
|
|
2015-04-27 13:40:11 -04:00
|
|
|
#endif /* _ASMLANGUAGE */
|
2016-01-22 12:38:49 -05:00
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-04-27 13:40:11 -04:00
|
|
|
#endif /* _ASM_INLINE_GCC_PUBLIC_GCC_H */
|