diff options
Diffstat (limited to 'arch/blackfin/mm/isram-driver.c')
-rw-r--r-- | arch/blackfin/mm/isram-driver.c | 212 |
1 files changed, 210 insertions, 2 deletions
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c index c080e70f98b0..02eaaa641d49 100644 --- a/arch/blackfin/mm/isram-driver.c +++ b/arch/blackfin/mm/isram-driver.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #define pr_fmt(fmt) "isram: " fmt | ||
20 | |||
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
20 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
21 | #include <linux/types.h> | 23 | #include <linux/types.h> |
@@ -23,6 +25,7 @@ | |||
23 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
24 | 26 | ||
25 | #include <asm/blackfin.h> | 27 | #include <asm/blackfin.h> |
28 | #include <asm/dma.h> | ||
26 | 29 | ||
27 | /* | 30 | /* |
28 | * IMPORTANT WARNING ABOUT THESE FUNCTIONS | 31 | * IMPORTANT WARNING ABOUT THESE FUNCTIONS |
@@ -127,8 +130,7 @@ static bool isram_check_addr(const void *addr, size_t n) | |||
127 | (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) { | 130 | (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) { |
128 | if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) { | 131 | if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) { |
129 | show_stack(NULL, NULL); | 132 | show_stack(NULL, NULL); |
130 | printk(KERN_ERR "isram_memcpy: copy involving %p length " | 133 | pr_err("copy involving %p length (%zu) too long\n", addr, n); |
131 | "(%zu) too long\n", addr, n); | ||
132 | } | 134 | } |
133 | return true; | 135 | return true; |
134 | } | 136 | } |
@@ -199,3 +201,209 @@ void *isram_memcpy(void *dest, const void *src, size_t n) | |||
199 | } | 201 | } |
200 | EXPORT_SYMBOL(isram_memcpy); | 202 | EXPORT_SYMBOL(isram_memcpy); |
201 | 203 | ||
204 | #ifdef CONFIG_BFIN_ISRAM_SELF_TEST | ||
205 | |||
206 | #define TEST_LEN 0x100 | ||
207 | |||
208 | static __init void hex_dump(unsigned char *buf, int len) | ||
209 | { | ||
210 | while (len--) | ||
211 | pr_cont("%02x", *buf++); | ||
212 | } | ||
213 | |||
214 | static __init int isram_read_test(char *sdram, void *l1inst) | ||
215 | { | ||
216 | int i, ret = 0; | ||
217 | uint64_t data1, data2; | ||
218 | |||
219 | pr_info("INFO: running isram_read tests\n"); | ||
220 | |||
221 | /* setup some different data to play with */ | ||
222 | for (i = 0; i < TEST_LEN; ++i) | ||
223 | sdram[i] = i; | ||
224 | dma_memcpy(l1inst, sdram, TEST_LEN); | ||
225 | |||
226 | /* make sure we can read the L1 inst */ | ||
227 | for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) { | ||
228 | data1 = isram_read(l1inst + i); | ||
229 | memcpy(&data2, sdram + i, sizeof(data2)); | ||
230 | if (memcmp(&data1, &data2, sizeof(uint64_t))) { | ||
231 | pr_err("FAIL: isram_read(%p) returned %#llx but wanted %#llx\n", | ||
232 | l1inst + i, data1, data2); | ||
233 | ++ret; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static __init int isram_write_test(char *sdram, void *l1inst) | ||
241 | { | ||
242 | int i, ret = 0; | ||
243 | uint64_t data1, data2; | ||
244 | |||
245 | pr_info("INFO: running isram_write tests\n"); | ||
246 | |||
247 | /* setup some different data to play with */ | ||
248 | memset(sdram, 0, TEST_LEN * 2); | ||
249 | dma_memcpy(l1inst, sdram, TEST_LEN); | ||
250 | for (i = 0; i < TEST_LEN; ++i) | ||
251 | sdram[i] = i; | ||
252 | |||
253 | /* make sure we can write the L1 inst */ | ||
254 | for (i = 0; i < TEST_LEN; i += sizeof(uint64_t)) { | ||
255 | memcpy(&data1, sdram + i, sizeof(data1)); | ||
256 | isram_write(l1inst + i, data1); | ||
257 | data2 = isram_read(l1inst + i); | ||
258 | if (memcmp(&data1, &data2, sizeof(uint64_t))) { | ||
259 | pr_err("FAIL: isram_write(%p, %#llx) != %#llx\n", | ||
260 | l1inst + i, data1, data2); | ||
261 | ++ret; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | dma_memcpy(sdram + TEST_LEN, l1inst, TEST_LEN); | ||
266 | if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) { | ||
267 | pr_err("FAIL: isram_write() did not work properly\n"); | ||
268 | ++ret; | ||
269 | } | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | static __init int | ||
275 | _isram_memcpy_test(char pattern, void *sdram, void *l1inst, const char *smemcpy, | ||
276 | void *(*fmemcpy)(void *, const void *, size_t)) | ||
277 | { | ||
278 | memset(sdram, pattern, TEST_LEN); | ||
279 | fmemcpy(l1inst, sdram, TEST_LEN); | ||
280 | fmemcpy(sdram + TEST_LEN, l1inst, TEST_LEN); | ||
281 | if (memcmp(sdram, sdram + TEST_LEN, TEST_LEN)) { | ||
282 | pr_err("FAIL: %s(%p <=> %p, %#x) failed (data is %#x)\n", | ||
283 | smemcpy, l1inst, sdram, TEST_LEN, pattern); | ||
284 | return 1; | ||
285 | } | ||
286 | return 0; | ||
287 | } | ||
288 | #define _isram_memcpy_test(a, b, c, d) _isram_memcpy_test(a, b, c, #d, d) | ||
289 | |||
290 | static __init int isram_memcpy_test(char *sdram, void *l1inst) | ||
291 | { | ||
292 | int i, j, thisret, ret = 0; | ||
293 | |||
294 | /* check broad isram_memcpy() */ | ||
295 | pr_info("INFO: running broad isram_memcpy tests\n"); | ||
296 | for (i = 0xf; i >= 0; --i) | ||
297 | ret += _isram_memcpy_test(i, sdram, l1inst, isram_memcpy); | ||
298 | |||
299 | /* check read of small, unaligned, and hardware 64bit limits */ | ||
300 | pr_info("INFO: running isram_memcpy (read) tests\n"); | ||
301 | |||
302 | for (i = 0; i < TEST_LEN; ++i) | ||
303 | sdram[i] = i; | ||
304 | dma_memcpy(l1inst, sdram, TEST_LEN); | ||
305 | |||
306 | thisret = 0; | ||
307 | for (i = 0; i < TEST_LEN - 32; ++i) { | ||
308 | unsigned char cmp[32]; | ||
309 | for (j = 1; j <= 32; ++j) { | ||
310 | memset(cmp, 0, sizeof(cmp)); | ||
311 | isram_memcpy(cmp, l1inst + i, j); | ||
312 | if (memcmp(cmp, sdram + i, j)) { | ||
313 | pr_err("FAIL: %p:", l1inst + 1); | ||
314 | hex_dump(cmp, j); | ||
315 | pr_cont(" SDRAM:"); | ||
316 | hex_dump(sdram + i, j); | ||
317 | pr_cont("\n"); | ||
318 | if (++thisret > 20) { | ||
319 | pr_err("FAIL: skipping remaining series\n"); | ||
320 | i = TEST_LEN; | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | ret += thisret; | ||
327 | |||
328 | /* check write of small, unaligned, and hardware 64bit limits */ | ||
329 | pr_info("INFO: running isram_memcpy (write) tests\n"); | ||
330 | |||
331 | memset(sdram + TEST_LEN, 0, TEST_LEN); | ||
332 | dma_memcpy(l1inst, sdram + TEST_LEN, TEST_LEN); | ||
333 | |||
334 | thisret = 0; | ||
335 | for (i = 0; i < TEST_LEN - 32; ++i) { | ||
336 | unsigned char cmp[32]; | ||
337 | for (j = 1; j <= 32; ++j) { | ||
338 | isram_memcpy(l1inst + i, sdram + i, j); | ||
339 | dma_memcpy(cmp, l1inst + i, j); | ||
340 | if (memcmp(cmp, sdram + i, j)) { | ||
341 | pr_err("FAIL: %p:", l1inst + i); | ||
342 | hex_dump(cmp, j); | ||
343 | pr_cont(" SDRAM:"); | ||
344 | hex_dump(sdram + i, j); | ||
345 | pr_cont("\n"); | ||
346 | if (++thisret > 20) { | ||
347 | pr_err("FAIL: skipping remaining series\n"); | ||
348 | i = TEST_LEN; | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | ret += thisret; | ||
355 | |||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | static __init int isram_test_init(void) | ||
360 | { | ||
361 | int ret; | ||
362 | char *sdram; | ||
363 | void *l1inst; | ||
364 | |||
365 | sdram = kmalloc(TEST_LEN * 2, GFP_KERNEL); | ||
366 | if (!sdram) { | ||
367 | pr_warning("SKIP: could not allocate sdram\n"); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | l1inst = l1_inst_sram_alloc(TEST_LEN); | ||
372 | if (!l1inst) { | ||
373 | kfree(sdram); | ||
374 | pr_warning("SKIP: could not allocate L1 inst\n"); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /* sanity check initial L1 inst state */ | ||
379 | ret = 1; | ||
380 | pr_info("INFO: running initial dma_memcpy checks\n"); | ||
381 | if (_isram_memcpy_test(0xa, sdram, l1inst, dma_memcpy)) | ||
382 | goto abort; | ||
383 | if (_isram_memcpy_test(0x5, sdram, l1inst, dma_memcpy)) | ||
384 | goto abort; | ||
385 | |||
386 | ret = 0; | ||
387 | ret += isram_read_test(sdram, l1inst); | ||
388 | ret += isram_write_test(sdram, l1inst); | ||
389 | ret += isram_memcpy_test(sdram, l1inst); | ||
390 | |||
391 | abort: | ||
392 | sram_free(l1inst); | ||
393 | kfree(sdram); | ||
394 | |||
395 | if (ret) | ||
396 | return -EIO; | ||
397 | |||
398 | pr_info("PASS: all tests worked !\n"); | ||
399 | return 0; | ||
400 | } | ||
401 | late_initcall(isram_test_init); | ||
402 | |||
403 | static __exit void isram_test_exit(void) | ||
404 | { | ||
405 | /* stub to allow unloading */ | ||
406 | } | ||
407 | module_exit(isram_test_exit); | ||
408 | |||
409 | #endif | ||