1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2023 Addiva Elektronik
4  * Author: Tobias Waldekranz <tobias@waldekranz.com>
5  */
6 
7 #include <blk.h>
8 #include <blkmap.h>
9 #include <dm.h>
10 #include <env.h>
11 #include <asm/test.h>
12 #include <dm/test.h>
13 #include <test/test.h>
14 #include <test/ut.h>
15 
16 #define BLKSZ 0x200
17 
18 struct mapping {
19 	int src;
20 	int cnt;
21 	int dst;
22 };
23 
24 const struct mapping unordered_mapping[] = {
25 	{ 0, 1, 3 },
26 	{ 1, 3, 0 },
27 	{ 4, 2, 6 },
28 	{ 6, 2, 4 },
29 
30 	{ 0, 0, 0 }
31 };
32 
33 const struct mapping identity_mapping[] = {
34 	{ 0, 8, 0 },
35 
36 	{ 0, 0, 0 }
37 };
38 
39 static char identity[8 * BLKSZ];
40 static char unordered[8 * BLKSZ];
41 static char buffer[8 * BLKSZ];
42 
mkblob(void * base,const struct mapping * m)43 static void mkblob(void *base, const struct mapping *m)
44 {
45 	int nr;
46 
47 	for (; m->cnt; m++) {
48 		for (nr = 0; nr < m->cnt; nr++) {
49 			memset(base + (m->dst + nr) * BLKSZ,
50 			       m->src + nr, BLKSZ);
51 		}
52 	}
53 }
54 
dm_test_blkmap_read(struct unit_test_state * uts)55 static int dm_test_blkmap_read(struct unit_test_state *uts)
56 {
57 	struct udevice *dev, *blk;
58 	const struct mapping *m;
59 
60 	ut_assertok(blkmap_create("rdtest", &dev));
61 	ut_assertok(blk_get_from_parent(dev, &blk));
62 
63 	/* Generate an ordered and an unordered pattern in memory */
64 	mkblob(unordered, unordered_mapping);
65 	mkblob(identity, identity_mapping);
66 
67 	/* Create a blkmap that cancels out the disorder */
68 	for (m = unordered_mapping; m->cnt; m++) {
69 		ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
70 					   unordered + m->dst * BLKSZ));
71 	}
72 
73 	/* Read out the data via the blkmap device to another area,
74 	 * and verify that it matches the ordered pattern.
75 	 */
76 	ut_asserteq(8, blk_read(blk, 0, 8, buffer));
77 	ut_assertok(memcmp(buffer, identity, sizeof(buffer)));
78 
79 	ut_assertok(blkmap_destroy(dev));
80 	return 0;
81 }
82 DM_TEST(dm_test_blkmap_read, 0);
83 
dm_test_blkmap_write(struct unit_test_state * uts)84 static int dm_test_blkmap_write(struct unit_test_state *uts)
85 {
86 	struct udevice *dev, *blk;
87 	const struct mapping *m;
88 
89 	ut_assertok(blkmap_create("wrtest", &dev));
90 	ut_assertok(blk_get_from_parent(dev, &blk));
91 
92 	/* Generate an ordered and an unordered pattern in memory */
93 	mkblob(unordered, unordered_mapping);
94 	mkblob(identity, identity_mapping);
95 
96 	/* Create a blkmap that mimics the disorder */
97 	for (m = unordered_mapping; m->cnt; m++) {
98 		ut_assertok(blkmap_map_mem(dev, m->src, m->cnt,
99 					   buffer + m->dst * BLKSZ));
100 	}
101 
102 	/* Write the ordered data via the blkmap device to another
103 	 * area, and verify that the result matches the unordered
104 	 * pattern.
105 	 */
106 	ut_asserteq(8, blk_write(blk, 0, 8, identity));
107 	ut_assertok(memcmp(buffer, unordered, sizeof(buffer)));
108 
109 	ut_assertok(blkmap_destroy(dev));
110 	return 0;
111 }
112 DM_TEST(dm_test_blkmap_write, 0);
113 
dm_test_blkmap_slicing(struct unit_test_state * uts)114 static int dm_test_blkmap_slicing(struct unit_test_state *uts)
115 {
116 	struct udevice *dev;
117 
118 	ut_assertok(blkmap_create("slicetest", &dev));
119 
120 	ut_assertok(blkmap_map_mem(dev, 8, 8, NULL));
121 
122 	/* Can't overlap on the low end */
123 	ut_asserteq(-EBUSY, blkmap_map_mem(dev,  4, 5, NULL));
124 	/* Can't be inside */
125 	ut_asserteq(-EBUSY, blkmap_map_mem(dev, 10, 2, NULL));
126 	/* Can't overlap on the high end */
127 	ut_asserteq(-EBUSY, blkmap_map_mem(dev, 15, 4, NULL));
128 
129 	/* But we should be able to add slices right before and
130 	 * after
131 	 */
132 	ut_assertok(blkmap_map_mem(dev,  4, 4, NULL));
133 	ut_assertok(blkmap_map_mem(dev, 16, 4, NULL));
134 
135 	ut_assertok(blkmap_destroy(dev));
136 	return 0;
137 }
138 DM_TEST(dm_test_blkmap_slicing, 0);
139 
dm_test_blkmap_creation(struct unit_test_state * uts)140 static int dm_test_blkmap_creation(struct unit_test_state *uts)
141 {
142 	struct udevice *first, *second;
143 
144 	ut_assertok(blkmap_create("first", &first));
145 
146 	/* Can't have two "first"s */
147 	ut_asserteq(-EBUSY, blkmap_create("first", &second));
148 
149 	/* But "second" should be fine */
150 	ut_assertok(blkmap_create("second", &second));
151 
152 	/* Once "first" is destroyed, we should be able to create it
153 	 * again
154 	 */
155 	ut_assertok(blkmap_destroy(first));
156 	ut_assertok(blkmap_create("first", &first));
157 
158 	ut_assertok(blkmap_destroy(first));
159 	ut_assertok(blkmap_destroy(second));
160 	return 0;
161 }
162 DM_TEST(dm_test_blkmap_creation, 0);
163 
dm_test_cmd_blkmap(struct unit_test_state * uts)164 static int dm_test_cmd_blkmap(struct unit_test_state *uts)
165 {
166 	ulong loadaddr = env_get_hex("loadaddr", 0);
167 	struct udevice *dev;
168 
169 	ut_assertok(run_command("blkmap info", 0));
170 	ut_assert_console_end();
171 
172 	ut_assertok(run_command("blkmap create ramdisk", 0));
173 	ut_assert_nextline("Created \"ramdisk\"");
174 	ut_assert_console_end();
175 
176 	ut_assertnonnull((dev = blkmap_from_label("ramdisk")));
177 
178 	ut_assertok(run_commandf("blkmap map ramdisk 0 800 mem 0x%lx", loadaddr));
179 	ut_assert_nextline("Block 0x0+0x800 mapped to 0x%lx", loadaddr);
180 	ut_assert_console_end();
181 
182 	ut_assertok(run_command("blkmap info", 0));
183 	ut_assert_nextline("Device 0: Vendor: U-Boot Rev: 1.0 Prod: blkmap");
184 	ut_assert_nextline("            Type: Hard Disk");
185 	ut_assert_nextline("            Capacity: 1.0 MB = 0.0 GB (2048 x 512)");
186 	ut_assert_console_end();
187 
188 	ut_assertok(run_command("blkmap get ramdisk dev devnum", 0));
189 	ut_asserteq(dev_seq(dev), env_get_hex("devnum", 0xdeadbeef));
190 
191 	ut_assertok(run_command("blkmap destroy ramdisk", 0));
192 	ut_assert_nextline("Destroyed \"ramdisk\"");
193 	ut_assert_console_end();
194 
195 	ut_assertok(run_command("blkmap info", 0));
196 	ut_assert_console_end();
197 	return 0;
198 }
199 DM_TEST(dm_test_cmd_blkmap, UTF_CONSOLE);
200