Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+62 −15
Original line number Diff line number Diff line
@@ -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);
}
#define IN_ASYNC(bnum, bctlnum) \
#define ASYNC_ENABLED(bnum, bctlnum) \
({ \
	(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \
	bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \
	BFIN_MEM_ACCESS_CORE; \
	(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \
	bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \
	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)
{
@@ -374,17 +420,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size)
	if (addr >= SYSMMR_BASE)
		return BFIN_MEM_ACCESS_CORE_ONLY;

	/* We can't read EBIU banks that aren't enabled or we end up hanging
	 * on the access to the async space.
	 */
	if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE))
		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);
	switch (in_async(addr, size)) {
	case 0: return -EFAULT;
	case 1: return BFIN_MEM_ACCESS_CORE;
	case 2: /* fall through */;
	}

	if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH))
		return BFIN_MEM_ACCESS_CORE;
@@ -401,6 +441,8 @@ __attribute__((l1_text))
/* Return 1 if access to memory range is OK, 0 otherwise */
int _access_ok(unsigned long addr, unsigned long size)
{
	int aret;

	if (size == 0)
		return 1;
	/* Check that things do not wrap around */
@@ -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))
		return 1;
#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))
		return 1;