aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-10-28 16:35:59 -0400
committerGrant Likely <grant.likely@linaro.org>2014-11-24 17:25:13 -0500
commit177d271cf3171bb6826ee5189f67dc1f7d34f1da (patch)
tree05e92739348fcd566c6a602070485766fcd0cb49
parent7518b5890d8ac366faa2326ce2356ef6392ce63d (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/unittest.txt14
-rw-r--r--drivers/of/unittest-data/testcases.dts16
-rw-r--r--drivers/of/unittest-data/tests-overlay.dtsi180
-rw-r--r--drivers/of/unittest.c481
4 files changed, 691 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/unittest.txt b/Documentation/devicetree/bindings/unittest.txt
new file mode 100644
index 000000000000..0f92a22fddfa
--- /dev/null
+++ b/Documentation/devicetree/bindings/unittest.txt
@@ -0,0 +1,14 @@
1* OF selftest platform device
2
3** selftest
4
5Required properties:
6- compatible: must be "selftest"
7
8All other properties are optional.
9
10Example:
11 selftest {
12 compatible = "selftest";
13 status = "okay";
14 };
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
index b6bc41b2a185..12f7c3d649c8 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dts
@@ -13,6 +13,7 @@
13#include "tests-interrupts.dtsi" 13#include "tests-interrupts.dtsi"
14#include "tests-match.dtsi" 14#include "tests-match.dtsi"
15#include "tests-platform.dtsi" 15#include "tests-platform.dtsi"
16#include "tests-overlay.dtsi"
16 17
17/* 18/*
18 * phandle fixup data - generated by dtc patches that aren't upstream. 19 * phandle fixup data - generated by dtc patches that aren't upstream.
@@ -59,5 +60,20 @@
59 testcase-device2 { 60 testcase-device2 {
60 interrupt-parent = <0x00000000>; 61 interrupt-parent = <0x00000000>;
61 }; 62 };
63 overlay2 {
64 fragment@0 {
65 target = <0x00000000>;
66 };
67 };
68 overlay3 {
69 fragment@0 {
70 target = <0x00000000>;
71 };
72 };
73 overlay4 {
74 fragment@0 {
75 target = <0x00000000>;
76 };
77 };
62 }; 78 };
63}; }; 79}; };
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
new file mode 100644
index 000000000000..75976da22b2e
--- /dev/null
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -0,0 +1,180 @@
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};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 1720b039cac7..cc0c5ec5d464 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -17,6 +17,8 @@
17#include <linux/mutex.h> 17#include <linux/mutex.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/of_platform.h>
20 22
21#include "of_private.h" 23#include "of_private.h"
22 24
@@ -933,6 +935,484 @@ static void selftest_data_remove(void)
933 } 935 }
934} 936}
935 937
938#ifdef CONFIG_OF_OVERLAY
939
940static int selftest_probe(struct platform_device *pdev)
941{
942 struct device *dev = &pdev->dev;
943 struct device_node *np = dev->of_node;
944
945 if (np == NULL) {
946 dev_err(dev, "No OF data for device\n");
947 return -EINVAL;
948
949 }
950
951 dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
952 return 0;
953}
954
955static int selftest_remove(struct platform_device *pdev)
956{
957 struct device *dev = &pdev->dev;
958 struct device_node *np = dev->of_node;
959
960 dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
961 return 0;
962}
963
964static struct of_device_id selftest_match[] = {
965 { .compatible = "selftest", },
966 {},
967};
968MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
969
970static struct platform_driver selftest_driver = {
971 .probe = selftest_probe,
972 .remove = selftest_remove,
973 .driver = {
974 .name = "selftest",
975 .owner = THIS_MODULE,
976 .of_match_table = of_match_ptr(selftest_match),
977 },
978};
979
980/* get the platform device instantiated at the path */
981static struct platform_device *of_path_to_platform_device(const char *path)
982{
983 struct device_node *np;
984 struct platform_device *pdev;
985
986 np = of_find_node_by_path(path);
987 if (np == NULL)
988 return NULL;
989
990 pdev = of_find_device_by_node(np);
991 of_node_put(np);
992
993 return pdev;
994}
995
996/* find out if a platform device exists at that path */
997static int of_path_platform_device_exists(const char *path)
998{
999 struct platform_device *pdev;
1000
1001 pdev = of_path_to_platform_device(path);
1002 platform_device_put(pdev);
1003 return pdev != NULL;
1004}
1005
1006static const char *selftest_path(int nr)
1007{
1008 static char buf[256];
1009
1010 snprintf(buf, sizeof(buf) - 1,
1011 "/testcase-data/overlay-node/test-bus/test-selftest%d", nr);
1012 buf[sizeof(buf) - 1] = '\0';
1013
1014 return buf;
1015}
1016
1017static const char *overlay_path(int nr)
1018{
1019 static char buf[256];
1020
1021 snprintf(buf, sizeof(buf) - 1,
1022 "/testcase-data/overlay%d", nr);
1023 buf[sizeof(buf) - 1] = '\0';
1024
1025 return buf;
1026}
1027
1028static const char *bus_path = "/testcase-data/overlay-node/test-bus";
1029
1030static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
1031 int *overlay_id)
1032{
1033 struct device_node *np = NULL;
1034 int ret, id = -1;
1035
1036 np = of_find_node_by_path(overlay_path(overlay_nr));
1037 if (np == NULL) {
1038 selftest(0, "could not find overlay node @\"%s\"\n",
1039 overlay_path(overlay_nr));
1040 ret = -EINVAL;
1041 goto out;
1042 }
1043
1044 ret = of_overlay_create(np);
1045 if (ret < 0) {
1046 selftest(0, "could not create overlay from \"%s\"\n",
1047 overlay_path(overlay_nr));
1048 goto out;
1049 }
1050 id = ret;
1051
1052 ret = 0;
1053
1054out:
1055 of_node_put(np);
1056
1057 if (overlay_id)
1058 *overlay_id = id;
1059
1060 return ret;
1061}
1062
1063/* apply an overlay while checking before and after states */
1064static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
1065 int before, int after)
1066{
1067 int ret;
1068
1069 /* selftest device must not be in before state */
1070 if (of_path_platform_device_exists(selftest_path(selftest_nr))
1071 != before) {
1072 selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
1073 overlay_path(overlay_nr),
1074 selftest_path(selftest_nr),
1075 !before ? "enabled" : "disabled");
1076 return -EINVAL;
1077 }
1078
1079 ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL);
1080 if (ret != 0) {
1081 /* of_selftest_apply_overlay already called selftest() */
1082 return ret;
1083 }
1084
1085 /* selftest device must be to set to after state */
1086 if (of_path_platform_device_exists(selftest_path(selftest_nr))
1087 != after) {
1088 selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
1089 overlay_path(overlay_nr),
1090 selftest_path(selftest_nr),
1091 !after ? "enabled" : "disabled");
1092 return -EINVAL;
1093 }
1094
1095 return 0;
1096}
1097
1098/* apply an overlay and then revert it while checking before, after states */
1099static int of_selftest_apply_revert_overlay_check(int overlay_nr,
1100 int selftest_nr, int before, int after)
1101{
1102 int ret, ov_id;
1103
1104 /* selftest device must be in before state */
1105 if (of_path_platform_device_exists(selftest_path(selftest_nr))
1106 != before) {
1107 selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
1108 overlay_path(overlay_nr),
1109 selftest_path(selftest_nr),
1110 !before ? "enabled" : "disabled");
1111 return -EINVAL;
1112 }
1113
1114 /* apply the overlay */
1115 ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id);
1116 if (ret != 0) {
1117 /* of_selftest_apply_overlay already called selftest() */
1118 return ret;
1119 }
1120
1121 /* selftest device must be in after state */
1122 if (of_path_platform_device_exists(selftest_path(selftest_nr))
1123 != after) {
1124 selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
1125 overlay_path(overlay_nr),
1126 selftest_path(selftest_nr),
1127 !after ? "enabled" : "disabled");
1128 return -EINVAL;
1129 }
1130
1131 ret = of_overlay_destroy(ov_id);
1132 if (ret != 0) {
1133 selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
1134 overlay_path(overlay_nr),
1135 selftest_path(selftest_nr));
1136 return ret;
1137 }
1138
1139 /* selftest device must be again in before state */
1140 if (of_path_platform_device_exists(selftest_path(selftest_nr))
1141 != before) {
1142 selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
1143 overlay_path(overlay_nr),
1144 selftest_path(selftest_nr),
1145 !before ? "enabled" : "disabled");
1146 return -EINVAL;
1147 }
1148
1149 return 0;
1150}
1151
1152/* test activation of device */
1153static void of_selftest_overlay_0(void)
1154{
1155 int ret;
1156
1157 /* device should enable */
1158 ret = of_selftest_apply_overlay_check(0, 0, 0, 1);
1159 if (ret != 0)
1160 return;
1161
1162 selftest(1, "overlay test %d passed\n", 0);
1163}
1164
1165/* test deactivation of device */
1166static void of_selftest_overlay_1(void)
1167{
1168 int ret;
1169
1170 /* device should disable */
1171 ret = of_selftest_apply_overlay_check(1, 1, 1, 0);
1172 if (ret != 0)
1173 return;
1174
1175 selftest(1, "overlay test %d passed\n", 1);
1176}
1177
1178/* test activation of device */
1179static void of_selftest_overlay_2(void)
1180{
1181 int ret;
1182
1183 /* device should enable */
1184 ret = of_selftest_apply_overlay_check(2, 2, 0, 1);
1185 if (ret != 0)
1186 return;
1187
1188 selftest(1, "overlay test %d passed\n", 2);
1189}
1190
1191/* test deactivation of device */
1192static void of_selftest_overlay_3(void)
1193{
1194 int ret;
1195
1196 /* device should disable */
1197 ret = of_selftest_apply_overlay_check(3, 3, 1, 0);
1198 if (ret != 0)
1199 return;
1200
1201 selftest(1, "overlay test %d passed\n", 3);
1202}
1203
1204/* test activation of a full device node */
1205static void of_selftest_overlay_4(void)
1206{
1207 int ret;
1208
1209 /* device should disable */
1210 ret = of_selftest_apply_overlay_check(4, 4, 0, 1);
1211 if (ret != 0)
1212 return;
1213
1214 selftest(1, "overlay test %d passed\n", 4);
1215}
1216
1217/* test overlay apply/revert sequence */
1218static void of_selftest_overlay_5(void)
1219{
1220 int ret;
1221
1222 /* device should disable */
1223 ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1);
1224 if (ret != 0)
1225 return;
1226
1227 selftest(1, "overlay test %d passed\n", 5);
1228}
1229
1230/* test overlay application in sequence */
1231static void of_selftest_overlay_6(void)
1232{
1233 struct device_node *np;
1234 int ret, i, ov_id[2];
1235 int overlay_nr = 6, selftest_nr = 6;
1236 int before = 0, after = 1;
1237
1238 /* selftest device must be in before state */
1239 for (i = 0; i < 2; i++) {
1240 if (of_path_platform_device_exists(
1241 selftest_path(selftest_nr + i))
1242 != before) {
1243 selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
1244 overlay_path(overlay_nr + i),
1245 selftest_path(selftest_nr + i),
1246 !before ? "enabled" : "disabled");
1247 return;
1248 }
1249 }
1250
1251 /* apply the overlays */
1252 for (i = 0; i < 2; i++) {
1253
1254 np = of_find_node_by_path(overlay_path(overlay_nr + i));
1255 if (np == NULL) {
1256 selftest(0, "could not find overlay node @\"%s\"\n",
1257 overlay_path(overlay_nr + i));
1258 return;
1259 }
1260
1261 ret = of_overlay_create(np);
1262 if (ret < 0) {
1263 selftest(0, "could not create overlay from \"%s\"\n",
1264 overlay_path(overlay_nr + i));
1265 return;
1266 }
1267 ov_id[i] = ret;
1268 }
1269
1270 for (i = 0; i < 2; i++) {
1271 /* selftest device must be in after state */
1272 if (of_path_platform_device_exists(
1273 selftest_path(selftest_nr + i))
1274 != after) {
1275 selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
1276 overlay_path(overlay_nr + i),
1277 selftest_path(selftest_nr + i),
1278 !after ? "enabled" : "disabled");
1279 return;
1280 }
1281 }
1282
1283 for (i = 1; i >= 0; i--) {
1284 ret = of_overlay_destroy(ov_id[i]);
1285 if (ret != 0) {
1286 selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
1287 overlay_path(overlay_nr + i),
1288 selftest_path(selftest_nr + i));
1289 return;
1290 }
1291 }
1292
1293 for (i = 0; i < 2; i++) {
1294 /* selftest device must be again in before state */
1295 if (of_path_platform_device_exists(
1296 selftest_path(selftest_nr + i))
1297 != before) {
1298 selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
1299 overlay_path(overlay_nr + i),
1300 selftest_path(selftest_nr + i),
1301 !before ? "enabled" : "disabled");
1302 return;
1303 }
1304 }
1305
1306 selftest(1, "overlay test %d passed\n", 6);
1307}
1308
1309/* test overlay application in sequence */
1310static void of_selftest_overlay_8(void)
1311{
1312 struct device_node *np;
1313 int ret, i, ov_id[2];
1314 int overlay_nr = 8, selftest_nr = 8;
1315
1316 /* we don't care about device state in this test */
1317
1318 /* apply the overlays */
1319 for (i = 0; i < 2; i++) {
1320
1321 np = of_find_node_by_path(overlay_path(overlay_nr + i));
1322 if (np == NULL) {
1323 selftest(0, "could not find overlay node @\"%s\"\n",
1324 overlay_path(overlay_nr + i));
1325 return;
1326 }
1327
1328 ret = of_overlay_create(np);
1329 if (ret < 0) {
1330 selftest(0, "could not create overlay from \"%s\"\n",
1331 overlay_path(overlay_nr + i));
1332 return;
1333 }
1334 ov_id[i] = ret;
1335 }
1336
1337 /* now try to remove first overlay (it should fail) */
1338 ret = of_overlay_destroy(ov_id[0]);
1339 if (ret == 0) {
1340 selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
1341 overlay_path(overlay_nr + 0),
1342 selftest_path(selftest_nr));
1343 return;
1344 }
1345
1346 /* removing them in order should work */
1347 for (i = 1; i >= 0; i--) {
1348 ret = of_overlay_destroy(ov_id[i]);
1349 if (ret != 0) {
1350 selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
1351 overlay_path(overlay_nr + i),
1352 selftest_path(selftest_nr));
1353 return;
1354 }
1355 }
1356
1357 selftest(1, "overlay test %d passed\n", 8);
1358}
1359
1360static void __init of_selftest_overlay(void)
1361{
1362 struct device_node *bus_np = NULL;
1363 int ret;
1364
1365 ret = platform_driver_register(&selftest_driver);
1366 if (ret != 0) {
1367 selftest(0, "could not register selftest driver\n");
1368 goto out;
1369 }
1370
1371 bus_np = of_find_node_by_path(bus_path);
1372 if (bus_np == NULL) {
1373 selftest(0, "could not find bus_path \"%s\"\n", bus_path);
1374 goto out;
1375 }
1376
1377 ret = of_platform_populate(bus_np, of_default_bus_match_table,
1378 NULL, NULL);
1379 if (ret != 0) {
1380 selftest(0, "could not populate bus @ \"%s\"\n", bus_path);
1381 goto out;
1382 }
1383
1384 if (!of_path_platform_device_exists(selftest_path(100))) {
1385 selftest(0, "could not find selftest0 @ \"%s\"\n",
1386 selftest_path(100));
1387 goto out;
1388 }
1389
1390 if (of_path_platform_device_exists(selftest_path(101))) {
1391 selftest(0, "selftest1 @ \"%s\" should not exist\n",
1392 selftest_path(101));
1393 goto out;
1394 }
1395
1396 selftest(1, "basic infrastructure of overlays passed");
1397
1398 /* tests in sequence */
1399 of_selftest_overlay_0();
1400 of_selftest_overlay_1();
1401 of_selftest_overlay_2();
1402 of_selftest_overlay_3();
1403 of_selftest_overlay_4();
1404 of_selftest_overlay_5();
1405 of_selftest_overlay_6();
1406 of_selftest_overlay_8();
1407
1408out:
1409 of_node_put(bus_np);
1410}
1411
1412#else
1413static inline void __init of_selftest_overlay(void) { }
1414#endif
1415
936static int __init of_selftest(void) 1416static int __init of_selftest(void)
937{ 1417{
938 struct device_node *np; 1418 struct device_node *np;
@@ -965,6 +1445,7 @@ static int __init of_selftest(void)
965 of_selftest_parse_interrupts_extended(); 1445 of_selftest_parse_interrupts_extended();
966 of_selftest_match_node(); 1446 of_selftest_match_node();
967 of_selftest_platform_populate(); 1447 of_selftest_platform_populate();
1448 of_selftest_overlay();
968 1449
969 /* removing selftest data from live tree */ 1450 /* removing selftest data from live tree */
970 selftest_data_remove(); 1451 selftest_data_remove();