Skip to content

Commit

Permalink
Merge branch 'for-rmk/lpae' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/will/linux into devel-stable

Conflicts:
	arch/arm/kernel/smp.c

Please pull these miscellaneous LPAE fixes I've been collecting for a while
now for 3.11. They've been tested and reviewed by quite a few people, and most
of the patches are pretty trivial. -- Will Deacon.
  • Loading branch information
Russell King committed Jun 18, 2013
2 parents b3f288d + a469abd commit 3fbd55e
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 96 deletions.
18 changes: 17 additions & 1 deletion arch/arm/include/asm/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <linux/types.h>
#include <linux/sizes.h>

#include <asm/cache.h>

#ifdef CONFIG_NEED_MACH_MEMORY_H
#include <mach/memory.h>
#endif
Expand Down Expand Up @@ -141,6 +143,20 @@
#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))

/*
* Minimum guaranted alignment in pgd_alloc(). The page table pointers passed
* around in head.S and proc-*.S are shifted by this amount, in order to
* leave spare high bits for systems with physical address extension. This
* does not fully accomodate the 40-bit addressing capability of ARM LPAE, but
* gives us about 38-bits or so.
*/
#ifdef CONFIG_ARM_LPAE
#define ARCH_PGD_SHIFT L1_CACHE_SHIFT
#else
#define ARCH_PGD_SHIFT 0
#endif
#define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1)

#ifndef __ASSEMBLY__

/*
Expand Down Expand Up @@ -207,7 +223,7 @@ static inline unsigned long __phys_to_virt(unsigned long x)
* direct-mapped view. We assume this is the first page
* of RAM in the mem_map as well.
*/
#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))

/*
* These are *only* valid on the kernel direct mapped RAM memory.
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/include/asm/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))

#ifndef __ASSEMBLY__

Expand Down
20 changes: 20 additions & 0 deletions arch/arm/include/asm/pgtable-3level-hwdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,24 @@
#define PHYS_MASK_SHIFT (40)
#define PHYS_MASK ((1ULL << PHYS_MASK_SHIFT) - 1)

/*
* TTBR0/TTBR1 split (PAGE_OFFSET):
* 0x40000000: T0SZ = 2, T1SZ = 0 (not used)
* 0x80000000: T0SZ = 0, T1SZ = 1
* 0xc0000000: T0SZ = 0, T1SZ = 2
*
* Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
* booting secondary CPUs would end up using TTBR1 for the identity
* mapping set up in TTBR0.
*/
#if defined CONFIG_VMSPLIT_2G
#define TTBR1_OFFSET 16 /* skip two L1 entries */
#elif defined CONFIG_VMSPLIT_3G
#define TTBR1_OFFSET (4096 * (1 + 3)) /* only L2, skip pgd + 3*pmd */
#else
#define TTBR1_OFFSET 0
#endif

#define TTBR1_SIZE (((PAGE_OFFSET >> 30) - 1) << 16)

#endif
8 changes: 4 additions & 4 deletions arch/arm/include/asm/pgtable-3level.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#define PTRS_PER_PMD 512
#define PTRS_PER_PGD 4

#define PTE_HWTABLE_PTRS (PTRS_PER_PTE)
#define PTE_HWTABLE_PTRS (0)
#define PTE_HWTABLE_OFF (0)
#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u64))

Expand All @@ -48,16 +48,16 @@
#define PMD_SHIFT 21

#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PMD_MASK (~((1 << PMD_SHIFT) - 1))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1))

/*
* section address mask and size definitions.
*/
#define SECTION_SHIFT 21
#define SECTION_SIZE (1UL << SECTION_SHIFT)
#define SECTION_MASK (~(SECTION_SIZE-1))
#define SECTION_MASK (~((1 << SECTION_SHIFT) - 1))

#define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE)

Expand Down
26 changes: 19 additions & 7 deletions arch/arm/include/asm/proc-fns.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ extern struct processor {
/*
* Set the page table
*/
void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
/*
* Set a possibly extended PTE. Non-extended PTEs should
* ignore 'ext'.
Expand All @@ -82,7 +82,7 @@ extern void cpu_proc_init(void);
extern void cpu_proc_fin(void);
extern int cpu_do_idle(void);
extern void cpu_dcache_clean_area(void *, int);
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
#ifdef CONFIG_ARM_LPAE
extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
#else
Expand Down Expand Up @@ -116,13 +116,25 @@ extern void cpu_resume(void);
#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)

#ifdef CONFIG_ARM_LPAE

#define cpu_get_ttbr(nr) \
({ \
u64 ttbr; \
__asm__("mrrc p15, " #nr ", %Q0, %R0, c2" \
: "=r" (ttbr)); \
ttbr; \
})

#define cpu_set_ttbr(nr, val) \
do { \
u64 ttbr = val; \
__asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \
: : "r" (ttbr)); \
} while (0)

#define cpu_get_pgd() \
({ \
unsigned long pg, pg2; \
__asm__("mrrc p15, 0, %0, %1, c2" \
: "=r" (pg), "=r" (pg2) \
: \
: "cc"); \
u64 pg = cpu_get_ttbr(0); \
pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1); \
(pgd_t *)phys_to_virt(pg); \
})
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/include/uapi/asm/hwcap.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
#define HWCAP_IDIVT (1 << 18)
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)

#define HWCAP_LPAE (1 << 20)

#endif /* _UAPI__ASMARM_HWCAP_H */
10 changes: 4 additions & 6 deletions arch/arm/kernel/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ ENDPROC(stext)
*
* Returns:
* r0, r3, r5-r7 corrupted
* r4 = physical page table address
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
*/
__create_page_tables:
pgtbl r4, r8 @ page table address
Expand Down Expand Up @@ -331,6 +331,7 @@ __create_page_tables:
#endif
#ifdef CONFIG_ARM_LPAE
sub r4, r4, #0x1000 @ point to the PGD table
mov r4, r4, lsr #ARCH_PGD_SHIFT
#endif
mov pc, lr
ENDPROC(__create_page_tables)
Expand Down Expand Up @@ -408,7 +409,7 @@ __secondary_data:
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
* r4 = page table pointer
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*/
Expand All @@ -427,10 +428,7 @@ __enable_mmu:
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
#ifdef CONFIG_ARM_LPAE
mov r5, #0
mcrr p15, 0, r4, r5, c2 @ load TTBR0
#else
#ifndef CONFIG_ARM_LPAE
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
Expand Down
8 changes: 7 additions & 1 deletion arch/arm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ void __init early_print(const char *str, ...)

static void __init cpuid_init_hwcaps(void)
{
unsigned int divide_instrs;
unsigned int divide_instrs, vmsa;

if (cpu_architecture() < CPU_ARCH_ARMv7)
return;
Expand All @@ -380,6 +380,11 @@ static void __init cpuid_init_hwcaps(void)
case 1:
elf_hwcap |= HWCAP_IDIVT;
}

/* LPAE implies atomic ldrd/strd instructions */
vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
if (vmsa >= 5)
elf_hwcap |= HWCAP_LPAE;
}

static void __init feat_v6_fixup(void)
Expand Down Expand Up @@ -892,6 +897,7 @@ static const char *hwcap_str[] = {
"vfpv4",
"idiva",
"idivt",
"lpae",
NULL
};

Expand Down
11 changes: 9 additions & 2 deletions arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ void __init smp_set_ops(struct smp_operations *ops)
smp_ops = *ops;
};

static unsigned long get_arch_pgd(pgd_t *pgd)
{
phys_addr_t pgdir = virt_to_phys(pgd);
BUG_ON(pgdir & ARCH_PGD_MASK);
return pgdir >> ARCH_PGD_SHIFT;
}

int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
Expand All @@ -93,8 +100,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
#endif

#ifdef CONFIG_MMU
secondary_data.pgdir = virt_to_phys(idmap_pgd);
secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
secondary_data.pgdir = get_arch_pgd(idmap_pgd);
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
Expand Down
9 changes: 2 additions & 7 deletions arch/arm/mm/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <asm/smp_plat.h>
#include <asm/thread_notify.h>
#include <asm/tlbflush.h>
#include <asm/proc-fns.h>

/*
* On ARMv6, we have the following structure in the Context ID:
Expand Down Expand Up @@ -55,17 +56,11 @@ static cpumask_t tlb_flush_pending;
#ifdef CONFIG_ARM_LPAE
static void cpu_set_reserved_ttbr0(void)
{
unsigned long ttbl = __pa(swapper_pg_dir);
unsigned long ttbh = 0;

/*
* Set TTBR0 to swapper_pg_dir which contains only global entries. The
* ASID is set to 0.
*/
asm volatile(
" mcrr p15, 0, %0, %1, c2 @ set TTBR0\n"
:
: "r" (ttbl), "r" (ttbh));
cpu_set_ttbr(0, __pa(swapper_pg_dir));
isb();
}
#else
Expand Down
19 changes: 10 additions & 9 deletions arch/arm/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@

#include "mm.h"

static unsigned long phys_initrd_start __initdata = 0;
static phys_addr_t phys_initrd_start __initdata = 0;
static unsigned long phys_initrd_size __initdata = 0;

static int __init early_initrd(char *p)
{
unsigned long start, size;
phys_addr_t start;
unsigned long size;
char *endp;

start = memparse(p, &endp);
Expand Down Expand Up @@ -350,14 +351,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
#ifdef CONFIG_BLK_DEV_INITRD
if (phys_initrd_size &&
!memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
phys_initrd_start, phys_initrd_size);
pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
(u64)phys_initrd_start, phys_initrd_size);
phys_initrd_start = phys_initrd_size = 0;
}
if (phys_initrd_size &&
memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
phys_initrd_start, phys_initrd_size);
pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
(u64)phys_initrd_start, phys_initrd_size);
phys_initrd_start = phys_initrd_size = 0;
}
if (phys_initrd_size) {
Expand Down Expand Up @@ -442,7 +443,7 @@ static inline void
free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
struct page *start_pg, *end_pg;
unsigned long pg, pgend;
phys_addr_t pg, pgend;

/*
* Convert start_pfn/end_pfn to a struct page pointer.
Expand All @@ -454,8 +455,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
* Convert to physical addresses, and
* round start upwards and end downwards.
*/
pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
pg = PAGE_ALIGN(__pa(start_pg));
pgend = __pa(end_pg) & PAGE_MASK;

/*
* If there are free pages between these,
Expand Down
Loading

0 comments on commit 3fbd55e

Please sign in to comment.