mirror of
				https://github.com/riscv-software-src/opensbi
				synced 2025-10-30 19:48:23 +00:00 
			
		
		
		
	Implement the test which covers some of the functions from the `riscv_atomic.h` header file. The test contains 9 test cases: 1) atomic read/write test 2) add/return test 3) sub/return test 4) cmpxchg test 5) atomic_xchg test 6) atomic_raw_set_bit test 7) atomic_raw_clear_bit test 8) atomic_set_bit test 9) atomic_clear_bit test Some of the test cases operate on the `test_atomic` variable. It gets initialized in the suite init function. Signed-off-by: Ivan Orlov <ivan.orlov0322@gmail.com> Reviewed-by: Anup Patel <anup@brainfault.org>
		
			
				
	
	
		
			144 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <sbi/sbi_unit_test.h>
 | |
| #include <sbi/riscv_atomic.h>
 | |
| #include <sbi/sbi_bitops.h>
 | |
| 
 | |
| #define ATOMIC_TEST_VAL1 239l
 | |
| #define ATOMIC_TEST_VAL2 30l
 | |
| #define ATOMIC_TEST_VAL3 2024l
 | |
| 
 | |
| #define ATOMIC_TEST_BIT_NUM 3
 | |
| 
 | |
| #define ATOMIC_TEST_RAW_BIT_CELL 1
 | |
| #define ATOMIC_TEST_RAW_BIT_NUM 15
 | |
| 
 | |
| static atomic_t test_atomic;
 | |
| 
 | |
| static void atomic_test_suite_init(void)
 | |
| {
 | |
| 	ATOMIC_INIT(&test_atomic, 0);
 | |
| }
 | |
| 
 | |
| static void atomic_rw_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	/* We should read the same value as we've written */
 | |
| 	atomic_write(&test_atomic, ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL1);
 | |
| 	/* Negative value should also work */
 | |
| 	atomic_write(&test_atomic, -ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), -ATOMIC_TEST_VAL1);
 | |
| }
 | |
| 
 | |
| static void add_return_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_add_return(&test_atomic, ATOMIC_TEST_VAL2),
 | |
| 			  ATOMIC_TEST_VAL1 + ATOMIC_TEST_VAL2);
 | |
| 	/* The atomic value should be updated as well */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL1 + ATOMIC_TEST_VAL2);
 | |
| }
 | |
| 
 | |
| static void sub_return_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_sub_return(&test_atomic, ATOMIC_TEST_VAL2),
 | |
| 			  ATOMIC_TEST_VAL1 - ATOMIC_TEST_VAL2);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL1 - ATOMIC_TEST_VAL2);
 | |
| }
 | |
| 
 | |
| static void cmpxchg_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, ATOMIC_TEST_VAL1);
 | |
| 	/* if current value != expected, it stays the same */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_cmpxchg(&test_atomic, ATOMIC_TEST_VAL2, ATOMIC_TEST_VAL3),
 | |
| 			  ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL1);
 | |
| 	/* if current value == expected, it gets updated */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_cmpxchg(&test_atomic, ATOMIC_TEST_VAL1, ATOMIC_TEST_VAL2),
 | |
| 			  ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL2);
 | |
| }
 | |
| 
 | |
| static void atomic_xchg_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_xchg(&test_atomic, ATOMIC_TEST_VAL2), ATOMIC_TEST_VAL1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), ATOMIC_TEST_VAL2);
 | |
| }
 | |
| 
 | |
| static void atomic_raw_set_bit_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	unsigned long data[] = {0, 0, 0};
 | |
| 	/* the bitpos points to the bit of one of the elements of the `data` array */
 | |
| 	size_t bitpos = ATOMIC_TEST_RAW_BIT_CELL * BITS_PER_LONG + ATOMIC_TEST_RAW_BIT_NUM;
 | |
| 
 | |
| 	/* check if the bit we set actually gets set */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_raw_set_bit(bitpos, data), 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[ATOMIC_TEST_RAW_BIT_CELL], 1 << ATOMIC_TEST_RAW_BIT_NUM);
 | |
| 
 | |
| 	/* Other elements of the `data` array should stay untouched */
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[0], 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[2], 0);
 | |
| 
 | |
| 	/* check that if we set the bit twice it stays set */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_raw_set_bit(bitpos, data), 1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[ATOMIC_TEST_RAW_BIT_CELL], 1 << ATOMIC_TEST_RAW_BIT_NUM);
 | |
| }
 | |
| 
 | |
| static void atomic_raw_clear_bit_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	unsigned long data[] = {~1UL, 1 << ATOMIC_TEST_RAW_BIT_NUM, ~1UL};
 | |
| 	/* the bitpos points to the bit of one of the elements of the `data` array */
 | |
| 	size_t bitpos = ATOMIC_TEST_RAW_BIT_CELL * BITS_PER_LONG + ATOMIC_TEST_RAW_BIT_NUM;
 | |
| 
 | |
| 	/* check if the bit we clear actually gets cleared */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_raw_clear_bit(bitpos, data), 1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[ATOMIC_TEST_RAW_BIT_CELL], 0);
 | |
| 
 | |
| 	/* Other elements of the `data` array should stay untouched */
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[0], ~1UL);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[2], ~1UL);
 | |
| 
 | |
| 	/* check that if we clear the bit twice it stays cleared */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_raw_clear_bit(bitpos, data), 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, data[ATOMIC_TEST_RAW_BIT_CELL], 0);
 | |
| }
 | |
| 
 | |
| static void atomic_set_bit_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_set_bit(ATOMIC_TEST_BIT_NUM, &test_atomic), 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), 1 << ATOMIC_TEST_BIT_NUM);
 | |
| 	/* If we set the bit twice, it stays 1 */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_set_bit(ATOMIC_TEST_BIT_NUM, &test_atomic), 1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), 1 << ATOMIC_TEST_BIT_NUM);
 | |
| }
 | |
| 
 | |
| static void atomic_clear_bit_test(struct sbiunit_test_case *test)
 | |
| {
 | |
| 	atomic_write(&test_atomic, 1 << ATOMIC_TEST_BIT_NUM);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_clear_bit(ATOMIC_TEST_BIT_NUM, &test_atomic), 1);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), 0);
 | |
| 	/* if we clear the bit twice, it stays 0 */
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_clear_bit(ATOMIC_TEST_BIT_NUM, &test_atomic), 0);
 | |
| 	SBIUNIT_EXPECT_EQ(test, atomic_read(&test_atomic), 0);
 | |
| }
 | |
| 
 | |
| static struct sbiunit_test_case atomic_test_cases[] = {
 | |
| 	SBIUNIT_TEST_CASE(atomic_rw_test),
 | |
| 	SBIUNIT_TEST_CASE(add_return_test),
 | |
| 	SBIUNIT_TEST_CASE(sub_return_test),
 | |
| 	SBIUNIT_TEST_CASE(cmpxchg_test),
 | |
| 	SBIUNIT_TEST_CASE(atomic_xchg_test),
 | |
| 	SBIUNIT_TEST_CASE(atomic_raw_set_bit_test),
 | |
| 	SBIUNIT_TEST_CASE(atomic_raw_clear_bit_test),
 | |
| 	SBIUNIT_TEST_CASE(atomic_set_bit_test),
 | |
| 	SBIUNIT_TEST_CASE(atomic_clear_bit_test),
 | |
| 	SBIUNIT_END_CASE,
 | |
| };
 | |
| 
 | |
| const struct sbiunit_test_suite atomic_test_suite = {
 | |
| 	.name = "atomic_test_suite",
 | |
| 	.cases = atomic_test_cases,
 | |
| 	.init = atomic_test_suite_init
 | |
| };
 |