Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into next
Pull ARM updates from Russell King: - Major clean-up of the L2 cache support code. The existing mess was becoming rather unmaintainable through all the additions that others have done over time. This turns it into a much nicer structure, and implements a few performance improvements as well. - Clean up some of the CP15 control register tweaks for alignment support, moving some code and data into alignment.c - DMA properties for ARM, from Santosh and reviewed by DT people. This adds DT properties to specify bus translations we can't discover automatically, and to indicate whether devices are coherent. - Hibernation support for ARM - Make ftrace work with read-only text in modules - add suspend support for PJ4B CPUs - rework interrupt masking for undefined instruction handling, which allows us to enable interrupts earlier in the handling of these exceptions. - support for big endian page tables - fix stacktrace support to exclude stacktrace functions from the trace, and add save_stack_trace_regs() implementation so that kprobes can record stack traces. - Add support for the Cortex-A17 CPU. - Remove last vestiges of ARM710 support. - Removal of ARM "meminfo" structure, finally converting us solely to memblock to handle the early memory initialisation. * 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (142 commits) ARM: ensure C page table setup code follows assembly code (part II) ARM: ensure C page table setup code follows assembly code ARM: consolidate last remaining open-coded alignment trap enable ARM: remove global cr_no_alignment ARM: remove CPU_CP15 conditional from alignment.c ARM: remove unused adjust_cr() function ARM: move "noalign" command line option to alignment.c ARM: provide common method to clear bits in CPU control register ARM: 8025/1: Get rid of meminfo ARM: 8060/1: mm: allow sub-architectures to override PCI I/O memory type ARM: 8066/1: correction for ARM patch 8031/2 ARM: 8049/1: ftrace/add save_stack_trace_regs() implementation ARM: 8065/1: remove last use of CONFIG_CPU_ARM710 ARM: 8062/1: Modify ldrt fixup handler to re-execute the userspace instruction ARM: 8047/1: rwsem: use asm-generic rwsem implementation ARM: l2c: trial at enabling some Cortex-A9 optimisations ARM: l2c: add warnings for stuff modifying aux_ctrl register values ARM: l2c: print a warning with L2C-310 caches if the cache size is modified ARM: l2c: remove old .set_debug method ARM: l2c: kill L2X0_AUX_CTRL_MASK before anyone else makes use of this ...
This commit is contained in:
@@ -897,6 +897,57 @@ config CACHE_PL310
|
||||
This option enables optimisations for the PL310 cache
|
||||
controller.
|
||||
|
||||
config PL310_ERRATA_588369
|
||||
bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines"
|
||||
depends on CACHE_L2X0
|
||||
help
|
||||
The PL310 L2 cache controller implements three types of Clean &
|
||||
Invalidate maintenance operations: by Physical Address
|
||||
(offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC).
|
||||
They are architecturally defined to behave as the execution of a
|
||||
clean operation followed immediately by an invalidate operation,
|
||||
both performing to the same memory location. This functionality
|
||||
is not correctly implemented in PL310 as clean lines are not
|
||||
invalidated as a result of these operations.
|
||||
|
||||
config PL310_ERRATA_727915
|
||||
bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption"
|
||||
depends on CACHE_L2X0
|
||||
help
|
||||
PL310 implements the Clean & Invalidate by Way L2 cache maintenance
|
||||
operation (offset 0x7FC). This operation runs in background so that
|
||||
PL310 can handle normal accesses while it is in progress. Under very
|
||||
rare circumstances, due to this erratum, write data can be lost when
|
||||
PL310 treats a cacheable write transaction during a Clean &
|
||||
Invalidate by Way operation.
|
||||
|
||||
config PL310_ERRATA_753970
|
||||
bool "PL310 errata: cache sync operation may be faulty"
|
||||
depends on CACHE_PL310
|
||||
help
|
||||
This option enables the workaround for the 753970 PL310 (r3p0) erratum.
|
||||
|
||||
Under some condition the effect of cache sync operation on
|
||||
the store buffer still remains when the operation completes.
|
||||
This means that the store buffer is always asked to drain and
|
||||
this prevents it from merging any further writes. The workaround
|
||||
is to replace the normal offset of cache sync operation (0x730)
|
||||
by another offset targeting an unmapped PL310 register 0x740.
|
||||
This has the same effect as the cache sync operation: store buffer
|
||||
drain and waiting for all buffers empty.
|
||||
|
||||
config PL310_ERRATA_769419
|
||||
bool "PL310 errata: no automatic Store Buffer drain"
|
||||
depends on CACHE_L2X0
|
||||
help
|
||||
On revisions of the PL310 prior to r3p2, the Store Buffer does
|
||||
not automatically drain. This can cause normal, non-cacheable
|
||||
writes to be retained when the memory system is idle, leading
|
||||
to suboptimal I/O performance for drivers using coherent DMA.
|
||||
This option adds a write barrier to the cpu_idle loop so that,
|
||||
on systems with an outer cache, the store buffer is drained
|
||||
explicitly.
|
||||
|
||||
config CACHE_TAUROS2
|
||||
bool "Enable the Tauros2 L2 cache controller"
|
||||
depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
|
||||
|
@@ -95,7 +95,8 @@ obj-$(CONFIG_CPU_V7M) += proc-v7m.o
|
||||
AFLAGS_proc-v6.o :=-Wa,-march=armv6
|
||||
AFLAGS_proc-v7.o :=-Wa,-march=armv7-a
|
||||
|
||||
obj-$(CONFIG_OUTER_CACHE) += l2c-common.o
|
||||
obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
|
||||
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
|
||||
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o
|
||||
obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
|
||||
obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
#include "fault.h"
|
||||
#include "mm.h"
|
||||
|
||||
/*
|
||||
* 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
|
||||
@@ -81,6 +82,7 @@ static unsigned long ai_word;
|
||||
static unsigned long ai_dword;
|
||||
static unsigned long ai_multi;
|
||||
static int ai_usermode;
|
||||
static unsigned long cr_no_alignment;
|
||||
|
||||
core_param(alignment, ai_usermode, int, 0600);
|
||||
|
||||
@@ -91,7 +93,7 @@ core_param(alignment, ai_usermode, int, 0600);
|
||||
/* Return true if and only if the ARMv6 unaligned access model is in use. */
|
||||
static bool cpu_is_v6_unaligned(void)
|
||||
{
|
||||
return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U);
|
||||
return cpu_architecture() >= CPU_ARCH_ARMv6 && get_cr() & CR_U;
|
||||
}
|
||||
|
||||
static int safe_usermode(int new_usermode, bool warn)
|
||||
@@ -949,6 +951,13 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init noalign_setup(char *__unused)
|
||||
{
|
||||
set_cr(__clear_cr(CR_A));
|
||||
return 1;
|
||||
}
|
||||
__setup("noalign", noalign_setup);
|
||||
|
||||
/*
|
||||
* This needs to be done after sysctl_init, otherwise sys/ will be
|
||||
* overwritten. Actually, this shouldn't be in sys/ at all since
|
||||
@@ -966,14 +975,12 @@ static int __init alignment_init(void)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_CP15
|
||||
if (cpu_is_v6_unaligned()) {
|
||||
cr_alignment &= ~CR_A;
|
||||
cr_no_alignment &= ~CR_A;
|
||||
set_cr(cr_alignment);
|
||||
set_cr(__clear_cr(CR_A));
|
||||
ai_usermode = safe_usermode(ai_usermode, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
cr_no_alignment = get_cr() & ~CR_A;
|
||||
|
||||
hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN,
|
||||
"alignment exception");
|
||||
|
@@ -350,7 +350,6 @@ void __init feroceon_l2_init(int __l2_wt_override)
|
||||
outer_cache.inv_range = feroceon_l2_inv_range;
|
||||
outer_cache.clean_range = feroceon_l2_clean_range;
|
||||
outer_cache.flush_range = feroceon_l2_flush_range;
|
||||
outer_cache.inv_all = l2_inv_all;
|
||||
|
||||
enable_l2();
|
||||
|
||||
|
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
Load Diff
@@ -59,7 +59,7 @@ ENTRY(v7_invalidate_l1)
|
||||
bgt 2b
|
||||
cmp r2, #0
|
||||
bgt 1b
|
||||
dsb
|
||||
dsb st
|
||||
isb
|
||||
mov pc, lr
|
||||
ENDPROC(v7_invalidate_l1)
|
||||
@@ -166,7 +166,7 @@ skip:
|
||||
finished:
|
||||
mov r10, #0 @ swith back to cache level 0
|
||||
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
|
||||
dsb
|
||||
dsb st
|
||||
isb
|
||||
mov pc, lr
|
||||
ENDPROC(v7_flush_dcache_all)
|
||||
@@ -335,7 +335,7 @@ ENTRY(v7_flush_kern_dcache_area)
|
||||
add r0, r0, r2
|
||||
cmp r0, r1
|
||||
blo 1b
|
||||
dsb
|
||||
dsb st
|
||||
mov pc, lr
|
||||
ENDPROC(v7_flush_kern_dcache_area)
|
||||
|
||||
@@ -368,7 +368,7 @@ v7_dma_inv_range:
|
||||
add r0, r0, r2
|
||||
cmp r0, r1
|
||||
blo 1b
|
||||
dsb
|
||||
dsb st
|
||||
mov pc, lr
|
||||
ENDPROC(v7_dma_inv_range)
|
||||
|
||||
@@ -390,7 +390,7 @@ v7_dma_clean_range:
|
||||
add r0, r0, r2
|
||||
cmp r0, r1
|
||||
blo 1b
|
||||
dsb
|
||||
dsb st
|
||||
mov pc, lr
|
||||
ENDPROC(v7_dma_clean_range)
|
||||
|
||||
@@ -412,7 +412,7 @@ ENTRY(v7_dma_flush_range)
|
||||
add r0, r0, r2
|
||||
cmp r0, r1
|
||||
blo 1b
|
||||
dsb
|
||||
dsb st
|
||||
mov pc, lr
|
||||
ENDPROC(v7_dma_flush_range)
|
||||
|
||||
|
@@ -885,7 +885,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
|
||||
static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long paddr;
|
||||
phys_addr_t paddr;
|
||||
|
||||
dma_cache_maint_page(page, off, size, dir, dmac_map_area);
|
||||
|
||||
@@ -901,14 +901,15 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
|
||||
static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
unsigned long paddr = page_to_phys(page) + off;
|
||||
phys_addr_t paddr = page_to_phys(page) + off;
|
||||
|
||||
/* FIXME: non-speculating: not required */
|
||||
/* don't bother invalidating if DMA to device */
|
||||
if (dir != DMA_TO_DEVICE)
|
||||
/* in any case, don't bother invalidating if DMA to device */
|
||||
if (dir != DMA_TO_DEVICE) {
|
||||
outer_inv_range(paddr, paddr + size);
|
||||
|
||||
dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
|
||||
dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the D-cache clean for these pages to avoid extra flushing.
|
||||
|
@@ -104,17 +104,20 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
|
||||
#define flush_icache_alias(pfn,vaddr,len) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define FLAG_PA_IS_EXEC 1
|
||||
#define FLAG_PA_CORE_IN_MM 2
|
||||
|
||||
static void flush_ptrace_access_other(void *args)
|
||||
{
|
||||
__flush_icache_all();
|
||||
}
|
||||
|
||||
static
|
||||
void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
|
||||
unsigned long uaddr, void *kaddr, unsigned long len)
|
||||
static inline
|
||||
void __flush_ptrace_access(struct page *page, unsigned long uaddr, void *kaddr,
|
||||
unsigned long len, unsigned int flags)
|
||||
{
|
||||
if (cache_is_vivt()) {
|
||||
if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
|
||||
if (flags & FLAG_PA_CORE_IN_MM) {
|
||||
unsigned long addr = (unsigned long)kaddr;
|
||||
__cpuc_coherent_kern_range(addr, addr + len);
|
||||
}
|
||||
@@ -128,7 +131,7 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
|
||||
}
|
||||
|
||||
/* VIPT non-aliasing D-cache */
|
||||
if (vma->vm_flags & VM_EXEC) {
|
||||
if (flags & FLAG_PA_IS_EXEC) {
|
||||
unsigned long addr = (unsigned long)kaddr;
|
||||
if (icache_is_vipt_aliasing())
|
||||
flush_icache_alias(page_to_pfn(page), uaddr, len);
|
||||
@@ -140,6 +143,26 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
|
||||
unsigned long uaddr, void *kaddr, unsigned long len)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)))
|
||||
flags |= FLAG_PA_CORE_IN_MM;
|
||||
if (vma->vm_flags & VM_EXEC)
|
||||
flags |= FLAG_PA_IS_EXEC;
|
||||
__flush_ptrace_access(page, uaddr, kaddr, len, flags);
|
||||
}
|
||||
|
||||
void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
|
||||
void *kaddr, unsigned long len)
|
||||
{
|
||||
unsigned int flags = FLAG_PA_CORE_IN_MM|FLAG_PA_IS_EXEC;
|
||||
|
||||
__flush_ptrace_access(page, uaddr, kaddr, len, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy user data from/to a page which is mapped into a different
|
||||
* processes address space. Really, we want to allow our "user
|
||||
|
@@ -18,6 +18,21 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include "mm.h"
|
||||
|
||||
pte_t *fixmap_page_table;
|
||||
|
||||
static inline void set_fixmap_pte(int idx, pte_t pte)
|
||||
{
|
||||
unsigned long vaddr = __fix_to_virt(idx);
|
||||
set_pte_ext(fixmap_page_table + idx, pte, 0);
|
||||
local_flush_tlb_kernel_page(vaddr);
|
||||
}
|
||||
|
||||
static inline pte_t get_fixmap_pte(unsigned long vaddr)
|
||||
{
|
||||
unsigned long idx = __virt_to_fix(vaddr);
|
||||
return *(fixmap_page_table + idx);
|
||||
}
|
||||
|
||||
void *kmap(struct page *page)
|
||||
{
|
||||
might_sleep();
|
||||
@@ -63,20 +78,20 @@ void *kmap_atomic(struct page *page)
|
||||
type = kmap_atomic_idx_push();
|
||||
|
||||
idx = type + KM_TYPE_NR * smp_processor_id();
|
||||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
|
||||
vaddr = __fix_to_virt(idx);
|
||||
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||
/*
|
||||
* With debugging enabled, kunmap_atomic forces that entry to 0.
|
||||
* Make sure it was indeed properly unmapped.
|
||||
*/
|
||||
BUG_ON(!pte_none(get_top_pte(vaddr)));
|
||||
BUG_ON(!pte_none(*(fixmap_page_table + idx)));
|
||||
#endif
|
||||
/*
|
||||
* When debugging is off, kunmap_atomic leaves the previous mapping
|
||||
* in place, so the contained TLB flush ensures the TLB is updated
|
||||
* with the new mapping.
|
||||
*/
|
||||
set_top_pte(vaddr, mk_pte(page, kmap_prot));
|
||||
set_fixmap_pte(idx, mk_pte(page, kmap_prot));
|
||||
|
||||
return (void *)vaddr;
|
||||
}
|
||||
@@ -94,8 +109,8 @@ void __kunmap_atomic(void *kvaddr)
|
||||
if (cache_is_vivt())
|
||||
__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
|
||||
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
|
||||
set_top_pte(vaddr, __pte(0));
|
||||
BUG_ON(vaddr != __fix_to_virt(idx));
|
||||
set_fixmap_pte(idx, __pte(0));
|
||||
#else
|
||||
(void) idx; /* to kill a warning */
|
||||
#endif
|
||||
@@ -117,11 +132,11 @@ void *kmap_atomic_pfn(unsigned long pfn)
|
||||
|
||||
type = kmap_atomic_idx_push();
|
||||
idx = type + KM_TYPE_NR * smp_processor_id();
|
||||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
|
||||
vaddr = __fix_to_virt(idx);
|
||||
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||
BUG_ON(!pte_none(get_top_pte(vaddr)));
|
||||
BUG_ON(!pte_none(*(fixmap_page_table + idx)));
|
||||
#endif
|
||||
set_top_pte(vaddr, pfn_pte(pfn, kmap_prot));
|
||||
set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot));
|
||||
|
||||
return (void *)vaddr;
|
||||
}
|
||||
@@ -133,5 +148,5 @@ struct page *kmap_atomic_to_page(const void *ptr)
|
||||
if (vaddr < FIXADDR_START)
|
||||
return virt_to_page(ptr);
|
||||
|
||||
return pte_page(get_top_pte(vaddr));
|
||||
return pte_page(get_fixmap_pte(vaddr));
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/memblock.h>
|
||||
#include <asm/prom.h>
|
||||
@@ -36,6 +37,14 @@
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
#ifdef CONFIG_CPU_CP15_MMU
|
||||
unsigned long __init __clear_cr(unsigned long mask)
|
||||
{
|
||||
cr_alignment = cr_alignment & ~mask;
|
||||
return cr_alignment;
|
||||
}
|
||||
#endif
|
||||
|
||||
static phys_addr_t phys_initrd_start __initdata = 0;
|
||||
static unsigned long phys_initrd_size __initdata = 0;
|
||||
|
||||
@@ -81,24 +90,21 @@ __tagtable(ATAG_INITRD2, parse_tag_initrd2);
|
||||
* initialization functions, as well as show_mem() for the skipping
|
||||
* of holes in the memory map. It is populated by arm_add_memory().
|
||||
*/
|
||||
struct meminfo meminfo;
|
||||
|
||||
void show_mem(unsigned int filter)
|
||||
{
|
||||
int free = 0, total = 0, reserved = 0;
|
||||
int shared = 0, cached = 0, slab = 0, i;
|
||||
struct meminfo * mi = &meminfo;
|
||||
int shared = 0, cached = 0, slab = 0;
|
||||
struct memblock_region *reg;
|
||||
|
||||
printk("Mem-info:\n");
|
||||
show_free_areas(filter);
|
||||
|
||||
for_each_bank (i, mi) {
|
||||
struct membank *bank = &mi->bank[i];
|
||||
for_each_memblock (memory, reg) {
|
||||
unsigned int pfn1, pfn2;
|
||||
struct page *page, *end;
|
||||
|
||||
pfn1 = bank_pfn_start(bank);
|
||||
pfn2 = bank_pfn_end(bank);
|
||||
pfn1 = memblock_region_memory_base_pfn(reg);
|
||||
pfn2 = memblock_region_memory_end_pfn(reg);
|
||||
|
||||
page = pfn_to_page(pfn1);
|
||||
end = pfn_to_page(pfn2 - 1) + 1;
|
||||
@@ -115,8 +121,9 @@ void show_mem(unsigned int filter)
|
||||
free++;
|
||||
else
|
||||
shared += page_count(page) - 1;
|
||||
page++;
|
||||
} while (page < end);
|
||||
pfn1++;
|
||||
page = pfn_to_page(pfn1);
|
||||
} while (pfn1 < pfn2);
|
||||
}
|
||||
|
||||
printk("%d pages of RAM\n", total);
|
||||
@@ -130,16 +137,9 @@ void show_mem(unsigned int filter)
|
||||
static void __init find_limits(unsigned long *min, unsigned long *max_low,
|
||||
unsigned long *max_high)
|
||||
{
|
||||
struct meminfo *mi = &meminfo;
|
||||
int i;
|
||||
|
||||
/* This assumes the meminfo array is properly sorted */
|
||||
*min = bank_pfn_start(&mi->bank[0]);
|
||||
for_each_bank (i, mi)
|
||||
if (mi->bank[i].highmem)
|
||||
break;
|
||||
*max_low = bank_pfn_end(&mi->bank[i - 1]);
|
||||
*max_high = bank_pfn_end(&mi->bank[mi->nr_banks - 1]);
|
||||
*max_low = PFN_DOWN(memblock_get_current_limit());
|
||||
*min = PFN_UP(memblock_start_of_DRAM());
|
||||
*max_high = PFN_DOWN(memblock_end_of_DRAM());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
@@ -274,14 +274,8 @@ phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
|
||||
return phys;
|
||||
}
|
||||
|
||||
void __init arm_memblock_init(struct meminfo *mi,
|
||||
const struct machine_desc *mdesc)
|
||||
void __init arm_memblock_init(const struct machine_desc *mdesc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mi->nr_banks; i++)
|
||||
memblock_add(mi->bank[i].start, mi->bank[i].size);
|
||||
|
||||
/* Register the kernel text, kernel data and initrd with memblock. */
|
||||
#ifdef CONFIG_XIP_KERNEL
|
||||
memblock_reserve(__pa(_sdata), _end - _sdata);
|
||||
@@ -412,54 +406,53 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
|
||||
/*
|
||||
* The mem_map array can get very big. Free the unused area of the memory map.
|
||||
*/
|
||||
static void __init free_unused_memmap(struct meminfo *mi)
|
||||
static void __init free_unused_memmap(void)
|
||||
{
|
||||
unsigned long bank_start, prev_bank_end = 0;
|
||||
unsigned int i;
|
||||
unsigned long start, prev_end = 0;
|
||||
struct memblock_region *reg;
|
||||
|
||||
/*
|
||||
* This relies on each bank being in address order.
|
||||
* The banks are sorted previously in bootmem_init().
|
||||
*/
|
||||
for_each_bank(i, mi) {
|
||||
struct membank *bank = &mi->bank[i];
|
||||
|
||||
bank_start = bank_pfn_start(bank);
|
||||
for_each_memblock(memory, reg) {
|
||||
start = memblock_region_memory_base_pfn(reg);
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM
|
||||
/*
|
||||
* Take care not to free memmap entries that don't exist
|
||||
* due to SPARSEMEM sections which aren't present.
|
||||
*/
|
||||
bank_start = min(bank_start,
|
||||
ALIGN(prev_bank_end, PAGES_PER_SECTION));
|
||||
start = min(start,
|
||||
ALIGN(prev_end, PAGES_PER_SECTION));
|
||||
#else
|
||||
/*
|
||||
* Align down here since the VM subsystem insists that the
|
||||
* memmap entries are valid from the bank start aligned to
|
||||
* MAX_ORDER_NR_PAGES.
|
||||
*/
|
||||
bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
|
||||
start = round_down(start, MAX_ORDER_NR_PAGES);
|
||||
#endif
|
||||
/*
|
||||
* If we had a previous bank, and there is a space
|
||||
* between the current bank and the previous, free it.
|
||||
*/
|
||||
if (prev_bank_end && prev_bank_end < bank_start)
|
||||
free_memmap(prev_bank_end, bank_start);
|
||||
if (prev_end && prev_end < start)
|
||||
free_memmap(prev_end, start);
|
||||
|
||||
/*
|
||||
* Align up here since the VM subsystem insists that the
|
||||
* memmap entries are valid from the bank end aligned to
|
||||
* MAX_ORDER_NR_PAGES.
|
||||
*/
|
||||
prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
|
||||
prev_end = ALIGN(memblock_region_memory_end_pfn(reg),
|
||||
MAX_ORDER_NR_PAGES);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM
|
||||
if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
|
||||
free_memmap(prev_bank_end,
|
||||
ALIGN(prev_bank_end, PAGES_PER_SECTION));
|
||||
if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
|
||||
free_memmap(prev_end,
|
||||
ALIGN(prev_end, PAGES_PER_SECTION));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -535,7 +528,7 @@ void __init mem_init(void)
|
||||
set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
|
||||
|
||||
/* this will put all unused low memory onto the freelists */
|
||||
free_unused_memmap(&meminfo);
|
||||
free_unused_memmap();
|
||||
free_all_bootmem();
|
||||
|
||||
#ifdef CONFIG_SA1111
|
||||
|
@@ -438,6 +438,13 @@ void __arm_iounmap(volatile void __iomem *io_addr)
|
||||
EXPORT_SYMBOL(__arm_iounmap);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int pci_ioremap_mem_type = MT_DEVICE;
|
||||
|
||||
void pci_ioremap_set_mem_type(int mem_type)
|
||||
{
|
||||
pci_ioremap_mem_type = mem_type;
|
||||
}
|
||||
|
||||
int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
|
||||
{
|
||||
BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
|
||||
@@ -445,7 +452,7 @@ int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
|
||||
return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
|
||||
PCI_IO_VIRT_BASE + offset + SZ_64K,
|
||||
phys_addr,
|
||||
__pgprot(get_mem_type(MT_DEVICE)->prot_pte));
|
||||
__pgprot(get_mem_type(pci_ioremap_mem_type)->prot_pte));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_ioremap_io);
|
||||
#endif
|
||||
|
20
arch/arm/mm/l2c-common.c
Normal file
20
arch/arm/mm/l2c-common.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2010 ARM Ltd.
|
||||
* Written by Catalin Marinas <catalin.marinas@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/bug.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/outercache.h>
|
||||
|
||||
void outer_disable(void)
|
||||
{
|
||||
WARN_ON(!irqs_disabled());
|
||||
WARN_ON(num_online_cpus() > 1);
|
||||
|
||||
if (outer_cache.disable)
|
||||
outer_cache.disable();
|
||||
}
|
58
arch/arm/mm/l2c-l2x0-resume.S
Normal file
58
arch/arm/mm/l2c-l2x0-resume.S
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* L2C-310 early resume code. This can be used by platforms to restore
|
||||
* the settings of their L2 cache controller before restoring the
|
||||
* processor state.
|
||||
*
|
||||
* This code can only be used to if you are running in the secure world.
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
.text
|
||||
|
||||
ENTRY(l2c310_early_resume)
|
||||
adr r0, 1f
|
||||
ldr r2, [r0]
|
||||
add r0, r2, r0
|
||||
|
||||
ldmia r0, {r1, r2, r3, r4, r5, r6, r7, r8}
|
||||
@ r1 = phys address of L2C-310 controller
|
||||
@ r2 = aux_ctrl
|
||||
@ r3 = tag_latency
|
||||
@ r4 = data_latency
|
||||
@ r5 = filter_start
|
||||
@ r6 = filter_end
|
||||
@ r7 = prefetch_ctrl
|
||||
@ r8 = pwr_ctrl
|
||||
|
||||
@ Check that the address has been initialised
|
||||
teq r1, #0
|
||||
moveq pc, lr
|
||||
|
||||
@ The prefetch and power control registers are revision dependent
|
||||
@ and can be written whether or not the L2 cache is enabled
|
||||
ldr r0, [r1, #L2X0_CACHE_ID]
|
||||
and r0, r0, #L2X0_CACHE_ID_RTL_MASK
|
||||
cmp r0, #L310_CACHE_ID_RTL_R2P0
|
||||
strcs r7, [r1, #L310_PREFETCH_CTRL]
|
||||
cmp r0, #L310_CACHE_ID_RTL_R3P0
|
||||
strcs r8, [r1, #L310_POWER_CTRL]
|
||||
|
||||
@ Don't setup the L2 cache if it is already enabled
|
||||
ldr r0, [r1, #L2X0_CTRL]
|
||||
tst r0, #L2X0_CTRL_EN
|
||||
movne pc, lr
|
||||
|
||||
str r3, [r1, #L310_TAG_LATENCY_CTRL]
|
||||
str r4, [r1, #L310_DATA_LATENCY_CTRL]
|
||||
str r6, [r1, #L310_ADDR_FILTER_END]
|
||||
str r5, [r1, #L310_ADDR_FILTER_START]
|
||||
|
||||
str r2, [r1, #L2X0_AUX_CTRL]
|
||||
mov r9, #L2X0_CTRL_EN
|
||||
str r9, [r1, #L2X0_CTRL]
|
||||
mov pc, lr
|
||||
ENDPROC(l2c310_early_resume)
|
||||
|
||||
.align
|
||||
1: .long l2x0_saved_regs - .
|
@@ -2,6 +2,8 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/* the upper-most page table pointer */
|
||||
extern pmd_t *top_pmd;
|
||||
|
||||
@@ -93,3 +95,5 @@ extern phys_addr_t arm_lowmem_limit;
|
||||
void __init bootmem_init(void);
|
||||
void arm_mm_memblock_reserve(void);
|
||||
void dma_contiguous_remap(void);
|
||||
|
||||
unsigned long __clear_cr(unsigned long mask);
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/pci.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#include "mm.h"
|
||||
#include "tcm.h"
|
||||
@@ -117,28 +118,54 @@ static struct cachepolicy cache_policies[] __initdata = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CPU_CP15
|
||||
static unsigned long initial_pmd_value __initdata = 0;
|
||||
|
||||
/*
|
||||
* These are useful for identifying cache coherency
|
||||
* problems by allowing the cache or the cache and
|
||||
* writebuffer to be turned off. (Note: the write
|
||||
* buffer should not be on and the cache off).
|
||||
* Initialise the cache_policy variable with the initial state specified
|
||||
* via the "pmd" value. This is used to ensure that on ARMv6 and later,
|
||||
* the C code sets the page tables up with the same policy as the head
|
||||
* assembly code, which avoids an illegal state where the TLBs can get
|
||||
* confused. See comments in early_cachepolicy() for more information.
|
||||
*/
|
||||
void __init init_default_cache_policy(unsigned long pmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
initial_pmd_value = pmd;
|
||||
|
||||
pmd &= PMD_SECT_TEX(1) | PMD_SECT_BUFFERABLE | PMD_SECT_CACHEABLE;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cache_policies); i++)
|
||||
if (cache_policies[i].pmd == pmd) {
|
||||
cachepolicy = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cache_policies))
|
||||
pr_err("ERROR: could not find cache policy\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* These are useful for identifying cache coherency problems by allowing
|
||||
* the cache or the cache and writebuffer to be turned off. (Note: the
|
||||
* write buffer should not be on and the cache off).
|
||||
*/
|
||||
static int __init early_cachepolicy(char *p)
|
||||
{
|
||||
int i;
|
||||
int i, selected = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
|
||||
int len = strlen(cache_policies[i].policy);
|
||||
|
||||
if (memcmp(p, cache_policies[i].policy, len) == 0) {
|
||||
cachepolicy = i;
|
||||
cr_alignment &= ~cache_policies[i].cr_mask;
|
||||
cr_no_alignment &= ~cache_policies[i].cr_mask;
|
||||
selected = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(cache_policies))
|
||||
printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
|
||||
|
||||
if (selected == -1)
|
||||
pr_err("ERROR: unknown or unsupported cache policy\n");
|
||||
|
||||
/*
|
||||
* This restriction is partly to do with the way we boot; it is
|
||||
* unpredictable to have memory mapped using two different sets of
|
||||
@@ -146,12 +173,18 @@ static int __init early_cachepolicy(char *p)
|
||||
* change these attributes once the initial assembly has setup the
|
||||
* page tables.
|
||||
*/
|
||||
if (cpu_architecture() >= CPU_ARCH_ARMv6) {
|
||||
printk(KERN_WARNING "Only cachepolicy=writeback supported on ARMv6 and later\n");
|
||||
cachepolicy = CPOLICY_WRITEBACK;
|
||||
if (cpu_architecture() >= CPU_ARCH_ARMv6 && selected != cachepolicy) {
|
||||
pr_warn("Only cachepolicy=%s supported on ARMv6 and later\n",
|
||||
cache_policies[cachepolicy].policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (selected != cachepolicy) {
|
||||
unsigned long cr = __clear_cr(cache_policies[selected].cr_mask);
|
||||
cachepolicy = selected;
|
||||
flush_cache_all();
|
||||
set_cr(cr);
|
||||
}
|
||||
flush_cache_all();
|
||||
set_cr(cr_alignment);
|
||||
return 0;
|
||||
}
|
||||
early_param("cachepolicy", early_cachepolicy);
|
||||
@@ -186,35 +219,6 @@ static int __init early_ecc(char *p)
|
||||
early_param("ecc", early_ecc);
|
||||
#endif
|
||||
|
||||
static int __init noalign_setup(char *__unused)
|
||||
{
|
||||
cr_alignment &= ~CR_A;
|
||||
cr_no_alignment &= ~CR_A;
|
||||
set_cr(cr_alignment);
|
||||
return 1;
|
||||
}
|
||||
__setup("noalign", noalign_setup);
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
void adjust_cr(unsigned long mask, unsigned long set)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
mask &= ~CR_A;
|
||||
|
||||
set &= mask;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
cr_no_alignment = (cr_no_alignment & ~mask) | set;
|
||||
cr_alignment = (cr_alignment & ~mask) | set;
|
||||
|
||||
set_cr((get_cr() & ~mask) | set);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* ifdef CONFIG_CPU_CP15 */
|
||||
|
||||
static int __init early_cachepolicy(char *p)
|
||||
@@ -414,8 +418,17 @@ static void __init build_mem_type_table(void)
|
||||
cachepolicy = CPOLICY_WRITEBACK;
|
||||
ecc_mask = 0;
|
||||
}
|
||||
if (is_smp())
|
||||
cachepolicy = CPOLICY_WRITEALLOC;
|
||||
|
||||
if (is_smp()) {
|
||||
if (cachepolicy != CPOLICY_WRITEALLOC) {
|
||||
pr_warn("Forcing write-allocate cache policy for SMP\n");
|
||||
cachepolicy = CPOLICY_WRITEALLOC;
|
||||
}
|
||||
if (!(initial_pmd_value & PMD_SECT_S)) {
|
||||
pr_warn("Forcing shared mappings for SMP\n");
|
||||
initial_pmd_value |= PMD_SECT_S;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip out features not present on earlier architectures.
|
||||
@@ -539,11 +552,12 @@ static void __init build_mem_type_table(void)
|
||||
mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
|
||||
#endif
|
||||
|
||||
if (is_smp()) {
|
||||
/*
|
||||
* Mark memory with the "shared" attribute
|
||||
* for SMP systems
|
||||
*/
|
||||
/*
|
||||
* If the initial page tables were created with the S bit
|
||||
* set, then we need to do the same here for the same
|
||||
* reasons given in early_cachepolicy().
|
||||
*/
|
||||
if (initial_pmd_value & PMD_SECT_S) {
|
||||
user_pgprot |= L_PTE_SHARED;
|
||||
kern_pgprot |= L_PTE_SHARED;
|
||||
vecs_pgprot |= L_PTE_SHARED;
|
||||
@@ -1061,74 +1075,47 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
|
||||
void __init sanity_check_meminfo(void)
|
||||
{
|
||||
phys_addr_t memblock_limit = 0;
|
||||
int i, j, highmem = 0;
|
||||
int highmem = 0;
|
||||
phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
|
||||
struct memblock_region *reg;
|
||||
|
||||
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
|
||||
struct membank *bank = &meminfo.bank[j];
|
||||
phys_addr_t size_limit;
|
||||
for_each_memblock(memory, reg) {
|
||||
phys_addr_t block_start = reg->base;
|
||||
phys_addr_t block_end = reg->base + reg->size;
|
||||
phys_addr_t size_limit = reg->size;
|
||||
|
||||
*bank = meminfo.bank[i];
|
||||
size_limit = bank->size;
|
||||
|
||||
if (bank->start >= vmalloc_limit)
|
||||
if (reg->base >= vmalloc_limit)
|
||||
highmem = 1;
|
||||
else
|
||||
size_limit = vmalloc_limit - bank->start;
|
||||
size_limit = vmalloc_limit - reg->base;
|
||||
|
||||
bank->highmem = highmem;
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
/*
|
||||
* Split those memory banks which are partially overlapping
|
||||
* the vmalloc area greatly simplifying things later.
|
||||
*/
|
||||
if (!highmem && bank->size > size_limit) {
|
||||
if (meminfo.nr_banks >= NR_BANKS) {
|
||||
printk(KERN_CRIT "NR_BANKS too low, "
|
||||
"ignoring high memory\n");
|
||||
} else {
|
||||
memmove(bank + 1, bank,
|
||||
(meminfo.nr_banks - i) * sizeof(*bank));
|
||||
meminfo.nr_banks++;
|
||||
i++;
|
||||
bank[1].size -= size_limit;
|
||||
bank[1].start = vmalloc_limit;
|
||||
bank[1].highmem = highmem = 1;
|
||||
j++;
|
||||
if (!IS_ENABLED(CONFIG_HIGHMEM) || cache_is_vipt_aliasing()) {
|
||||
|
||||
if (highmem) {
|
||||
pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
|
||||
&block_start, &block_end);
|
||||
memblock_remove(reg->base, reg->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reg->size > size_limit) {
|
||||
phys_addr_t overlap_size = reg->size - size_limit;
|
||||
|
||||
pr_notice("Truncating RAM at %pa-%pa to -%pa",
|
||||
&block_start, &block_end, &vmalloc_limit);
|
||||
memblock_remove(vmalloc_limit, overlap_size);
|
||||
block_end = vmalloc_limit;
|
||||
}
|
||||
bank->size = size_limit;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Highmem banks not allowed with !CONFIG_HIGHMEM.
|
||||
*/
|
||||
if (highmem) {
|
||||
printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
|
||||
"(!CONFIG_HIGHMEM).\n",
|
||||
(unsigned long long)bank->start,
|
||||
(unsigned long long)bank->start + bank->size - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether this memory bank would partially overlap
|
||||
* the vmalloc area.
|
||||
*/
|
||||
if (bank->size > size_limit) {
|
||||
printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
|
||||
"to -%.8llx (vmalloc region overlap).\n",
|
||||
(unsigned long long)bank->start,
|
||||
(unsigned long long)bank->start + bank->size - 1,
|
||||
(unsigned long long)bank->start + size_limit - 1);
|
||||
bank->size = size_limit;
|
||||
}
|
||||
#endif
|
||||
if (!bank->highmem) {
|
||||
phys_addr_t bank_end = bank->start + bank->size;
|
||||
|
||||
if (bank_end > arm_lowmem_limit)
|
||||
arm_lowmem_limit = bank_end;
|
||||
if (!highmem) {
|
||||
if (block_end > arm_lowmem_limit) {
|
||||
if (reg->size > size_limit)
|
||||
arm_lowmem_limit = vmalloc_limit;
|
||||
else
|
||||
arm_lowmem_limit = block_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the first non-section-aligned page, and point
|
||||
@@ -1144,35 +1131,15 @@ void __init sanity_check_meminfo(void)
|
||||
* occurs before any free memory is mapped.
|
||||
*/
|
||||
if (!memblock_limit) {
|
||||
if (!IS_ALIGNED(bank->start, SECTION_SIZE))
|
||||
memblock_limit = bank->start;
|
||||
else if (!IS_ALIGNED(bank_end, SECTION_SIZE))
|
||||
memblock_limit = bank_end;
|
||||
if (!IS_ALIGNED(block_start, SECTION_SIZE))
|
||||
memblock_limit = block_start;
|
||||
else if (!IS_ALIGNED(block_end, SECTION_SIZE))
|
||||
memblock_limit = arm_lowmem_limit;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
if (highmem) {
|
||||
const char *reason = NULL;
|
||||
|
||||
if (cache_is_vipt_aliasing()) {
|
||||
/*
|
||||
* Interactions between kmap and other mappings
|
||||
* make highmem support with aliasing VIPT caches
|
||||
* rather difficult.
|
||||
*/
|
||||
reason = "with VIPT aliasing cache";
|
||||
}
|
||||
if (reason) {
|
||||
printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n",
|
||||
reason);
|
||||
while (j > 0 && meminfo.bank[j - 1].highmem)
|
||||
j--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
meminfo.nr_banks = j;
|
||||
|
||||
high_memory = __va(arm_lowmem_limit - 1) + 1;
|
||||
|
||||
/*
|
||||
@@ -1359,6 +1326,9 @@ static void __init kmap_init(void)
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
|
||||
PKMAP_BASE, _PAGE_KERNEL_TABLE);
|
||||
|
||||
fixmap_page_table = early_pte_alloc(pmd_off_k(FIXADDR_START),
|
||||
FIXADDR_START, _PAGE_KERNEL_TABLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1461,7 +1431,7 @@ void __init early_paging_init(const struct machine_desc *mdesc,
|
||||
* just complicate the code.
|
||||
*/
|
||||
flush_cache_louis();
|
||||
dsb();
|
||||
dsb(ishst);
|
||||
isb();
|
||||
|
||||
/* remap level 1 table */
|
||||
|
@@ -88,30 +88,35 @@ static unsigned long irbar_read(void)
|
||||
void __init sanity_check_meminfo_mpu(void)
|
||||
{
|
||||
int i;
|
||||
struct membank *bank = meminfo.bank;
|
||||
phys_addr_t phys_offset = PHYS_OFFSET;
|
||||
phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
|
||||
struct memblock_region *reg;
|
||||
bool first = true;
|
||||
phys_addr_t mem_start;
|
||||
phys_addr_t mem_end;
|
||||
|
||||
/* Initially only use memory continuous from PHYS_OFFSET */
|
||||
if (bank_phys_start(&bank[0]) != phys_offset)
|
||||
panic("First memory bank must be contiguous from PHYS_OFFSET");
|
||||
for_each_memblock(memory, reg) {
|
||||
if (first) {
|
||||
/*
|
||||
* Initially only use memory continuous from
|
||||
* PHYS_OFFSET */
|
||||
if (reg->base != phys_offset)
|
||||
panic("First memory bank must be contiguous from PHYS_OFFSET");
|
||||
|
||||
/* Banks have already been sorted by start address */
|
||||
for (i = 1; i < meminfo.nr_banks; i++) {
|
||||
if (bank[i].start <= bank_phys_end(&bank[0]) &&
|
||||
bank_phys_end(&bank[i]) > bank_phys_end(&bank[0])) {
|
||||
bank[0].size = bank_phys_end(&bank[i]) - bank[0].start;
|
||||
mem_start = reg->base;
|
||||
mem_end = reg->base + reg->size;
|
||||
specified_mem_size = reg->size;
|
||||
first = false;
|
||||
} else {
|
||||
pr_notice("Ignoring RAM after 0x%.8lx. "
|
||||
"First non-contiguous (ignored) bank start: 0x%.8lx\n",
|
||||
(unsigned long)bank_phys_end(&bank[0]),
|
||||
(unsigned long)bank_phys_start(&bank[i]));
|
||||
break;
|
||||
/*
|
||||
* memblock auto merges contiguous blocks, remove
|
||||
* all blocks afterwards
|
||||
*/
|
||||
pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n",
|
||||
&mem_start, ®->base);
|
||||
memblock_remove(reg->base, reg->size);
|
||||
}
|
||||
}
|
||||
/* All contiguous banks are now merged in to the first bank */
|
||||
meminfo.nr_banks = 1;
|
||||
specified_mem_size = bank[0].size;
|
||||
|
||||
/*
|
||||
* MPU has curious alignment requirements: Size must be power of 2, and
|
||||
@@ -128,23 +133,24 @@ void __init sanity_check_meminfo_mpu(void)
|
||||
*/
|
||||
aligned_region_size = (phys_offset - 1) ^ (phys_offset);
|
||||
/* Find the max power-of-two sized region that fits inside our bank */
|
||||
rounded_mem_size = (1 << __fls(bank[0].size)) - 1;
|
||||
rounded_mem_size = (1 << __fls(specified_mem_size)) - 1;
|
||||
|
||||
/* The actual region size is the smaller of the two */
|
||||
aligned_region_size = aligned_region_size < rounded_mem_size
|
||||
? aligned_region_size + 1
|
||||
: rounded_mem_size + 1;
|
||||
|
||||
if (aligned_region_size != specified_mem_size)
|
||||
pr_warn("Truncating memory from 0x%.8lx to 0x%.8lx (MPU region constraints)",
|
||||
(unsigned long)specified_mem_size,
|
||||
(unsigned long)aligned_region_size);
|
||||
if (aligned_region_size != specified_mem_size) {
|
||||
pr_warn("Truncating memory from %pa to %pa (MPU region constraints)",
|
||||
&specified_mem_size, &aligned_region_size);
|
||||
memblock_remove(mem_start + aligned_region_size,
|
||||
specified_mem_size - aligned_round_size);
|
||||
|
||||
meminfo.bank[0].size = aligned_region_size;
|
||||
pr_debug("MPU Region from 0x%.8lx size 0x%.8lx (end 0x%.8lx))\n",
|
||||
(unsigned long)phys_offset,
|
||||
(unsigned long)aligned_region_size,
|
||||
(unsigned long)bank_phys_end(&bank[0]));
|
||||
mem_end = mem_start + aligned_region_size;
|
||||
}
|
||||
|
||||
pr_debug("MPU Region from %pa size %pa (end %pa))\n",
|
||||
&phys_offset, &aligned_region_size, &mem_end);
|
||||
|
||||
}
|
||||
|
||||
@@ -292,7 +298,7 @@ void __init sanity_check_meminfo(void)
|
||||
{
|
||||
phys_addr_t end;
|
||||
sanity_check_meminfo_mpu();
|
||||
end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]);
|
||||
end = memblock_end_of_DRAM();
|
||||
high_memory = __va(end - 1) + 1;
|
||||
}
|
||||
|
||||
|
@@ -64,6 +64,14 @@ ENTRY(cpu_v7_switch_mm)
|
||||
mov pc, lr
|
||||
ENDPROC(cpu_v7_switch_mm)
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define rl r3
|
||||
#define rh r2
|
||||
#else
|
||||
#define rl r2
|
||||
#define rh r3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu_v7_set_pte_ext(ptep, pte)
|
||||
*
|
||||
@@ -73,13 +81,13 @@ ENDPROC(cpu_v7_switch_mm)
|
||||
*/
|
||||
ENTRY(cpu_v7_set_pte_ext)
|
||||
#ifdef CONFIG_MMU
|
||||
tst r2, #L_PTE_VALID
|
||||
tst rl, #L_PTE_VALID
|
||||
beq 1f
|
||||
tst r3, #1 << (57 - 32) @ L_PTE_NONE
|
||||
bicne r2, #L_PTE_VALID
|
||||
tst rh, #1 << (57 - 32) @ L_PTE_NONE
|
||||
bicne rl, #L_PTE_VALID
|
||||
bne 1f
|
||||
tst r3, #1 << (55 - 32) @ L_PTE_DIRTY
|
||||
orreq r2, #L_PTE_RDONLY
|
||||
tst rh, #1 << (55 - 32) @ L_PTE_DIRTY
|
||||
orreq rl, #L_PTE_RDONLY
|
||||
1: strd r2, r3, [r0]
|
||||
ALT_SMP(W(nop))
|
||||
ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte
|
||||
|
@@ -169,9 +169,31 @@ ENDPROC(cpu_pj4b_do_idle)
|
||||
globl_equ cpu_pj4b_do_idle, cpu_v7_do_idle
|
||||
#endif
|
||||
globl_equ cpu_pj4b_dcache_clean_area, cpu_v7_dcache_clean_area
|
||||
globl_equ cpu_pj4b_do_suspend, cpu_v7_do_suspend
|
||||
globl_equ cpu_pj4b_do_resume, cpu_v7_do_resume
|
||||
globl_equ cpu_pj4b_suspend_size, cpu_v7_suspend_size
|
||||
#ifdef CONFIG_ARM_CPU_SUSPEND
|
||||
ENTRY(cpu_pj4b_do_suspend)
|
||||
stmfd sp!, {r6 - r10}
|
||||
mrc p15, 1, r6, c15, c1, 0 @ save CP15 - extra features
|
||||
mrc p15, 1, r7, c15, c2, 0 @ save CP15 - Aux Func Modes Ctrl 0
|
||||
mrc p15, 1, r8, c15, c1, 2 @ save CP15 - Aux Debug Modes Ctrl 2
|
||||
mrc p15, 1, r9, c15, c1, 1 @ save CP15 - Aux Debug Modes Ctrl 1
|
||||
mrc p15, 0, r10, c9, c14, 0 @ save CP15 - PMC
|
||||
stmia r0!, {r6 - r10}
|
||||
ldmfd sp!, {r6 - r10}
|
||||
b cpu_v7_do_suspend
|
||||
ENDPROC(cpu_pj4b_do_suspend)
|
||||
|
||||
ENTRY(cpu_pj4b_do_resume)
|
||||
ldmia r0!, {r6 - r10}
|
||||
mcr p15, 1, r6, c15, c1, 0 @ save CP15 - extra features
|
||||
mcr p15, 1, r7, c15, c2, 0 @ save CP15 - Aux Func Modes Ctrl 0
|
||||
mcr p15, 1, r8, c15, c1, 2 @ save CP15 - Aux Debug Modes Ctrl 2
|
||||
mcr p15, 1, r9, c15, c1, 1 @ save CP15 - Aux Debug Modes Ctrl 1
|
||||
mcr p15, 0, r10, c9, c14, 0 @ save CP15 - PMC
|
||||
b cpu_v7_do_resume
|
||||
ENDPROC(cpu_pj4b_do_resume)
|
||||
#endif
|
||||
.globl cpu_pj4b_suspend_size
|
||||
.equ cpu_pj4b_suspend_size, 4 * 14
|
||||
|
||||
#endif
|
||||
|
||||
@@ -194,6 +216,7 @@ __v7_cr7mp_setup:
|
||||
__v7_ca7mp_setup:
|
||||
__v7_ca12mp_setup:
|
||||
__v7_ca15mp_setup:
|
||||
__v7_ca17mp_setup:
|
||||
mov r10, #0
|
||||
1:
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -504,6 +527,16 @@ __v7_ca15mp_proc_info:
|
||||
__v7_proc __v7_ca15mp_setup
|
||||
.size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
|
||||
|
||||
/*
|
||||
* ARM Ltd. Cortex A17 processor.
|
||||
*/
|
||||
.type __v7_ca17mp_proc_info, #object
|
||||
__v7_ca17mp_proc_info:
|
||||
.long 0x410fc0e0
|
||||
.long 0xff0ffff0
|
||||
__v7_proc __v7_ca17mp_setup
|
||||
.size __v7_ca17mp_proc_info, . - __v7_ca17mp_proc_info
|
||||
|
||||
/*
|
||||
* Qualcomm Inc. Krait processors.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user