diff options
author | Bernd Schmidt <bernds_cb1@t-online.de> | 2009-09-23 12:47:16 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-12-15 00:13:52 -0500 |
commit | 13048f8866390a26a7b657e0ca28100e2660063a (patch) | |
tree | 9613b8d038e3e0786ed854ce4f172dc698f8c65d /arch/blackfin/kernel/process.c | |
parent | cb5ae60f7a0b21b936c022a2e7f9303c60665233 (diff) |
Blackfin: improve async bank access checking (for cross-banks & XIP)
The access_ok() function did not accept ranges within the async banks
which made it impossible to do XIP in flash. Fixing that also showed
that the current bfin_mem_access_type() code did not work with accesses
that spanned async banks (like a file system). So split out and fix the
async bank checks so that all these scenarios work as expected.
Signed-off-by: Bernd Schmidt <bernds_cb1@t-online.de>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel/process.c')
-rw-r--r-- | arch/blackfin/kernel/process.c | 77 |
1 files changed, 62 insertions, 15 deletions
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 45876427eb2d..a57723808743 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -332,12 +332,58 @@ int in_mem_const(unsigned long addr, unsigned long size, | |||
332 | { | 332 | { |
333 | return in_mem_const_off(addr, size, 0, const_addr, const_size); | 333 | return in_mem_const_off(addr, size, 0, const_addr, const_size); |
334 | } | 334 | } |
335 | #define IN_ASYNC(bnum, bctlnum) \ | 335 | #define ASYNC_ENABLED(bnum, bctlnum) \ |
336 | ({ \ | 336 | ({ \ |
337 | (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \ | 337 | (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \ |
338 | bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \ | 338 | bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \ |
339 | BFIN_MEM_ACCESS_CORE; \ | 339 | 1; \ |
340 | }) | 340 | }) |
341 | /* | ||
342 | * We can't read EBIU banks that aren't enabled or we end up hanging | ||
343 | * on the access to the async space. Make sure we validate accesses | ||
344 | * that cross async banks too. | ||
345 | * 0 - found, but unusable | ||
346 | * 1 - found & usable | ||
347 | * 2 - not found | ||
348 | */ | ||
349 | static | ||
350 | int in_async(unsigned long addr, unsigned long size) | ||
351 | { | ||
352 | if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) { | ||
353 | if (!ASYNC_ENABLED(0, 0)) | ||
354 | return 0; | ||
355 | if (addr + size <= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) | ||
356 | return 1; | ||
357 | size -= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE - addr; | ||
358 | addr = ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE; | ||
359 | } | ||
360 | if (addr >= ASYNC_BANK1_BASE && addr < ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) { | ||
361 | if (!ASYNC_ENABLED(1, 0)) | ||
362 | return 0; | ||
363 | if (addr + size <= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) | ||
364 | return 1; | ||
365 | size -= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE - addr; | ||
366 | addr = ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE; | ||
367 | } | ||
368 | if (addr >= ASYNC_BANK2_BASE && addr < ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) { | ||
369 | if (!ASYNC_ENABLED(2, 1)) | ||
370 | return 0; | ||
371 | if (addr + size <= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) | ||
372 | return 1; | ||
373 | size -= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE - addr; | ||
374 | addr = ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE; | ||
375 | } | ||
376 | if (addr >= ASYNC_BANK3_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { | ||
377 | if (ASYNC_ENABLED(3, 1)) | ||
378 | return 0; | ||
379 | if (addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) | ||
380 | return 1; | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* not within async bounds */ | ||
385 | return 2; | ||
386 | } | ||
341 | 387 | ||
342 | int bfin_mem_access_type(unsigned long addr, unsigned long size) | 388 | int bfin_mem_access_type(unsigned long addr, unsigned long size) |
343 | { | 389 | { |
@@ -374,17 +420,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size) | |||
374 | if (addr >= SYSMMR_BASE) | 420 | if (addr >= SYSMMR_BASE) |
375 | return BFIN_MEM_ACCESS_CORE_ONLY; | 421 | return BFIN_MEM_ACCESS_CORE_ONLY; |
376 | 422 | ||
377 | /* We can't read EBIU banks that aren't enabled or we end up hanging | 423 | switch (in_async(addr, size)) { |
378 | * on the access to the async space. | 424 | case 0: return -EFAULT; |
379 | */ | 425 | case 1: return BFIN_MEM_ACCESS_CORE; |
380 | if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE)) | 426 | case 2: /* fall through */; |
381 | return IN_ASYNC(0, 0); | 427 | } |
382 | if (in_mem_const(addr, size, ASYNC_BANK1_BASE, ASYNC_BANK1_SIZE)) | ||
383 | return IN_ASYNC(1, 0); | ||
384 | if (in_mem_const(addr, size, ASYNC_BANK2_BASE, ASYNC_BANK2_SIZE)) | ||
385 | return IN_ASYNC(2, 1); | ||
386 | if (in_mem_const(addr, size, ASYNC_BANK3_BASE, ASYNC_BANK3_SIZE)) | ||
387 | return IN_ASYNC(3, 1); | ||
388 | 428 | ||
389 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) | 429 | if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) |
390 | return BFIN_MEM_ACCESS_CORE; | 430 | return BFIN_MEM_ACCESS_CORE; |
@@ -401,6 +441,8 @@ __attribute__((l1_text)) | |||
401 | /* Return 1 if access to memory range is OK, 0 otherwise */ | 441 | /* Return 1 if access to memory range is OK, 0 otherwise */ |
402 | int _access_ok(unsigned long addr, unsigned long size) | 442 | int _access_ok(unsigned long addr, unsigned long size) |
403 | { | 443 | { |
444 | int aret; | ||
445 | |||
404 | if (size == 0) | 446 | if (size == 0) |
405 | return 1; | 447 | return 1; |
406 | /* Check that things do not wrap around */ | 448 | /* Check that things do not wrap around */ |
@@ -450,6 +492,11 @@ int _access_ok(unsigned long addr, unsigned long size) | |||
450 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) | 492 | if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) |
451 | return 1; | 493 | return 1; |
452 | #endif | 494 | #endif |
495 | |||
496 | aret = in_async(addr, size); | ||
497 | if (aret < 2) | ||
498 | return aret; | ||
499 | |||
453 | if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) | 500 | if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) |
454 | return 1; | 501 | return 1; |
455 | 502 | ||