summaryrefslogtreecommitdiffstats
path: root/userspace
diff options
context:
space:
mode:
authorNicolas Benech <nbenech@nvidia.com>2018-06-27 17:45:31 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-24 18:52:34 -0400
commit5c7a740403fe5b65149b8b30d1007fd02b33c890 (patch)
treef6d37e9668f62fd2debb334ed1ac13e104c7cdc9 /userspace
parent127aa9735b07a2613bdbcfedbf741e44cf99ee9e (diff)
gpu: nvgpu: unit: Add mockio unit test
Add a unit test to make sure the posix IO mocking works corretly. JIRA NVGPU-1040 Change-Id: Iadec2f515c9dd74dc0723885b3a6560dc91ce052 Signed-off-by: Nicolas Benech <nbenech@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1741954 Reviewed-by: svc-misra-checker <svc-misra-checker@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-by: Alex Waterman <alexw@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'userspace')
-rw-r--r--userspace/Makefile.sources3
-rw-r--r--userspace/units/posix-mockio/Makefile26
-rw-r--r--userspace/units/posix-mockio/posix-mockio.c338
3 files changed, 366 insertions, 1 deletions
diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources
index c0f9124f..a7b89cfe 100644
--- a/userspace/Makefile.sources
+++ b/userspace/Makefile.sources
@@ -48,7 +48,8 @@ CORE_HEADERS := \
48# Each directory under the UNIT_SRC directory should correspond to one module. 48# Each directory under the UNIT_SRC directory should correspond to one module.
49UNITS := \ 49UNITS := \
50 $(UNIT_SRC)/posix-env \ 50 $(UNIT_SRC)/posix-env \
51 $(UNIT_SRC)/posix-bitops 51 $(UNIT_SRC)/posix-bitops \
52 $(UNIT_SRC)/posix-mockio
52 53
53# A test unit. Not really needed any more... 54# A test unit. Not really needed any more...
54# $(UNIT_SRC)/test 55# $(UNIT_SRC)/test
diff --git a/userspace/units/posix-mockio/Makefile b/userspace/units/posix-mockio/Makefile
new file mode 100644
index 00000000..f247ad0f
--- /dev/null
+++ b/userspace/units/posix-mockio/Makefile
@@ -0,0 +1,26 @@
1# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the "Software"),
5# to deal in the Software without restriction, including without limitation
6# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7# and/or sell copies of the Software, and to permit persons to whom the
8# Software is furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included in
11# all copies or substantial portions of the Software.
12#
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19# DEALINGS IN THE SOFTWARE.
20
21.SUFFIXES:
22
23OBJS = posix-mockio.o
24MODULE = posix-mockio
25
26include ../Makefile.units
diff --git a/userspace/units/posix-mockio/posix-mockio.c b/userspace/units/posix-mockio/posix-mockio.c
new file mode 100644
index 00000000..334905bb
--- /dev/null
+++ b/userspace/units/posix-mockio/posix-mockio.c
@@ -0,0 +1,338 @@
1/*
2 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <stdlib.h>
24
25#include <unit/io.h>
26#include <unit/unit.h>
27
28#include <nvgpu/io.h>
29#include <nvgpu/io_usermode.h>
30#include <nvgpu/posix/io.h>
31
32struct writel_test_args {
33 const char *name;
34 void (*fn)(struct gk20a *, u32, u32);
35};
36
37struct readl_test_args {
38 const char *name;
39 u32 (*fn)(struct gk20a *, u32);
40};
41
42/**
43 * This is both a very simple functional test and documentation for how to use
44 * the core IO mocking API.
45 *
46 * The testing is very simple: just generate a bunch of reads and writes and
47 * check that they make it to the call back functions correctly.
48 */
49
50static struct nvgpu_reg_access mockio_access;
51
52/*
53 * List of writes to test with.
54 */
55static struct nvgpu_reg_access test_access_list[] = {
56 { 0U, 0U },
57 { ~0U, ~0U },
58 { 0x100U, 0x30U },
59 { 0x0U, 0x100U },
60 { 0x1000000U, 0x0U },
61 { 0xFFU, 0xFFU },
62 { 0x1U, 0x1U },
63 { 0x10U, 0x30U },
64};
65
66/*
67 * The *writel*() access functions copy the incoming write into our own
68 * access info. That way one can do the following:
69 *
70 * nvgpu_writel(g, reg, val);
71 *
72 * And then:
73 *
74 * do_something_with(writel_access.addr, writel_access.value);
75 *
76 * No bounds checking is performed by the mock API so that's up to you.
77 * Higher level APIs may do this.
78 */
79static void writel_access_fn(struct gk20a *g,
80 struct nvgpu_reg_access *access)
81{
82 memcpy(&mockio_access, access, sizeof(mockio_access));
83}
84
85/*
86 * Reads are handled by simply passing back a value. Exactly the opposite as the
87 * write APIs.
88 */
89static void readl_access_fn(struct gk20a *g,
90 struct nvgpu_reg_access *access)
91{
92 /*
93 * The mock API checks that the returned address is actually the same as
94 * the requested address. If it mismatches then the mock IO API returns
95 * 0x0 to the nvgpu caller.
96 */
97 memcpy(access, &mockio_access, sizeof(mockio_access));
98}
99
100static struct nvgpu_posix_io_callbacks test_callbacks = {
101 /* Write APIs all can use the same accessor. */
102 .writel = writel_access_fn,
103 .writel_check = writel_access_fn,
104 .bar1_writel = writel_access_fn,
105 .usermode_writel = writel_access_fn,
106
107 /* Likewise for the read APIs. */
108 .__readl = readl_access_fn,
109 .readl = readl_access_fn,
110 .bar1_readl = readl_access_fn,
111};
112
113static int test_register_io_callbacks(struct unit_module *m, struct gk20a *g,
114 void *__args)
115{
116 nvgpu_posix_register_io(g, &test_callbacks);
117
118 return UNIT_SUCCESS;
119}
120
121static int test_writel(struct unit_module *m, struct gk20a *g, void *__args)
122{
123 unsigned int i;
124 struct nvgpu_reg_access *a;
125 struct writel_test_args *args = __args;
126
127 for (i = 0;
128 i < sizeof(test_access_list) / sizeof(test_access_list[0]);
129 i++) {
130 a = &test_access_list[i];
131
132 memset(&mockio_access, 0, sizeof(mockio_access));
133
134 args->fn(g, a->addr, a->value);
135
136 if (mockio_access.addr != a->addr ||
137 mockio_access.value != a->value) {
138 unit_return_fail(m, "%s() mismatch!\n", args->name);
139 }
140 }
141
142 return UNIT_SUCCESS;
143}
144
145static int test_readl(struct unit_module *m, struct gk20a *g, void *__args)
146{
147 unsigned int i;
148 struct nvgpu_reg_access *a;
149 struct readl_test_args *args = __args;
150
151 for (i = 0;
152 i < sizeof(test_access_list) / sizeof(test_access_list[0]);
153 i++) {
154 u32 ret;
155
156 a = &test_access_list[i];
157 memcpy(&mockio_access, a, sizeof(mockio_access));
158
159 ret = args->fn(g, a->value);
160
161 if (ret != a->value) {
162 unit_return_fail(m, "%s() mismatch!\n", args->name);
163 }
164 }
165
166 return UNIT_SUCCESS;
167}
168
169struct writel_test_args nvgpu_writel_args = {
170 .name = "nvgpu_writel",
171 .fn = nvgpu_writel
172};
173
174struct writel_test_args nvgpu_writel_check_args = {
175 .name = "nvgpu_writel_check",
176 .fn = nvgpu_writel_check
177};
178
179struct writel_test_args nvgpu_bar1_writel_args = {
180 .name = "nvgpu_bar1_writel",
181 .fn = nvgpu_bar1_writel
182};
183
184struct writel_test_args nvgpu_usermode_writel_args = {
185 .name = "nvgpu_usermode_writel",
186 .fn = nvgpu_usermode_writel
187};
188
189struct readl_test_args nvgpu_readl_args = {
190 .name = "nvgpu_readl",
191 .fn = nvgpu_readl
192};
193
194struct readl_test_args __nvgpu_readl_args = {
195 .name = "__nvgpu_readl",
196 .fn = __nvgpu_readl
197};
198
199struct readl_test_args nvgpu_bar1_readl_args = {
200 .name = "nvgpu_bar1_readl",
201 .fn = nvgpu_bar1_readl
202};
203
204/*
205 * Typical example of a write callback. At the very least the callback
206 * should forward the write access to the mock IO framework and also
207 * call the API to record transactions. This function would be a great
208 * place to add test logic to run at every register write.
209 */
210static void writel_access_reg_fn(struct gk20a *g,
211 struct nvgpu_reg_access *access)
212{
213 nvgpu_posix_io_writel_reg_space(g, access->addr, access->value);
214 nvgpu_posix_io_record_access(g, access);
215}
216
217/*
218 * Example of a read callback. At the very least the callback should
219 * get the register value from the mock IO framework. You could also add
220 * some test logic to run at every register read.
221 */
222static void readl_access_reg_fn(struct gk20a *g,
223 struct nvgpu_reg_access *access)
224{
225 access->value = nvgpu_posix_io_readl_reg_space(g, access->addr);
226}
227
228/*
229 * Define all the callbacks to be used during the test. Typically all
230 * write operations use the same callback, likewise for all read operations.
231 */
232static struct nvgpu_posix_io_callbacks test_reg_callbacks = {
233 /* Write APIs all can use the same accessor. */
234 .writel = writel_access_reg_fn,
235 .writel_check = writel_access_reg_fn,
236 .bar1_writel = writel_access_reg_fn,
237 .usermode_writel = writel_access_reg_fn,
238
239 /* Likewise for the read APIs. */
240 .__readl = readl_access_reg_fn,
241 .readl = readl_access_reg_fn,
242 .bar1_readl = readl_access_reg_fn,
243};
244
245static int test_register_space(struct unit_module *m, struct gk20a *g,
246 void *__args)
247{
248 u32 value;
249
250 nvgpu_posix_io_init_reg_space(g);
251 nvgpu_posix_io_start_recorder(g);
252
253 /* Define a couple of register spaces */
254 if (nvgpu_posix_io_add_reg_space(g, 0x10000000, 0x100) != 0) {
255 return UNIT_FAIL;
256 }
257 if (nvgpu_posix_io_add_reg_space(g, 0x80000000, 0x1000) != 0) {
258 return UNIT_FAIL;
259 }
260
261 /*
262 * Some direct access operations to test register IO. This could be
263 * used to initialize memory before starting the actual test.
264 */
265 nvgpu_posix_io_writel_reg_space(g, 0x10000000, 0x12345678);
266 nvgpu_posix_io_writel_reg_space(g, 0x80000004, 0x87654321);
267 value = nvgpu_posix_io_readl_reg_space(g, 0x80000004);
268 if (value != 0x87654321) {
269 return UNIT_FAIL;
270 }
271 nvgpu_posix_io_writel_reg_space(g, 0x10000100, 0x2727);
272
273 /* Now re-define the callbacks to perform our own testing */
274 struct nvgpu_posix_io_callbacks *old_cbs = nvgpu_posix_register_io(g,
275 &test_reg_callbacks);
276
277 /* The test begins where we would call some real NVGPU code */
278 nvgpu_writel(g, 0x80000008, 0xA1B1C1D1);
279 nvgpu_writel(g, 0x1000000C, 0x1);
280 nvgpu_writel(g, 0x10000010, 0x55);
281 /* End of real NVGPU code */
282
283 /* First check that no memory access error occurred */
284 if (nvgpu_posix_io_get_error_code(g) != 0) {
285 unit_return_fail(m, "IO Access Error\n");
286 }
287
288 /* Verification can then be done either using nvgpu_readl or
289 * nvgpu_posix_io_readl_reg_space
290 */
291 value = nvgpu_readl(g, 0x80000008);
292 if (value != 0xA1B1C1D1) {
293 unit_return_fail(m, "Register value mismatch at address=0x%x\n",
294 0x80000008);
295 }
296
297 /* Define a sequence of expected register writes */
298 struct nvgpu_reg_access sequence[] = {
299 { .addr = 0x80000008, .value = 0xA1B1C1D1 },
300 { .addr = 0x1000000C, .value = 0x1 },
301 { .addr = 0x10000010, .value = 0x55 }
302 };
303
304 /* Compare the recording with the expected sequence. If strict mode is
305 * used, then the same accesses, order and number of accesses is
306 * expected.
307 */
308 if (nvgpu_posix_io_check_sequence(g, sequence,
309 sizeof(sequence)/sizeof(struct nvgpu_reg_access),
310 true) == false) {
311 unit_return_fail(m, "Failed checking sequence\n");
312 }
313
314 /* Calling this function again resets the recorder to use it again */
315 nvgpu_posix_io_start_recorder(g);
316
317 /* Restore the old callbacks for other tests within this unit */
318 nvgpu_posix_register_io(g, old_cbs);
319
320 return UNIT_SUCCESS;
321}
322
323
324struct unit_module_test posix_mockio_tests[] = {
325 UNIT_TEST(register_io_callbacks, test_register_io_callbacks, NULL),
326 UNIT_TEST(writel, test_writel, &nvgpu_writel_args),
327 UNIT_TEST(writel_check, test_writel, &nvgpu_writel_check_args),
328 UNIT_TEST(bar1_writel, test_writel, &nvgpu_bar1_writel_args),
329 UNIT_TEST(usermode_writel, test_writel,
330 &nvgpu_usermode_writel_args),
331 UNIT_TEST(readl, test_readl, &nvgpu_readl_args),
332 UNIT_TEST(__readl, test_readl, &__nvgpu_readl_args),
333 UNIT_TEST(bar1_readl, test_readl, &nvgpu_bar1_readl_args),
334 UNIT_TEST(test_register_space, test_register_space, NULL),
335};
336
337UNIT_MODULE(posix_mockio, posix_mockio_tests, UNIT_PRIO_POSIX_TEST);
338