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 24 static struct resource r0 = { .start = R0_START, .end = R0_END }; 25 static struct resource r1 = { .start = R1_START, .end = R1_END }; 26 static struct resource r2 = { .start = R2_START, .end = R2_END }; 27 static struct resource r3 = { .start = R3_START, .end = R3_END }; 28 static struct resource r4 = { .start = R4_START, .end = R4_END }; 29 30 struct result { 31 struct resource *r1; 32 struct resource *r2; 33 struct resource r; 34 bool ret; 35 }; 36 37 static 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 61 static 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 85 static 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 94 static 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 108 static 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 118 static 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 132 static 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 172 static void remove_free_resource(void *ctx) 173 { 174 struct resource *res = (struct resource *)ctx; 175 176 remove_resource(res); 177 kfree(res); 178 } 179 180 static void resource_test_request_region(struct kunit *test, struct resource *parent, 181 resource_size_t start, resource_size_t size, 182 const char *name, unsigned long flags) 183 { 184 struct resource *res; 185 186 res = __request_region(parent, start, size, name, flags); 187 KUNIT_ASSERT_NOT_NULL(test, res); 188 kunit_add_action_or_reset(test, remove_free_resource, res); 189 } 190 191 static void resource_test_insert_resource(struct kunit *test, struct resource *parent, 192 resource_size_t start, resource_size_t size, 193 const char *name, unsigned long flags) 194 { 195 struct resource *res; 196 197 res = kzalloc(sizeof(*res), GFP_KERNEL); 198 KUNIT_ASSERT_NOT_NULL(test, res); 199 200 res->name = name; 201 res->start = start; 202 res->end = start + size - 1; 203 res->flags = flags; 204 if (insert_resource(parent, res)) { 205 kfree(res); 206 KUNIT_FAIL_AND_ABORT(test, "Fail to insert resource %pR\n", res); 207 } 208 209 kunit_add_action_or_reset(test, remove_free_resource, res); 210 } 211 212 static void resource_test_region_intersects(struct kunit *test) 213 { 214 unsigned long flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 215 struct resource *parent; 216 resource_size_t start; 217 218 /* Find an iomem_resource hole to hold test resources */ 219 parent = alloc_free_mem_region(&iomem_resource, RES_TEST_TOTAL_SIZE, SZ_1M, 220 "test resources"); 221 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); 222 start = parent->start; 223 kunit_add_action_or_reset(test, remove_free_resource, parent); 224 225 resource_test_request_region(test, parent, start + RES_TEST_RAM0_OFFSET, 226 RES_TEST_RAM0_SIZE, "Test System RAM 0", flags); 227 resource_test_insert_resource(test, parent, start + RES_TEST_WIN0_OFFSET, 228 RES_TEST_WIN0_SIZE, "Test CXL Window 0", 229 IORESOURCE_MEM); 230 resource_test_request_region(test, parent, start + RES_TEST_RAM1_OFFSET, 231 RES_TEST_RAM1_SIZE, "Test System RAM 1", flags); 232 resource_test_insert_resource(test, parent, start + RES_TEST_WIN1_OFFSET, 233 RES_TEST_WIN1_SIZE, "Test CXL Window 1", 234 IORESOURCE_MEM); 235 resource_test_request_region(test, parent, start + RES_TEST_RAM2_OFFSET, 236 RES_TEST_RAM2_SIZE, "Test System RAM 2", flags); 237 resource_test_insert_resource(test, parent, start + RES_TEST_CODE_OFFSET, 238 RES_TEST_CODE_SIZE, "Test Code", flags); 239 resource_test_request_region(test, parent, start + RES_TEST_RAM3_OFFSET, 240 RES_TEST_RAM3_SIZE, "Test System RAM 3", flags); 241 kunit_release_action(test, remove_free_resource, parent); 242 243 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 244 region_intersects(start + RES_TEST_RAM0_OFFSET, PAGE_SIZE, 245 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 246 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 247 region_intersects(start + RES_TEST_RAM0_OFFSET + 248 RES_TEST_RAM0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 249 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 250 KUNIT_EXPECT_EQ(test, REGION_DISJOINT, 251 region_intersects(start + RES_TEST_HOLE0_OFFSET, PAGE_SIZE, 252 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 253 KUNIT_EXPECT_EQ(test, REGION_DISJOINT, 254 region_intersects(start + RES_TEST_HOLE0_OFFSET + 255 RES_TEST_HOLE0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 256 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 257 KUNIT_EXPECT_EQ(test, REGION_MIXED, 258 region_intersects(start + RES_TEST_WIN0_OFFSET + 259 RES_TEST_WIN0_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 260 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 261 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 262 region_intersects(start + RES_TEST_RAM1_OFFSET + 263 RES_TEST_RAM1_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 264 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 265 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 266 region_intersects(start + RES_TEST_RAM2_OFFSET + 267 RES_TEST_RAM2_SIZE - PAGE_SIZE, 2 * PAGE_SIZE, 268 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 269 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 270 region_intersects(start + RES_TEST_CODE_OFFSET, PAGE_SIZE, 271 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 272 KUNIT_EXPECT_EQ(test, REGION_INTERSECTS, 273 region_intersects(start + RES_TEST_RAM2_OFFSET, 274 RES_TEST_RAM2_SIZE + PAGE_SIZE, 275 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 276 KUNIT_EXPECT_EQ(test, REGION_MIXED, 277 region_intersects(start + RES_TEST_RAM3_OFFSET, 278 RES_TEST_RAM3_SIZE + PAGE_SIZE, 279 IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)); 280 } 281 282 static struct kunit_case resource_test_cases[] = { 283 KUNIT_CASE(resource_test_union), 284 KUNIT_CASE(resource_test_intersection), 285 KUNIT_CASE(resource_test_region_intersects), 286 {} 287 }; 288 289 static struct kunit_suite resource_test_suite = { 290 .name = "resource", 291 .test_cases = resource_test_cases, 292 }; 293 kunit_test_suite(resource_test_suite); 294 295 MODULE_DESCRIPTION("I/O Port & Memory Resource manager unit tests"); 296 MODULE_LICENSE("GPL"); 297