Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of/overlay: Add overlay unittests

Add unittests for OF overlays.

It tests overlay device addition/removal and whether
the apply revert sequence is correct.

Changes since V1:
* Added local fixups entries.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
Signed-off-by: Grant Likely <grant.likely@linaro.org>

authored by

Pantelis Antoniou and committed by
Grant Likely
177d271c 7518b589

+691
+14
Documentation/devicetree/bindings/unittest.txt
··· 1 + * OF selftest platform device 2 + 3 + ** selftest 4 + 5 + Required properties: 6 + - compatible: must be "selftest" 7 + 8 + All other properties are optional. 9 + 10 + Example: 11 + selftest { 12 + compatible = "selftest"; 13 + status = "okay"; 14 + };
+16
drivers/of/unittest-data/testcases.dts
··· 13 13 #include "tests-interrupts.dtsi" 14 14 #include "tests-match.dtsi" 15 15 #include "tests-platform.dtsi" 16 + #include "tests-overlay.dtsi" 16 17 17 18 /* 18 19 * phandle fixup data - generated by dtc patches that aren't upstream. ··· 59 58 }; 60 59 testcase-device2 { 61 60 interrupt-parent = <0x00000000>; 61 + }; 62 + overlay2 { 63 + fragment@0 { 64 + target = <0x00000000>; 65 + }; 66 + }; 67 + overlay3 { 68 + fragment@0 { 69 + target = <0x00000000>; 70 + }; 71 + }; 72 + overlay4 { 73 + fragment@0 { 74 + target = <0x00000000>; 75 + }; 62 76 }; 63 77 }; 64 78 }; };
+180
drivers/of/unittest-data/tests-overlay.dtsi
··· 1 + 2 + / { 3 + testcase-data { 4 + overlay-node { 5 + 6 + /* test bus */ 7 + selftestbus: test-bus { 8 + compatible = "simple-bus"; 9 + #address-cells = <1>; 10 + #size-cells = <0>; 11 + 12 + selftest100: test-selftest100 { 13 + compatible = "selftest"; 14 + status = "okay"; 15 + reg = <100>; 16 + }; 17 + 18 + selftest101: test-selftest101 { 19 + compatible = "selftest"; 20 + status = "disabled"; 21 + reg = <101>; 22 + }; 23 + 24 + selftest0: test-selftest0 { 25 + compatible = "selftest"; 26 + status = "disabled"; 27 + reg = <0>; 28 + }; 29 + 30 + selftest1: test-selftest1 { 31 + compatible = "selftest"; 32 + status = "okay"; 33 + reg = <1>; 34 + }; 35 + 36 + selftest2: test-selftest2 { 37 + compatible = "selftest"; 38 + status = "disabled"; 39 + reg = <2>; 40 + }; 41 + 42 + selftest3: test-selftest3 { 43 + compatible = "selftest"; 44 + status = "okay"; 45 + reg = <3>; 46 + }; 47 + 48 + selftest5: test-selftest5 { 49 + compatible = "selftest"; 50 + status = "disabled"; 51 + reg = <5>; 52 + }; 53 + 54 + selftest6: test-selftest6 { 55 + compatible = "selftest"; 56 + status = "disabled"; 57 + reg = <6>; 58 + }; 59 + 60 + selftest7: test-selftest7 { 61 + compatible = "selftest"; 62 + status = "disabled"; 63 + reg = <7>; 64 + }; 65 + 66 + selftest8: test-selftest8 { 67 + compatible = "selftest"; 68 + status = "disabled"; 69 + reg = <8>; 70 + }; 71 + }; 72 + }; 73 + 74 + /* test enable using absolute target path */ 75 + overlay0 { 76 + fragment@0 { 77 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest0"; 78 + __overlay__ { 79 + status = "okay"; 80 + }; 81 + }; 82 + }; 83 + 84 + /* test disable using absolute target path */ 85 + overlay1 { 86 + fragment@0 { 87 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest1"; 88 + __overlay__ { 89 + status = "disabled"; 90 + }; 91 + }; 92 + }; 93 + 94 + /* test enable using label */ 95 + overlay2 { 96 + fragment@0 { 97 + target = <&selftest2>; 98 + __overlay__ { 99 + status = "okay"; 100 + }; 101 + }; 102 + }; 103 + 104 + /* test disable using label */ 105 + overlay3 { 106 + fragment@0 { 107 + target = <&selftest3>; 108 + __overlay__ { 109 + status = "disabled"; 110 + }; 111 + }; 112 + }; 113 + 114 + /* test insertion of a full node */ 115 + overlay4 { 116 + fragment@0 { 117 + target = <&selftestbus>; 118 + __overlay__ { 119 + 120 + /* suppress DTC warning */ 121 + #address-cells = <1>; 122 + #size-cells = <0>; 123 + 124 + test-selftest4 { 125 + compatible = "selftest"; 126 + status = "okay"; 127 + reg = <4>; 128 + }; 129 + }; 130 + }; 131 + }; 132 + 133 + /* test overlay apply revert */ 134 + overlay5 { 135 + fragment@0 { 136 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest5"; 137 + __overlay__ { 138 + status = "okay"; 139 + }; 140 + }; 141 + }; 142 + 143 + /* test overlays application and removal in sequence */ 144 + overlay6 { 145 + fragment@0 { 146 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest6"; 147 + __overlay__ { 148 + status = "okay"; 149 + }; 150 + }; 151 + }; 152 + overlay7 { 153 + fragment@0 { 154 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest7"; 155 + __overlay__ { 156 + status = "okay"; 157 + }; 158 + }; 159 + }; 160 + 161 + /* test overlays application and removal in bad sequence */ 162 + overlay8 { 163 + fragment@0 { 164 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest8"; 165 + __overlay__ { 166 + status = "okay"; 167 + }; 168 + }; 169 + }; 170 + overlay9 { 171 + fragment@0 { 172 + target-path = "/testcase-data/overlay-node/test-bus/test-selftest8"; 173 + __overlay__ { 174 + property-foo = "bar"; 175 + }; 176 + }; 177 + }; 178 + 179 + }; 180 + };
+481
drivers/of/unittest.c
··· 17 17 #include <linux/mutex.h> 18 18 #include <linux/slab.h> 19 19 #include <linux/device.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/of_platform.h> 20 22 21 23 #include "of_private.h" 22 24 ··· 935 933 } 936 934 } 937 935 936 + #ifdef CONFIG_OF_OVERLAY 937 + 938 + static int selftest_probe(struct platform_device *pdev) 939 + { 940 + struct device *dev = &pdev->dev; 941 + struct device_node *np = dev->of_node; 942 + 943 + if (np == NULL) { 944 + dev_err(dev, "No OF data for device\n"); 945 + return -EINVAL; 946 + 947 + } 948 + 949 + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); 950 + return 0; 951 + } 952 + 953 + static int selftest_remove(struct platform_device *pdev) 954 + { 955 + struct device *dev = &pdev->dev; 956 + struct device_node *np = dev->of_node; 957 + 958 + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); 959 + return 0; 960 + } 961 + 962 + static struct of_device_id selftest_match[] = { 963 + { .compatible = "selftest", }, 964 + {}, 965 + }; 966 + MODULE_DEVICE_TABLE(of, altera_jtaguart_match); 967 + 968 + static struct platform_driver selftest_driver = { 969 + .probe = selftest_probe, 970 + .remove = selftest_remove, 971 + .driver = { 972 + .name = "selftest", 973 + .owner = THIS_MODULE, 974 + .of_match_table = of_match_ptr(selftest_match), 975 + }, 976 + }; 977 + 978 + /* get the platform device instantiated at the path */ 979 + static struct platform_device *of_path_to_platform_device(const char *path) 980 + { 981 + struct device_node *np; 982 + struct platform_device *pdev; 983 + 984 + np = of_find_node_by_path(path); 985 + if (np == NULL) 986 + return NULL; 987 + 988 + pdev = of_find_device_by_node(np); 989 + of_node_put(np); 990 + 991 + return pdev; 992 + } 993 + 994 + /* find out if a platform device exists at that path */ 995 + static int of_path_platform_device_exists(const char *path) 996 + { 997 + struct platform_device *pdev; 998 + 999 + pdev = of_path_to_platform_device(path); 1000 + platform_device_put(pdev); 1001 + return pdev != NULL; 1002 + } 1003 + 1004 + static const char *selftest_path(int nr) 1005 + { 1006 + static char buf[256]; 1007 + 1008 + snprintf(buf, sizeof(buf) - 1, 1009 + "/testcase-data/overlay-node/test-bus/test-selftest%d", nr); 1010 + buf[sizeof(buf) - 1] = '\0'; 1011 + 1012 + return buf; 1013 + } 1014 + 1015 + static const char *overlay_path(int nr) 1016 + { 1017 + static char buf[256]; 1018 + 1019 + snprintf(buf, sizeof(buf) - 1, 1020 + "/testcase-data/overlay%d", nr); 1021 + buf[sizeof(buf) - 1] = '\0'; 1022 + 1023 + return buf; 1024 + } 1025 + 1026 + static const char *bus_path = "/testcase-data/overlay-node/test-bus"; 1027 + 1028 + static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr, 1029 + int *overlay_id) 1030 + { 1031 + struct device_node *np = NULL; 1032 + int ret, id = -1; 1033 + 1034 + np = of_find_node_by_path(overlay_path(overlay_nr)); 1035 + if (np == NULL) { 1036 + selftest(0, "could not find overlay node @\"%s\"\n", 1037 + overlay_path(overlay_nr)); 1038 + ret = -EINVAL; 1039 + goto out; 1040 + } 1041 + 1042 + ret = of_overlay_create(np); 1043 + if (ret < 0) { 1044 + selftest(0, "could not create overlay from \"%s\"\n", 1045 + overlay_path(overlay_nr)); 1046 + goto out; 1047 + } 1048 + id = ret; 1049 + 1050 + ret = 0; 1051 + 1052 + out: 1053 + of_node_put(np); 1054 + 1055 + if (overlay_id) 1056 + *overlay_id = id; 1057 + 1058 + return ret; 1059 + } 1060 + 1061 + /* apply an overlay while checking before and after states */ 1062 + static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr, 1063 + int before, int after) 1064 + { 1065 + int ret; 1066 + 1067 + /* selftest device must not be in before state */ 1068 + if (of_path_platform_device_exists(selftest_path(selftest_nr)) 1069 + != before) { 1070 + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1071 + overlay_path(overlay_nr), 1072 + selftest_path(selftest_nr), 1073 + !before ? "enabled" : "disabled"); 1074 + return -EINVAL; 1075 + } 1076 + 1077 + ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL); 1078 + if (ret != 0) { 1079 + /* of_selftest_apply_overlay already called selftest() */ 1080 + return ret; 1081 + } 1082 + 1083 + /* selftest device must be to set to after state */ 1084 + if (of_path_platform_device_exists(selftest_path(selftest_nr)) 1085 + != after) { 1086 + selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", 1087 + overlay_path(overlay_nr), 1088 + selftest_path(selftest_nr), 1089 + !after ? "enabled" : "disabled"); 1090 + return -EINVAL; 1091 + } 1092 + 1093 + return 0; 1094 + } 1095 + 1096 + /* apply an overlay and then revert it while checking before, after states */ 1097 + static int of_selftest_apply_revert_overlay_check(int overlay_nr, 1098 + int selftest_nr, int before, int after) 1099 + { 1100 + int ret, ov_id; 1101 + 1102 + /* selftest device must be in before state */ 1103 + if (of_path_platform_device_exists(selftest_path(selftest_nr)) 1104 + != before) { 1105 + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1106 + overlay_path(overlay_nr), 1107 + selftest_path(selftest_nr), 1108 + !before ? "enabled" : "disabled"); 1109 + return -EINVAL; 1110 + } 1111 + 1112 + /* apply the overlay */ 1113 + ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id); 1114 + if (ret != 0) { 1115 + /* of_selftest_apply_overlay already called selftest() */ 1116 + return ret; 1117 + } 1118 + 1119 + /* selftest device must be in after state */ 1120 + if (of_path_platform_device_exists(selftest_path(selftest_nr)) 1121 + != after) { 1122 + selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", 1123 + overlay_path(overlay_nr), 1124 + selftest_path(selftest_nr), 1125 + !after ? "enabled" : "disabled"); 1126 + return -EINVAL; 1127 + } 1128 + 1129 + ret = of_overlay_destroy(ov_id); 1130 + if (ret != 0) { 1131 + selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", 1132 + overlay_path(overlay_nr), 1133 + selftest_path(selftest_nr)); 1134 + return ret; 1135 + } 1136 + 1137 + /* selftest device must be again in before state */ 1138 + if (of_path_platform_device_exists(selftest_path(selftest_nr)) 1139 + != before) { 1140 + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1141 + overlay_path(overlay_nr), 1142 + selftest_path(selftest_nr), 1143 + !before ? "enabled" : "disabled"); 1144 + return -EINVAL; 1145 + } 1146 + 1147 + return 0; 1148 + } 1149 + 1150 + /* test activation of device */ 1151 + static void of_selftest_overlay_0(void) 1152 + { 1153 + int ret; 1154 + 1155 + /* device should enable */ 1156 + ret = of_selftest_apply_overlay_check(0, 0, 0, 1); 1157 + if (ret != 0) 1158 + return; 1159 + 1160 + selftest(1, "overlay test %d passed\n", 0); 1161 + } 1162 + 1163 + /* test deactivation of device */ 1164 + static void of_selftest_overlay_1(void) 1165 + { 1166 + int ret; 1167 + 1168 + /* device should disable */ 1169 + ret = of_selftest_apply_overlay_check(1, 1, 1, 0); 1170 + if (ret != 0) 1171 + return; 1172 + 1173 + selftest(1, "overlay test %d passed\n", 1); 1174 + } 1175 + 1176 + /* test activation of device */ 1177 + static void of_selftest_overlay_2(void) 1178 + { 1179 + int ret; 1180 + 1181 + /* device should enable */ 1182 + ret = of_selftest_apply_overlay_check(2, 2, 0, 1); 1183 + if (ret != 0) 1184 + return; 1185 + 1186 + selftest(1, "overlay test %d passed\n", 2); 1187 + } 1188 + 1189 + /* test deactivation of device */ 1190 + static void of_selftest_overlay_3(void) 1191 + { 1192 + int ret; 1193 + 1194 + /* device should disable */ 1195 + ret = of_selftest_apply_overlay_check(3, 3, 1, 0); 1196 + if (ret != 0) 1197 + return; 1198 + 1199 + selftest(1, "overlay test %d passed\n", 3); 1200 + } 1201 + 1202 + /* test activation of a full device node */ 1203 + static void of_selftest_overlay_4(void) 1204 + { 1205 + int ret; 1206 + 1207 + /* device should disable */ 1208 + ret = of_selftest_apply_overlay_check(4, 4, 0, 1); 1209 + if (ret != 0) 1210 + return; 1211 + 1212 + selftest(1, "overlay test %d passed\n", 4); 1213 + } 1214 + 1215 + /* test overlay apply/revert sequence */ 1216 + static void of_selftest_overlay_5(void) 1217 + { 1218 + int ret; 1219 + 1220 + /* device should disable */ 1221 + ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1); 1222 + if (ret != 0) 1223 + return; 1224 + 1225 + selftest(1, "overlay test %d passed\n", 5); 1226 + } 1227 + 1228 + /* test overlay application in sequence */ 1229 + static void of_selftest_overlay_6(void) 1230 + { 1231 + struct device_node *np; 1232 + int ret, i, ov_id[2]; 1233 + int overlay_nr = 6, selftest_nr = 6; 1234 + int before = 0, after = 1; 1235 + 1236 + /* selftest device must be in before state */ 1237 + for (i = 0; i < 2; i++) { 1238 + if (of_path_platform_device_exists( 1239 + selftest_path(selftest_nr + i)) 1240 + != before) { 1241 + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1242 + overlay_path(overlay_nr + i), 1243 + selftest_path(selftest_nr + i), 1244 + !before ? "enabled" : "disabled"); 1245 + return; 1246 + } 1247 + } 1248 + 1249 + /* apply the overlays */ 1250 + for (i = 0; i < 2; i++) { 1251 + 1252 + np = of_find_node_by_path(overlay_path(overlay_nr + i)); 1253 + if (np == NULL) { 1254 + selftest(0, "could not find overlay node @\"%s\"\n", 1255 + overlay_path(overlay_nr + i)); 1256 + return; 1257 + } 1258 + 1259 + ret = of_overlay_create(np); 1260 + if (ret < 0) { 1261 + selftest(0, "could not create overlay from \"%s\"\n", 1262 + overlay_path(overlay_nr + i)); 1263 + return; 1264 + } 1265 + ov_id[i] = ret; 1266 + } 1267 + 1268 + for (i = 0; i < 2; i++) { 1269 + /* selftest device must be in after state */ 1270 + if (of_path_platform_device_exists( 1271 + selftest_path(selftest_nr + i)) 1272 + != after) { 1273 + selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n", 1274 + overlay_path(overlay_nr + i), 1275 + selftest_path(selftest_nr + i), 1276 + !after ? "enabled" : "disabled"); 1277 + return; 1278 + } 1279 + } 1280 + 1281 + for (i = 1; i >= 0; i--) { 1282 + ret = of_overlay_destroy(ov_id[i]); 1283 + if (ret != 0) { 1284 + selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", 1285 + overlay_path(overlay_nr + i), 1286 + selftest_path(selftest_nr + i)); 1287 + return; 1288 + } 1289 + } 1290 + 1291 + for (i = 0; i < 2; i++) { 1292 + /* selftest device must be again in before state */ 1293 + if (of_path_platform_device_exists( 1294 + selftest_path(selftest_nr + i)) 1295 + != before) { 1296 + selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", 1297 + overlay_path(overlay_nr + i), 1298 + selftest_path(selftest_nr + i), 1299 + !before ? "enabled" : "disabled"); 1300 + return; 1301 + } 1302 + } 1303 + 1304 + selftest(1, "overlay test %d passed\n", 6); 1305 + } 1306 + 1307 + /* test overlay application in sequence */ 1308 + static void of_selftest_overlay_8(void) 1309 + { 1310 + struct device_node *np; 1311 + int ret, i, ov_id[2]; 1312 + int overlay_nr = 8, selftest_nr = 8; 1313 + 1314 + /* we don't care about device state in this test */ 1315 + 1316 + /* apply the overlays */ 1317 + for (i = 0; i < 2; i++) { 1318 + 1319 + np = of_find_node_by_path(overlay_path(overlay_nr + i)); 1320 + if (np == NULL) { 1321 + selftest(0, "could not find overlay node @\"%s\"\n", 1322 + overlay_path(overlay_nr + i)); 1323 + return; 1324 + } 1325 + 1326 + ret = of_overlay_create(np); 1327 + if (ret < 0) { 1328 + selftest(0, "could not create overlay from \"%s\"\n", 1329 + overlay_path(overlay_nr + i)); 1330 + return; 1331 + } 1332 + ov_id[i] = ret; 1333 + } 1334 + 1335 + /* now try to remove first overlay (it should fail) */ 1336 + ret = of_overlay_destroy(ov_id[0]); 1337 + if (ret == 0) { 1338 + selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", 1339 + overlay_path(overlay_nr + 0), 1340 + selftest_path(selftest_nr)); 1341 + return; 1342 + } 1343 + 1344 + /* removing them in order should work */ 1345 + for (i = 1; i >= 0; i--) { 1346 + ret = of_overlay_destroy(ov_id[i]); 1347 + if (ret != 0) { 1348 + selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", 1349 + overlay_path(overlay_nr + i), 1350 + selftest_path(selftest_nr)); 1351 + return; 1352 + } 1353 + } 1354 + 1355 + selftest(1, "overlay test %d passed\n", 8); 1356 + } 1357 + 1358 + static void __init of_selftest_overlay(void) 1359 + { 1360 + struct device_node *bus_np = NULL; 1361 + int ret; 1362 + 1363 + ret = platform_driver_register(&selftest_driver); 1364 + if (ret != 0) { 1365 + selftest(0, "could not register selftest driver\n"); 1366 + goto out; 1367 + } 1368 + 1369 + bus_np = of_find_node_by_path(bus_path); 1370 + if (bus_np == NULL) { 1371 + selftest(0, "could not find bus_path \"%s\"\n", bus_path); 1372 + goto out; 1373 + } 1374 + 1375 + ret = of_platform_populate(bus_np, of_default_bus_match_table, 1376 + NULL, NULL); 1377 + if (ret != 0) { 1378 + selftest(0, "could not populate bus @ \"%s\"\n", bus_path); 1379 + goto out; 1380 + } 1381 + 1382 + if (!of_path_platform_device_exists(selftest_path(100))) { 1383 + selftest(0, "could not find selftest0 @ \"%s\"\n", 1384 + selftest_path(100)); 1385 + goto out; 1386 + } 1387 + 1388 + if (of_path_platform_device_exists(selftest_path(101))) { 1389 + selftest(0, "selftest1 @ \"%s\" should not exist\n", 1390 + selftest_path(101)); 1391 + goto out; 1392 + } 1393 + 1394 + selftest(1, "basic infrastructure of overlays passed"); 1395 + 1396 + /* tests in sequence */ 1397 + of_selftest_overlay_0(); 1398 + of_selftest_overlay_1(); 1399 + of_selftest_overlay_2(); 1400 + of_selftest_overlay_3(); 1401 + of_selftest_overlay_4(); 1402 + of_selftest_overlay_5(); 1403 + of_selftest_overlay_6(); 1404 + of_selftest_overlay_8(); 1405 + 1406 + out: 1407 + of_node_put(bus_np); 1408 + } 1409 + 1410 + #else 1411 + static inline void __init of_selftest_overlay(void) { } 1412 + #endif 1413 + 938 1414 static int __init of_selftest(void) 939 1415 { 940 1416 struct device_node *np; ··· 1445 965 of_selftest_parse_interrupts_extended(); 1446 966 of_selftest_match_node(); 1447 967 of_selftest_platform_populate(); 968 + of_selftest_overlay(); 1448 969 1449 970 /* removing selftest data from live tree */ 1450 971 selftest_data_remove();