Commit 13048f88 authored by Bernd Schmidt's avatar Bernd Schmidt Committed by Mike Frysinger

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: default avatarBernd Schmidt <bernds_cb1@t-online.de>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
parent cb5ae60f
...@@ -332,12 +332,58 @@ int in_mem_const(unsigned long addr, unsigned long size, ...@@ -332,12 +332,58 @@ int in_mem_const(unsigned long addr, unsigned long size,
{ {
return in_mem_const_off(addr, size, 0, const_addr, const_size); return in_mem_const_off(addr, size, 0, const_addr, const_size);
} }
#define IN_ASYNC(bnum, bctlnum) \ #define ASYNC_ENABLED(bnum, bctlnum) \
({ \ ({ \
(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \ (bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \
bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \ bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \
BFIN_MEM_ACCESS_CORE; \ 1; \
}) })
/*
* We can't read EBIU banks that aren't enabled or we end up hanging
* on the access to the async space. Make sure we validate accesses
* that cross async banks too.
* 0 - found, but unusable
* 1 - found & usable
* 2 - not found
*/
static
int in_async(unsigned long addr, unsigned long size)
{
if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) {
if (!ASYNC_ENABLED(0, 0))
return 0;
if (addr + size <= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)
return 1;
size -= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE - addr;
addr = ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE;
}
if (addr >= ASYNC_BANK1_BASE && addr < ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) {
if (!ASYNC_ENABLED(1, 0))
return 0;
if (addr + size <= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)
return 1;
size -= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE - addr;
addr = ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE;
}
if (addr >= ASYNC_BANK2_BASE && addr < ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) {
if (!ASYNC_ENABLED(2, 1))
return 0;
if (addr + size <= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE)
return 1;
size -= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE - addr;
addr = ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE;
}
if (addr >= ASYNC_BANK3_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
if (ASYNC_ENABLED(3, 1))
return 0;
if (addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
return 1;
return 0;
}
/* not within async bounds */
return 2;
}
int bfin_mem_access_type(unsigned long addr, unsigned long size) int bfin_mem_access_type(unsigned long addr, unsigned long size)
{ {
...@@ -374,17 +420,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size) ...@@ -374,17 +420,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size)
if (addr >= SYSMMR_BASE) if (addr >= SYSMMR_BASE)
return BFIN_MEM_ACCESS_CORE_ONLY; return BFIN_MEM_ACCESS_CORE_ONLY;
/* We can't read EBIU banks that aren't enabled or we end up hanging switch (in_async(addr, size)) {
* on the access to the async space. case 0: return -EFAULT;
*/ case 1: return BFIN_MEM_ACCESS_CORE;
if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE)) case 2: /* fall through */;
return IN_ASYNC(0, 0); }
if (in_mem_const(addr, size, ASYNC_BANK1_BASE, ASYNC_BANK1_SIZE))
return IN_ASYNC(1, 0);
if (in_mem_const(addr, size, ASYNC_BANK2_BASE, ASYNC_BANK2_SIZE))
return IN_ASYNC(2, 1);
if (in_mem_const(addr, size, ASYNC_BANK3_BASE, ASYNC_BANK3_SIZE))
return IN_ASYNC(3, 1);
if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH)) if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH))
return BFIN_MEM_ACCESS_CORE; return BFIN_MEM_ACCESS_CORE;
...@@ -401,6 +441,8 @@ __attribute__((l1_text)) ...@@ -401,6 +441,8 @@ __attribute__((l1_text))
/* Return 1 if access to memory range is OK, 0 otherwise */ /* Return 1 if access to memory range is OK, 0 otherwise */
int _access_ok(unsigned long addr, unsigned long size) int _access_ok(unsigned long addr, unsigned long size)
{ {
int aret;
if (size == 0) if (size == 0)
return 1; return 1;
/* Check that things do not wrap around */ /* Check that things do not wrap around */
...@@ -450,6 +492,11 @@ int _access_ok(unsigned long addr, unsigned long size) ...@@ -450,6 +492,11 @@ int _access_ok(unsigned long addr, unsigned long size)
if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH)) if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
return 1; return 1;
#endif #endif
aret = in_async(addr, size);
if (aret < 2)
return aret;
if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH)) if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH))
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment