diff options
Diffstat (limited to 'arch/blackfin')
-rw-r--r-- | arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 64 |
1 files changed, 41 insertions, 23 deletions
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index f23bba5c6e63..3377cbf28fb4 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -146,14 +146,16 @@ static noinline int dcplb_miss(void) d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_DCACHE - if (addr < _ramend - DMA_UNCACHED_REGION) { + if (addr < _ramend - DMA_UNCACHED_REGION || + (reserved_mem_dcache_on && addr >= _ramend && + addr < physical_mem_end)) { d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; #ifdef CONFIG_BFIN_WT d_data |= CPLB_L1_AOW | CPLB_WT; #endif } #endif - if (addr >= _ramend) { + if (addr >= physical_mem_end) { if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE && (status & FAULT_USERSUPV)) { addr &= ~0x3fffff; @@ -161,6 +163,8 @@ static noinline int dcplb_miss(void) d_data |= PAGE_SIZE_4MB; } else return CPLB_PROT_VIOL; + } else if (addr >= _ramend) { + d_data |= CPLB_USER_RD | CPLB_USER_WR; } else { mask = current_rwx_mask; if (mask) { @@ -198,12 +202,14 @@ static noinline int icplb_miss(void) unsigned long i_data; nr_icplb_miss++; - if (status & FAULT_USERSUPV) - nr_icplb_supv_miss++; - if (addr >= _ramend) + /* If inside the uncached DMA region, fault. */ + if (addr >= _ramend - DMA_UNCACHED_REGION && addr < _ramend) return CPLB_PROT_VIOL; + if (status & FAULT_USERSUPV) + nr_icplb_supv_miss++; + /* * First, try to find a CPLB that matches this address. If we * find one, then the fact that we're in the miss handler means @@ -220,30 +226,42 @@ static noinline int icplb_miss(void) } i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB; -#ifdef CONFIG_BFIN_ICACHE - i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; -#endif +#ifdef CONFIG_BFIN_ICACHE /* - * Two cases to distinguish - a supervisor access must necessarily - * be for a module page; we grant it unconditionally (could do better - * here in the future). Otherwise, check the x bitmap of the current - * process. + * Normal RAM, and possibly the reserved memory area, are + * cacheable. */ - if (!(status & FAULT_USERSUPV)) { - unsigned long *mask = current_rwx_mask; - - if (mask) { - int page = addr >> PAGE_SHIFT; - int offs = page >> 5; - int bit = 1 << (page & 31); + if (addr < _ramend || + (addr < physical_mem_end && reserved_mem_icache_on)) + i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND; +#endif - mask += 2 * page_mask_nelts; - if (mask[offs] & bit) - i_data |= CPLB_USER_RD; + if (addr >= physical_mem_end) { + return CPLB_PROT_VIOL; + } else if (addr >= _ramend) { + i_data |= CPLB_USER_RD; + } else { + /* + * Two cases to distinguish - a supervisor access must + * necessarily be for a module page; we grant it + * unconditionally (could do better here in the future). + * Otherwise, check the x bitmap of the current process. + */ + if (!(status & FAULT_USERSUPV)) { + unsigned long *mask = current_rwx_mask; + + if (mask) { + int page = addr >> PAGE_SHIFT; + int offs = page >> 5; + int bit = 1 << (page & 31); + + mask += 2 * page_mask_nelts; + if (mask[offs] & bit) + i_data |= CPLB_USER_RD; + } } } - idx = evict_one_icplb(); addr &= PAGE_MASK; icplb_tbl[idx].addr = addr; |