FILE
resource_kunit.c
File preview with syntax highlighting.
linux-6.19.14/kernel/resource_kunit.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Test cases for API provided by resource.c and ioport.h 4 */ 5 6#include <kunit/test.h> 7#include <linux/ioport.h> 8#include <linux/kernel.h> 9#include <linux/string.h> 10#include <linux/sizes.h> 11#include <linux/mm.h> 12 13#define R0_START 0x0000 14#define R0_END 0xffff 15#define R1_START 0x1234 16#define R1_END 0x2345 17#define R2_START 0x4567 18#define R2_END 0x5678 19#define R3_START 0x6789 20#define R3_END 0x789a 21#define R4_START 0x2000 22#define R4_END 0x7000 23 24static struct resource r0 = { .start = R0_START, .end = R0_END }; 25static struct resource r1 = { .start = R1_START, .end = R1_END }; 26static struct resource r2 = { .start = R2_START, .end = R2_END }; 27static struct resource r3 = { .start = R3_START, .end = R3_END }; 28static struct resource r4 = { .start = R4_START, .end = R4_END }; 29 30struct result { 31 struct resource *r1; 32 struct resource *r2; 33 struct resource r; 34 bool ret; 35}; 36 37static struct result results_for_union[] = { 38 { 39 .r1 = &r1, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true, 40 }, { 41 .r1 = &r2, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true, 42 }, { 43 .r1 = &r3, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true, 44 }, { 45 .r1 = &r4, .r2 = &r0, .r.start = R0_START, .r.end = R0_END, .ret = true, 46 }, { 47 .r1 = &r2, .r2 = &r1, .ret = false, 48 }, { 49 .r1 = &r3, .r2 = &r1, .ret = false, 50 }, { 51 .r1 = &r4, .r2 = &r1, .r.start = R1_START, .r.end = R4_END, .ret = true, 52 }, { 53 .r1 = &r2, .r2 = &r3, .ret = false, 54 }, { 55 .r1 = &r2, .r2 = &r4, .r.start = R4_START, .r.end = R4_END, .ret = true, 56 }, { 57 .r1 = &r3, .r2 = &r4, .r.start = R4_START, .r.end = R3_END, .ret = true, 58 }, 59}; 60 61static struct result results_for_intersection[] = { 62 { 63 .r1 = &r1, .r2 = &r0, .r.start = R1_START, .r.end = R1_END, .ret = true, 64 }, { 65 .r1 = &r2, .r2 = &r0, .r.start = R2_START, .r.end = R2_END, .ret = true, 66 }, { 67 .r1 = &r3, .r2 = &r0, .r.start = R3_START, .r.end = R3_END, .ret = true, 68 }, { 69 .r1 = &r4, .r2 = &r0, .r.start = R4_START, .r.end = R4_END, .ret = true, 70 }, { 71 .r1 = &r2, .r2 = &r1, .ret = false, 72 }, { 73 .r1 = &r3, .r2 = &r1, .ret = false, 74 }, { 75 .r1 = &r4, .r2 = &r1, .r.start = R4_START, .r.end = R1_END, .ret = true, 76 }, { 77 .r1 = &r2, .r2 = &r3, .ret = false, 78 }, { 79 .r1 = &r2, .r2 = &r4, .r.start = R2_START, .r.end = R2_END, .ret = true, 80 }, { 81 .r1 = &r3, .r2 = &r4, .r.start = R3_START, .r.end = R4_END, .ret = true, 82 }, 83}; 84 85static void resource_do_test(struct kunit *test, bool ret, struct resource *r, 86 bool exp_ret, struct resource *exp_r, 87 struct resource *r1, struct resource *r2) 88{ 89 KUNIT_EXPECT_EQ_MSG(test, ret, exp_ret, "Resources %pR %pR", r1, r2); 90 KUNIT_EXPECT_EQ_MSG(test, r->start, exp_r->start, "Start elements are not equal"); 91 KUNIT_EXPECT_EQ_MSG(test, r->end, exp_r->end, "End elements are not equal"); 92} 93 94static void resource_do_union_test(struct kunit *test, struct result *r) 95{ 96 struct resource result; 97 bool ret; 98 99 memset(&result, 0, sizeof(result)); 100 ret = resource_union(r->r1, r->r2, &result); 101 resource_do_test(test, ret, &result, r->ret, &r->r, r->r1, r->r2); 102 103 memset(&result, 0, sizeof(result)); 104 ret = resource_union(r->r2, r->r1, &result); 105 resource_do_test(test, ret, &result, r->ret, &r->r, r->r2, r->r1); 106} 107 108static void resource_test_union(struct kunit *test) 109{ 110 struct result *r = results_for_union; 111 unsigned int i = 0; 112 113 do { 114 resource_do_union_test(test, &r[i]); 115 } while (++i < ARRAY_SIZE(results_for_union)); 116} 117 118static void resource_do_intersection_test(struct kunit *test, struct result *r) 119{ 120 struct resource result; 121 bool ret; 122 123 memset(&result, 0, sizeof(result)); 124 ret = resource_intersection(r->r1, r->r2, &result); 125 resource_do_test(test, ret, &result, r->ret, &r->r, r->r1, r->r2); 126 127 memset(&result, 0, sizeof(result)); 128 ret = resource_intersection(r->r2, r->r1, &result); 129 resource_do_test(test, ret, &result, r->ret, &r->r, r->r2, r->r1); 130} 131 132static void resource_test_intersection(struct kunit *test) 133{ 134 struct result *r = results_for_intersection; 135 unsigned int i = 0; 136 137 do { 138 resource_do_intersection_test(test, &r[i]); 139 } while (++i < ARRAY_SIZE(results_for_intersection)); 140} 141 142/* 143 * The test resource tree for region_intersects() test: 144 * 145 * BASE-BASE+1M-1 : Test System RAM 0 146 * # hole 0 (BASE+1M-BASE+2M) 147 * BASE+2M-BASE+3M-1 : Test CXL Window 0 148 * BASE+3M-BASE+4M-1 : Test System RAM 1 149 * BASE+4M-BASE+7M-1 : Test CXL Window 1 150 * BASE+4M-BASE+5M-1 : Test System RAM 2 151 * BASE+4M+128K-BASE+4M+256K-1: Test Code 152 * BASE+5M-BASE+6M-1 : Test System RAM 3 153 */ 154#define RES_TEST_RAM0_OFFSET 0 155#define RES_TEST_RAM0_SIZE SZ_1M 156#define RES_TEST_HOLE0_OFFSET (RES_TEST_RAM0_OFFSET + RES_TEST_RAM0_SIZE) 157#define RES_TEST_HOLE0_SIZE SZ_1M 158#define RES_TEST_WIN0_OFFSET (RES_TEST_HOLE0_OFFSET + RES_TEST_HOLE0_SIZE) 159#define RES_TEST_WIN0_SIZE SZ_1M 160#define RES_TEST_RAM1_OFFSET (RES_TEST_WIN0_OFFSET + RES_TEST_WIN0_SIZE) 161#define RES_TEST_RAM1_SIZE SZ_1M 162#define RES_TEST_WIN1_OFFSET (RES_TEST_RAM1_OFFSET + RES_TEST_RAM1_SIZE) 163#define RES_TEST_WIN1_SIZE (SZ_1M * 3) 164#define RES_TEST_RAM2_OFFSET RES_TEST_WIN1_OFFSET 165#define RES_TEST_RAM2_SIZE SZ_1M 166#define RES_TEST_CODE_OFFSET (RES_TEST_RAM2_OFFSET + SZ_128K) 167#define RES_TEST_CODE_SIZE SZ_128K 168#define RES_TEST_RAM3_OFFSET (RES_TEST_RAM2_OFFSET + RES_TEST_RAM2_SIZE) 169#define RES_TEST_RAM3_SIZE SZ_1M 170#define RES_TEST_TOTAL_SIZE ((RES_TEST_WIN1_OFFSET + RES_TEST_WIN1_SIZE)) 171 172KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *); 173 174static void remove_free_resource(void *ctx) 175{ 176 struct resource *res = (struct resource *)ctx; 177 178 remove_resource(res); 179 kfree(res); 180} 181 182static void resource_test_add_action_or_abort( 183 struct kunit *test, void (*action)(void *), void *ctx) 184{ 185 KUNIT_ASSERT_EQ_MSG(test, 0, 186 kunit_add_action_or_reset(test, action, ctx), 187 "Fail to add action"); 188} 189 190static void resource_test_request_region(struct kunit *test, struct resource *parent, 191 resource_size_t start, resource_size_t size, 192 const char *name, unsigned long flags) 193{ 194 struct resource *res; 195 196 res = __request_region(parent, start, size, name, flags); 197 KUNIT_ASSERT_NOT_NULL(test, res); 198 resource_test_add_action_or_abort(test, remove_free_resource, res); 199} 200 201static void resource_test_insert_resource(struct kunit *test, struct resource *parent, 202 resource_size_t start, resource_size_t size, 203 const char *name, unsigned long flags) 204{ 205 struct resource *res; 206 207 res = kzalloc(sizeof(*res), GFP_KERNEL); 208 KUNIT_ASSERT_NOT_NULL(test, res); 209 210 res->name = name; 211 res->start = start; 212 res->end = start + size - 1; 213 res->flags = flags; 214 if (insert_resource(parent, res)) { 215 resource_test_add_action_or_abort(test, kfree_wrapper, res); 216 KUNIT_FAIL_AND_ABORT(test, "Fail to insert resource %pR\n", res); 217 } 218 219 resource_test_add_action_or_abort(test, remove_free_resource, res); 220} 221 222static void resource_test_region_intersects(struct kunit *test) 223{ 224 unsigned long flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 225 struct resource *parent; 226 resource_size_t start; 227 228 /* Find an iomem_resource hole to hold test resources */ 229 parent = alloc_free_mem_region(&iomem_resource, RES_TEST_TOTAL_SIZE, SZ_1M, 230 "test resources"); 231 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); 232 start = parent->start; 233 resource_test_add_action_or_abort(test, remove_free_resource, parent); 234 235 resource_test_request_region(test, parent, start + RES_TEST_RAM0_OFFSET, 236 RES_TEST_RAM0_SIZE, "Test System RAM 0", flags); 237 resource_test_insert_resource(test, parent, start + RES_TEST_WIN0_OFFSET, 238 RES_TEST_WIN0_SIZE, "Test CXL Window 0", 239 IORESOURCE_MEM); 240 resource_test_request_region(test, parent, start + RES_TEST_RAM1_OFFSET, 241 RES_TEST_RAM1_SIZE, "Test System RAM 1", flags); 242 resource_test_insert_resource(test, parent, start + RES_TEST_WIN1_OFFSET, 243 RES_TEST_WIN1_SIZE, "Test CXL Window 1", 244 IORESOURCE_MEM); 245 resource_test_request_region(test, parent, start + RES_TEST_RAM2_OFFSET, 246 RES_TEST_RAM2_SIZE, "Test System RAM 2", flags); 247 resource_test_insert_resource(test, parent, start + RES_TEST_CODE_OFFSET, 248 RES_TEST_CODE_SIZE, "Test Code", flags); 249 resource_test_request_region(test, parent, start + RES_TEST_RAM3_OFFSET, 250 RES_TEST_RAM3_SIZE, "Test System RAM 3", flags); 251 kunit_release_action(test, remove_free_resource, parent); 252 253 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 254 region_intersects(start + RES_TEST_RAM0_OFFSET, PAGE_SIZE, 255 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 256 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 257 region_intersects(start + RES_TEST_RAM0_OFFSET + 258 RES_TEST_RAM0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 259 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 260 KUNIT_EXPECT_EQ(test, REGION_DISJOINT, 261 region_intersects(start + RES_TEST_HOLE0_OFFSET, PAGE_SIZE, 262 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 263 KUNIT_EXPECT_EQ(test, REGION_DISJOINT, 264 region_intersects(start + RES_TEST_HOLE0_OFFSET + 265 RES_TEST_HOLE0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 266 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 267 KUNIT_EXPECT_EQ(test, REGION_MIXED, 268 region_intersects(start + RES_TEST_WIN0_OFFSET + 269 RES_TEST_WIN0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 270 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 271 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 272 region_intersects(start + RES_TEST_RAM1_OFFSET + 273 RES_TEST_RAM1_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 274 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 275 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 276 region_intersects(start + RES_TEST_RAM2_OFFSET + 277 RES_TEST_RAM2_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 278 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 279 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 280 region_intersects(start + RES_TEST_CODE_OFFSET, PAGE_SIZE, 281 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 282 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 283 region_intersects(start + RES_TEST_RAM2_OFFSET, 284 RES_TEST_RAM2_SIZE + PAGE_SIZE, 285 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 286 KUNIT_EXPECT_EQ(test, REGION_MIXED, 287 region_intersects(start + RES_TEST_RAM3_OFFSET, 288 RES_TEST_RAM3_SIZE + PAGE_SIZE, 289 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 290} 291 292static struct kunit_case resource_test_cases[] = { 293 KUNIT_CASE(resource_test_union), 294 KUNIT_CASE(resource_test_intersection), 295 KUNIT_CASE(resource_test_region_intersects), 296 {} 297}; 298 299static struct kunit_suite resource_test_suite = { 300 .name = "resource", 301 .test_cases = resource_test_cases, 302}; 303kunit_test_suite(resource_test_suite); 304 305MODULE_DESCRIPTION("I/O Port & Memory Resource manager unit tests"); 306MODULE_LICENSE("GPL");
~/
Read-only file preview.