at v5.9 4.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Test cases for bitfield helpers. 4 */ 5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/bitfield.h> 11 12#define CHECK_ENC_GET_U(tp, v, field, res) do { \ 13 { \ 14 u##tp _res; \ 15 \ 16 _res = u##tp##_encode_bits(v, field); \ 17 if (_res != res) { \ 18 pr_warn("u" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != " #res "\n",\ 19 (u64)_res); \ 20 return -EINVAL; \ 21 } \ 22 if (u##tp##_get_bits(_res, field) != v) \ 23 return -EINVAL; \ 24 } \ 25 } while (0) 26 27#define CHECK_ENC_GET_LE(tp, v, field, res) do { \ 28 { \ 29 __le##tp _res; \ 30 \ 31 _res = le##tp##_encode_bits(v, field); \ 32 if (_res != cpu_to_le##tp(res)) { \ 33 pr_warn("le" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\ 34 (u64)le##tp##_to_cpu(_res), \ 35 (u64)(res)); \ 36 return -EINVAL; \ 37 } \ 38 if (le##tp##_get_bits(_res, field) != v) \ 39 return -EINVAL; \ 40 } \ 41 } while (0) 42 43#define CHECK_ENC_GET_BE(tp, v, field, res) do { \ 44 { \ 45 __be##tp _res; \ 46 \ 47 _res = be##tp##_encode_bits(v, field); \ 48 if (_res != cpu_to_be##tp(res)) { \ 49 pr_warn("be" #tp "_encode_bits(" #v ", " #field ") is 0x%llx != 0x%llx\n",\ 50 (u64)be##tp##_to_cpu(_res), \ 51 (u64)(res)); \ 52 return -EINVAL; \ 53 } \ 54 if (be##tp##_get_bits(_res, field) != v) \ 55 return -EINVAL; \ 56 } \ 57 } while (0) 58 59#define CHECK_ENC_GET(tp, v, field, res) do { \ 60 CHECK_ENC_GET_U(tp, v, field, res); \ 61 CHECK_ENC_GET_LE(tp, v, field, res); \ 62 CHECK_ENC_GET_BE(tp, v, field, res); \ 63 } while (0) 64 65static int test_constants(void) 66{ 67 /* 68 * NOTE 69 * This whole function compiles (or at least should, if everything 70 * is going according to plan) to nothing after optimisation. 71 */ 72 73 CHECK_ENC_GET(16, 1, 0x000f, 0x0001); 74 CHECK_ENC_GET(16, 3, 0x00f0, 0x0030); 75 CHECK_ENC_GET(16, 5, 0x0f00, 0x0500); 76 CHECK_ENC_GET(16, 7, 0xf000, 0x7000); 77 CHECK_ENC_GET(16, 14, 0x000f, 0x000e); 78 CHECK_ENC_GET(16, 15, 0x00f0, 0x00f0); 79 80 CHECK_ENC_GET_U(8, 1, 0x0f, 0x01); 81 CHECK_ENC_GET_U(8, 3, 0xf0, 0x30); 82 CHECK_ENC_GET_U(8, 14, 0x0f, 0x0e); 83 CHECK_ENC_GET_U(8, 15, 0xf0, 0xf0); 84 85 CHECK_ENC_GET(32, 1, 0x00000f00, 0x00000100); 86 CHECK_ENC_GET(32, 3, 0x0000f000, 0x00003000); 87 CHECK_ENC_GET(32, 5, 0x000f0000, 0x00050000); 88 CHECK_ENC_GET(32, 7, 0x00f00000, 0x00700000); 89 CHECK_ENC_GET(32, 14, 0x0f000000, 0x0e000000); 90 CHECK_ENC_GET(32, 15, 0xf0000000, 0xf0000000); 91 92 CHECK_ENC_GET(64, 1, 0x00000f0000000000ull, 0x0000010000000000ull); 93 CHECK_ENC_GET(64, 3, 0x0000f00000000000ull, 0x0000300000000000ull); 94 CHECK_ENC_GET(64, 5, 0x000f000000000000ull, 0x0005000000000000ull); 95 CHECK_ENC_GET(64, 7, 0x00f0000000000000ull, 0x0070000000000000ull); 96 CHECK_ENC_GET(64, 14, 0x0f00000000000000ull, 0x0e00000000000000ull); 97 CHECK_ENC_GET(64, 15, 0xf000000000000000ull, 0xf000000000000000ull); 98 99 return 0; 100} 101 102#define CHECK(tp, mask) do { \ 103 u64 v; \ 104 \ 105 for (v = 0; v < 1 << hweight32(mask); v++) \ 106 if (tp##_encode_bits(v, mask) != v << __ffs64(mask)) \ 107 return -EINVAL; \ 108 } while (0) 109 110static int test_variables(void) 111{ 112 CHECK(u8, 0x0f); 113 CHECK(u8, 0xf0); 114 CHECK(u8, 0x38); 115 116 CHECK(u16, 0x0038); 117 CHECK(u16, 0x0380); 118 CHECK(u16, 0x3800); 119 CHECK(u16, 0x8000); 120 121 CHECK(u32, 0x80000000); 122 CHECK(u32, 0x7f000000); 123 CHECK(u32, 0x07e00000); 124 CHECK(u32, 0x00018000); 125 126 CHECK(u64, 0x8000000000000000ull); 127 CHECK(u64, 0x7f00000000000000ull); 128 CHECK(u64, 0x0001800000000000ull); 129 CHECK(u64, 0x0000000080000000ull); 130 CHECK(u64, 0x000000007f000000ull); 131 CHECK(u64, 0x0000000018000000ull); 132 CHECK(u64, 0x0000001f8000000ull); 133 134 return 0; 135} 136 137static int __init test_bitfields(void) 138{ 139 int ret = test_constants(); 140 141 if (ret) { 142 pr_warn("constant tests failed!\n"); 143 return ret; 144 } 145 146 ret = test_variables(); 147 if (ret) { 148 pr_warn("variable tests failed!\n"); 149 return ret; 150 } 151 152#ifdef TEST_BITFIELD_COMPILE 153 /* these should fail compilation */ 154 CHECK_ENC_GET(16, 16, 0x0f00, 0x1000); 155 u32_encode_bits(7, 0x06000000); 156 157 /* this should at least give a warning */ 158 u16_encode_bits(0, 0x60000); 159#endif 160 161 pr_info("tests passed\n"); 162 163 return 0; 164} 165module_init(test_bitfields) 166 167MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); 168MODULE_LICENSE("GPL");