- SMP support for the PSCI booting protocol (power state coordination

interface).
 - Simple earlyprintk support.
 - Platform devices populated by default from the DT (SoC-agnostic).
 - CONTEXTIDR support (used by external trace tools).
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.9 (GNU/Linux)
 
 iQIcBAABAgAGBQJRJOI1AAoJEGvWsS0AyF7xzfwP/0vyy1BE9oBWsISu/ITCfMa0
 X6nffGoh1bcq2TqwqYD3M9gH5HJkd/JzyGDyuJdZB72XOB2Z0eiZYTs1E46MhP8g
 17FH0QJG0D5hi32byDM8A1NC+z2Ep6YRDQzlvG1F2StsLDJqZIL0tsSdld8L7gu6
 F/IS6NQy2eGmCcFvX7MCBRien53dPxYhrQfzKcUcCsWZDy1HfSoOBZE4XhZO3eTL
 HiAMDtqb1mTxsHOHHehJLOcEeFH4U7FM1k525VFzrFgCoZ10N85X57guzhnK63Bj
 zmdlP0CvVZDt/vGU08ZJDDWahGzDo6i1tLF66ZDy888zG/QjM2AdGjz99YH/L2so
 TrqGvVtX89doV5isvmS0mJjDx42QwO9881DlrDSMumWu2iVtwmRWcrdZ5MPSyrKU
 bhrDU57/EvHTMbNScaA4SrPVhM2kIoUUYJBLDxiaKfk577mjFod/gfhgg7Mc0I67
 q3jWv9NdcODmX5FAWXZ2jQ0Lz1PsVHNNjpZZQY3TKMLbSLgk+Vcsu07quWxtJl6K
 QqOGAS9QWX6jb1qIxw8NdB0qbGpGR2jIHBRtMNNB65luPm8EqH4bHmGWy6fUahJr
 8UJBUA+v5kRjYwtO6AAtzaJavYePRhAqMIGUu8eoatPzN5JOObp9RAtYuQZNTN9v
 asKJKRGfD8kwBSeovt+X
 =2prj
 -----END PGP SIGNATURE-----

Merge tag 'arm64-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64

Pull arm64 patches from Catalin Marinas:

 - SMP support for the PSCI booting protocol (power state coordination
   interface).

 - Simple earlyprintk support.

 - Platform devices populated by default from the DT (SoC-agnostic).

 - CONTEXTIDR support (used by external trace tools).

* tag 'arm64-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64:
  arm64: mm: update CONTEXTIDR register to contain PID of current process
  arm64: atomics: fix grossly inconsistent asm constraints for exclusives
  arm64: compat: use compat_uptr_t type for compat_ucontext.uc_link
  arm64: Select ARCH_WANT_FRAME_POINTERS
  arm64: Add kvm_para.h and xor.h generic headers
  arm64: SMP: enable PSCI boot method
  arm64: psci: add support for PSCI invocations from the kernel
  arm64: SMP: rework the SMP code to be enabling method agnostic
  arm64: perf: add guest vs host discrimination
  arm64: add COMPAT_PSR_*_BIT flags
  arm64: Add simple earlyprintk support
  arm64: Populate the platform devices
This commit is contained in:
Linus Torvalds 2013-02-20 14:30:33 -08:00
commit 79a69d342d
29 changed files with 855 additions and 173 deletions

View File

@ -35,6 +35,8 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]
ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O space
ffffffbbffff0000 ffffffbcffffffff ~2MB [guard]

View File

@ -2,6 +2,7 @@ config ARM64
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select ARCH_WANT_FRAME_POINTERS
select ARM_AMBA
select CLONE_BACKWARDS
select COMMON_CLK

View File

@ -24,4 +24,21 @@ config DEBUG_STACK_USAGE
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T output.
config EARLY_PRINTK
bool "Early printk support"
default y
help
Say Y here if you want to have an early console using the
earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It
is assumed that the early console device has been initialised
by the boot loader prior to starting the Linux kernel.
config PID_IN_CONTEXTIDR
bool "Write the current PID to the CONTEXTIDR register"
help
Enabling this option causes the kernel to write the current PID to
the CONTEXTIDR register, at the expense of some additional
instructions during context switch. Say Y here only if you are
planning to use hardware trace tools with this kernel.
endmenu

View File

@ -19,6 +19,7 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
generic-y += mman.h
@ -48,3 +49,4 @@ generic-y += trace_clock.h
generic-y += types.h
generic-y += unaligned.h
generic-y += user.h
generic-y += xor.h

View File

@ -49,12 +49,12 @@ static inline void atomic_add(int i, atomic_t *v)
int result;
asm volatile("// atomic_add\n"
"1: ldxr %w0, [%3]\n"
" add %w0, %w0, %w4\n"
" stxr %w1, %w0, [%3]\n"
"1: ldxr %w0, %2\n"
" add %w0, %w0, %w3\n"
" stxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc");
}
@ -64,13 +64,13 @@ static inline int atomic_add_return(int i, atomic_t *v)
int result;
asm volatile("// atomic_add_return\n"
"1: ldaxr %w0, [%3]\n"
" add %w0, %w0, %w4\n"
" stlxr %w1, %w0, [%3]\n"
"1: ldaxr %w0, %2\n"
" add %w0, %w0, %w3\n"
" stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc", "memory");
return result;
}
@ -81,12 +81,12 @@ static inline void atomic_sub(int i, atomic_t *v)
int result;
asm volatile("// atomic_sub\n"
"1: ldxr %w0, [%3]\n"
" sub %w0, %w0, %w4\n"
" stxr %w1, %w0, [%3]\n"
"1: ldxr %w0, %2\n"
" sub %w0, %w0, %w3\n"
" stxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc");
}
@ -96,13 +96,13 @@ static inline int atomic_sub_return(int i, atomic_t *v)
int result;
asm volatile("// atomic_sub_return\n"
"1: ldaxr %w0, [%3]\n"
" sub %w0, %w0, %w4\n"
" stlxr %w1, %w0, [%3]\n"
"1: ldaxr %w0, %2\n"
" sub %w0, %w0, %w3\n"
" stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc", "memory");
return result;
}
@ -113,15 +113,15 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
int oldval;
asm volatile("// atomic_cmpxchg\n"
"1: ldaxr %w1, [%3]\n"
" cmp %w1, %w4\n"
"1: ldaxr %w1, %2\n"
" cmp %w1, %w3\n"
" b.ne 2f\n"
" stlxr %w0, %w5, [%3]\n"
" stlxr %w0, %w4, %2\n"
" cbnz %w0, 1b\n"
"2:"
: "=&r" (tmp), "=&r" (oldval), "+o" (ptr->counter)
: "r" (&ptr->counter), "Ir" (old), "r" (new)
: "cc");
: "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter)
: "Ir" (old), "r" (new)
: "cc", "memory");
return oldval;
}
@ -131,12 +131,12 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
unsigned long tmp, tmp2;
asm volatile("// atomic_clear_mask\n"
"1: ldxr %0, [%3]\n"
" bic %0, %0, %4\n"
" stxr %w1, %0, [%3]\n"
"1: ldxr %0, %2\n"
" bic %0, %0, %3\n"
" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
: "=&r" (tmp), "=&r" (tmp2), "+o" (*addr)
: "r" (addr), "Ir" (mask)
: "=&r" (tmp), "=&r" (tmp2), "+Q" (*addr)
: "Ir" (mask)
: "cc");
}
@ -182,12 +182,12 @@ static inline void atomic64_add(u64 i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_add\n"
"1: ldxr %0, [%3]\n"
" add %0, %0, %4\n"
" stxr %w1, %0, [%3]\n"
"1: ldxr %0, %2\n"
" add %0, %0, %3\n"
" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc");
}
@ -197,13 +197,13 @@ static inline long atomic64_add_return(long i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_add_return\n"
"1: ldaxr %0, [%3]\n"
" add %0, %0, %4\n"
" stlxr %w1, %0, [%3]\n"
"1: ldaxr %0, %2\n"
" add %0, %0, %3\n"
" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc", "memory");
return result;
}
@ -214,12 +214,12 @@ static inline void atomic64_sub(u64 i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_sub\n"
"1: ldxr %0, [%3]\n"
" sub %0, %0, %4\n"
" stxr %w1, %0, [%3]\n"
"1: ldxr %0, %2\n"
" sub %0, %0, %3\n"
" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc");
}
@ -229,13 +229,13 @@ static inline long atomic64_sub_return(long i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_sub_return\n"
"1: ldaxr %0, [%3]\n"
" sub %0, %0, %4\n"
" stlxr %w1, %0, [%3]\n"
"1: ldaxr %0, %2\n"
" sub %0, %0, %3\n"
" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter), "Ir" (i)
: "cc");
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (i)
: "cc", "memory");
return result;
}
@ -246,15 +246,15 @@ static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new)
unsigned long res;
asm volatile("// atomic64_cmpxchg\n"
"1: ldaxr %1, [%3]\n"
" cmp %1, %4\n"
"1: ldaxr %1, %2\n"
" cmp %1, %3\n"
" b.ne 2f\n"
" stlxr %w0, %5, [%3]\n"
" stlxr %w0, %4, %2\n"
" cbnz %w0, 1b\n"
"2:"
: "=&r" (res), "=&r" (oldval), "+o" (ptr->counter)
: "r" (&ptr->counter), "Ir" (old), "r" (new)
: "cc");
: "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter)
: "Ir" (old), "r" (new)
: "cc", "memory");
return oldval;
}
@ -267,15 +267,15 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_dec_if_positive\n"
"1: ldaxr %0, [%3]\n"
"1: ldaxr %0, %2\n"
" subs %0, %0, #1\n"
" b.mi 2f\n"
" stlxr %w1, %0, [%3]\n"
" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b\n"
"2:"
: "=&r" (result), "=&r" (tmp), "+o" (v->counter)
: "r" (&v->counter)
: "cc");
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
:
: "cc", "memory");
return result;
}

View File

@ -29,39 +29,39 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
switch (size) {
case 1:
asm volatile("// __xchg1\n"
"1: ldaxrb %w0, [%3]\n"
" stlxrb %w1, %w2, [%3]\n"
"1: ldaxrb %w0, %2\n"
" stlxrb %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
: "=&r" (ret), "=&r" (tmp)
: "r" (x), "r" (ptr)
: "memory", "cc");
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)
: "r" (x)
: "cc", "memory");
break;
case 2:
asm volatile("// __xchg2\n"
"1: ldaxrh %w0, [%3]\n"
" stlxrh %w1, %w2, [%3]\n"
"1: ldaxrh %w0, %2\n"
" stlxrh %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
: "=&r" (ret), "=&r" (tmp)
: "r" (x), "r" (ptr)
: "memory", "cc");
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr)
: "r" (x)
: "cc", "memory");
break;
case 4:
asm volatile("// __xchg4\n"
"1: ldaxr %w0, [%3]\n"
" stlxr %w1, %w2, [%3]\n"
"1: ldaxr %w0, %2\n"
" stlxr %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
: "=&r" (ret), "=&r" (tmp)
: "r" (x), "r" (ptr)
: "memory", "cc");
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr)
: "r" (x)
: "cc", "memory");
break;
case 8:
asm volatile("// __xchg8\n"
"1: ldaxr %0, [%3]\n"
" stlxr %w1, %2, [%3]\n"
"1: ldaxr %0, %2\n"
" stlxr %w1, %3, %2\n"
" cbnz %w1, 1b\n"
: "=&r" (ret), "=&r" (tmp)
: "r" (x), "r" (ptr)
: "memory", "cc");
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr)
: "r" (x)
: "cc", "memory");
break;
default:
BUILD_BUG();
@ -82,14 +82,14 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 1:
do {
asm volatile("// __cmpxchg1\n"
" ldxrb %w1, [%2]\n"
" ldxrb %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
" stxrb %w0, %w4, [%2]\n"
" stxrb %w0, %w4, %2\n"
"1:\n"
: "=&r" (res), "=&r" (oldval)
: "r" (ptr), "Ir" (old), "r" (new)
: "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
: "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
@ -97,29 +97,29 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 2:
do {
asm volatile("// __cmpxchg2\n"
" ldxrh %w1, [%2]\n"
" ldxrh %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
" stxrh %w0, %w4, [%2]\n"
" stxrh %w0, %w4, %2\n"
"1:\n"
: "=&r" (res), "=&r" (oldval)
: "r" (ptr), "Ir" (old), "r" (new)
: "memory", "cc");
: "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
: "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
case 4:
do {
asm volatile("// __cmpxchg4\n"
" ldxr %w1, [%2]\n"
" ldxr %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
" stxr %w0, %w4, [%2]\n"
" stxr %w0, %w4, %2\n"
"1:\n"
: "=&r" (res), "=&r" (oldval)
: "r" (ptr), "Ir" (old), "r" (new)
: "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
: "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
@ -127,14 +127,14 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 8:
do {
asm volatile("// __cmpxchg8\n"
" ldxr %1, [%2]\n"
" ldxr %1, %2\n"
" mov %w0, #0\n"
" cmp %1, %3\n"
" b.ne 1f\n"
" stxr %w0, %4, [%2]\n"
" stxr %w0, %4, %2\n"
"1:\n"
: "=&r" (res), "=&r" (oldval)
: "r" (ptr), "Ir" (old), "r" (new)
: "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
: "Ir" (old), "r" (new)
: "cc");
} while (res);
break;

View File

@ -39,7 +39,7 @@
" .popsection\n" \
: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \
: "r" (oparg), "Ir" (-EFAULT) \
: "cc")
: "cc", "memory")
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)

View File

@ -230,6 +230,9 @@ extern void __iounmap(volatile void __iomem *addr);
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define iounmap __iounmap
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF)
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PTE_PXN | PTE_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
#define ARCH_HAS_IOREMAP_WC
#include <asm-generic/iomap.h>

View File

@ -43,6 +43,7 @@
#define PAGE_OFFSET UL(0xffffffc000000000)
#define MODULES_END (PAGE_OFFSET)
#define MODULES_VADDR (MODULES_END - SZ_64M)
#define EARLYCON_IOBASE (MODULES_VADDR - SZ_4M)
#define VA_BITS (39)
#define TASK_SIZE_64 (UL(1) << VA_BITS)

View File

@ -26,5 +26,6 @@ typedef struct {
extern void paging_init(void);
extern void setup_mm_for_reboot(void);
extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
#endif

View File

@ -35,6 +35,21 @@ extern unsigned int cpu_last_asid;
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void __new_context(struct mm_struct *mm);
#ifdef CONFIG_PID_IN_CONTEXTIDR
static inline void contextidr_thread_switch(struct task_struct *next)
{
asm(
" msr contextidr_el1, %0\n"
" isb"
:
: "r" (task_pid_nr(next)));
}
#else
static inline void contextidr_thread_switch(struct task_struct *next)
{
}
#endif
/*
* Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0.
*/

View File

@ -17,6 +17,11 @@
#ifndef __ASM_PERF_EVENT_H
#define __ASM_PERF_EVENT_H
/* It's quiet around here... */
#ifdef CONFIG_HW_PERF_EVENTS
struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#endif
#endif

View File

@ -0,0 +1,38 @@
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2013 ARM Limited
*/
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
#define PSCI_POWER_STATE_TYPE_STANDBY 0
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
struct psci_power_state {
u16 id;
u8 type;
u8 affinity_level;
};
struct psci_operations {
int (*cpu_suspend)(struct psci_power_state state,
unsigned long entry_point);
int (*cpu_off)(struct psci_power_state state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
int (*migrate)(unsigned long cpuid);
};
extern struct psci_operations psci_ops;
int psci_init(void);
#endif /* __ASM_PSCI_H */

View File

@ -42,6 +42,16 @@
#define COMPAT_PSR_MODE_UND 0x0000001b
#define COMPAT_PSR_MODE_SYS 0x0000001f
#define COMPAT_PSR_T_BIT 0x00000020
#define COMPAT_PSR_F_BIT 0x00000040
#define COMPAT_PSR_I_BIT 0x00000080
#define COMPAT_PSR_A_BIT 0x00000100
#define COMPAT_PSR_E_BIT 0x00000200
#define COMPAT_PSR_J_BIT 0x01000000
#define COMPAT_PSR_Q_BIT 0x08000000
#define COMPAT_PSR_V_BIT 0x10000000
#define COMPAT_PSR_C_BIT 0x20000000
#define COMPAT_PSR_Z_BIT 0x40000000
#define COMPAT_PSR_N_BIT 0x80000000
#define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
/*
* These are 'magic' values for PTRACE_PEEKUSR that return info about where a

View File

@ -66,4 +66,15 @@ extern volatile unsigned long secondary_holding_pen_release;
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
struct device_node;
struct smp_enable_ops {
const char *name;
int (*init_cpu)(struct device_node *, int);
int (*prepare_cpu)(int);
};
extern const struct smp_enable_ops smp_spin_table_ops;
extern const struct smp_enable_ops smp_psci_ops;
#endif /* ifndef __ASM_SMP_H */

View File

@ -45,13 +45,13 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
asm volatile(
" sevl\n"
"1: wfe\n"
"2: ldaxr %w0, [%1]\n"
"2: ldaxr %w0, %1\n"
" cbnz %w0, 1b\n"
" stxr %w0, %w2, [%1]\n"
" stxr %w0, %w2, %1\n"
" cbnz %w0, 2b\n"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
: "memory");
: "=&r" (tmp), "+Q" (lock->lock)
: "r" (1)
: "cc", "memory");
}
static inline int arch_spin_trylock(arch_spinlock_t *lock)
@ -59,13 +59,13 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
unsigned int tmp;
asm volatile(
" ldaxr %w0, [%1]\n"
" ldaxr %w0, %1\n"
" cbnz %w0, 1f\n"
" stxr %w0, %w2, [%1]\n"
" stxr %w0, %w2, %1\n"
"1:\n"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
: "memory");
: "=&r" (tmp), "+Q" (lock->lock)
: "r" (1)
: "cc", "memory");
return !tmp;
}
@ -73,8 +73,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
asm volatile(
" stlr %w1, [%0]\n"
: : "r" (&lock->lock), "r" (0) : "memory");
" stlr %w1, %0\n"
: "=Q" (lock->lock) : "r" (0) : "memory");
}
/*
@ -94,13 +94,13 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
asm volatile(
" sevl\n"
"1: wfe\n"
"2: ldaxr %w0, [%1]\n"
"2: ldaxr %w0, %1\n"
" cbnz %w0, 1b\n"
" stxr %w0, %w2, [%1]\n"
" stxr %w0, %w2, %1\n"
" cbnz %w0, 2b\n"
: "=&r" (tmp)
: "r" (&rw->lock), "r" (0x80000000)
: "memory");
: "=&r" (tmp), "+Q" (rw->lock)
: "r" (0x80000000)
: "cc", "memory");
}
static inline int arch_write_trylock(arch_rwlock_t *rw)
@ -108,13 +108,13 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
unsigned int tmp;
asm volatile(
" ldaxr %w0, [%1]\n"
" ldaxr %w0, %1\n"
" cbnz %w0, 1f\n"
" stxr %w0, %w2, [%1]\n"
" stxr %w0, %w2, %1\n"
"1:\n"
: "=&r" (tmp)
: "r" (&rw->lock), "r" (0x80000000)
: "memory");
: "=&r" (tmp), "+Q" (rw->lock)
: "r" (0x80000000)
: "cc", "memory");
return !tmp;
}
@ -122,8 +122,8 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
static inline void arch_write_unlock(arch_rwlock_t *rw)
{
asm volatile(
" stlr %w1, [%0]\n"
: : "r" (&rw->lock), "r" (0) : "memory");
" stlr %w1, %0\n"
: "=Q" (rw->lock) : "r" (0) : "memory");
}
/* write_can_lock - would write_trylock() succeed? */
@ -148,14 +148,14 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
asm volatile(
" sevl\n"
"1: wfe\n"
"2: ldaxr %w0, [%2]\n"
"2: ldaxr %w0, %2\n"
" add %w0, %w0, #1\n"
" tbnz %w0, #31, 1b\n"
" stxr %w1, %w0, [%2]\n"
" stxr %w1, %w0, %2\n"
" cbnz %w1, 2b\n"
: "=&r" (tmp), "=&r" (tmp2)
: "r" (&rw->lock)
: "memory");
: "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
:
: "cc", "memory");
}
static inline void arch_read_unlock(arch_rwlock_t *rw)
@ -163,13 +163,13 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
unsigned int tmp, tmp2;
asm volatile(
"1: ldxr %w0, [%2]\n"
"1: ldxr %w0, %2\n"
" sub %w0, %w0, #1\n"
" stlxr %w1, %w0, [%2]\n"
" stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b\n"
: "=&r" (tmp), "=&r" (tmp2)
: "r" (&rw->lock)
: "memory");
: "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
:
: "cc", "memory");
}
static inline int arch_read_trylock(arch_rwlock_t *rw)
@ -177,14 +177,14 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
unsigned int tmp, tmp2 = 1;
asm volatile(
" ldaxr %w0, [%2]\n"
" ldaxr %w0, %2\n"
" add %w0, %w0, #1\n"
" tbnz %w0, #31, 1f\n"
" stxr %w1, %w0, [%2]\n"
" stxr %w1, %w0, %2\n"
"1:\n"
: "=&r" (tmp), "+r" (tmp2)
: "r" (&rw->lock)
: "memory");
: "=&r" (tmp), "+r" (tmp2), "+Q" (rw->lock)
:
: "cc", "memory");
return !tmp2;
}

View File

@ -1,11 +1,14 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += kvm_para.h
header-y += auxvec.h
header-y += bitsperlong.h
header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h

View File

@ -9,14 +9,15 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o
hyp-stub.o psci.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)

View File

@ -0,0 +1,118 @@
/*
* Earlyprintk support.
*
* Copyright (C) 2012 ARM Ltd.
* Author: 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/amba/serial.h>
static void __iomem *early_base;
static void (*printch)(char ch);
/*
* PL011 single character TX.
*/
static void pl011_printch(char ch)
{
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
;
writeb_relaxed(ch, early_base + UART01x_DR);
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
;
}
struct earlycon_match {
const char *name;
void (*printch)(char ch);
};
static const struct earlycon_match earlycon_match[] __initconst = {
{ .name = "pl011", .printch = pl011_printch, },
{}
};
static void early_write(struct console *con, const char *s, unsigned n)
{
while (n-- > 0) {
if (*s == '\n')
printch('\r');
printch(*s);
s++;
}
}
static struct console early_console = {
.name = "earlycon",
.write = early_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
/*
* Parse earlyprintk=... parameter in the format:
*
* <name>[,<addr>][,<options>]
*
* and register the early console. It is assumed that the UART has been
* initialised by the bootloader already.
*/
static int __init setup_early_printk(char *buf)
{
const struct earlycon_match *match = earlycon_match;
phys_addr_t paddr = 0;
if (!buf) {
pr_warning("No earlyprintk arguments passed.\n");
return 0;
}
while (match->name) {
size_t len = strlen(match->name);
if (!strncmp(buf, match->name, len)) {
buf += len;
break;
}
match++;
}
if (!match->name) {
pr_warning("Unknown earlyprintk arguments: %s\n", buf);
return 0;
}
/* I/O address */
if (!strncmp(buf, ",0x", 3)) {
char *e;
paddr = simple_strtoul(buf + 1, &e, 16);
buf = e;
}
/* no options parsing yet */
if (paddr)
early_base = early_io_map(paddr, EARLYCON_IOBASE);
printch = match->printch;
register_console(&early_console);
return 0;
}
early_param("earlyprintk", setup_early_printk);

View File

@ -82,10 +82,8 @@
#ifdef CONFIG_ARM64_64K_PAGES
#define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS
#define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS
#else
#define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS
#define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS
#endif
/*
@ -368,6 +366,7 @@ ENDPROC(__calc_phys_offset)
* - identity mapping to enable the MMU (low address, TTBR0)
* - first few MB of the kernel linear mapping to jump to once the MMU has
* been enabled, including the FDT blob (TTBR1)
* - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1)
*/
__create_page_tables:
pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses
@ -420,6 +419,15 @@ __create_page_tables:
sub x6, x6, #1 // inclusive range
create_block_map x0, x7, x3, x5, x6
1:
#ifdef CONFIG_EARLY_PRINTK
/*
* Create the pgd entry for the UART mapping. The full mapping is done
* later based earlyprintk kernel parameter.
*/
ldr x5, =EARLYCON_IOBASE // UART virtual address
add x0, x26, #2 * PAGE_SIZE // section table address
create_pgd_entry x26, x0, x5, x6, x7
#endif
ret
ENDPROC(__create_page_tables)
.ltorg

View File

@ -1331,6 +1331,11 @@ void perf_callchain_user(struct perf_callchain_entry *entry,
{
struct frame_tail __user *tail;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
tail = (struct frame_tail __user *)regs->regs[29];
while (entry->nr < PERF_MAX_STACK_DEPTH &&
@ -1355,8 +1360,40 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
{
struct stackframe frame;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
walk_stackframe(&frame, callchain_trace, entry);
}
unsigned long perf_instruction_pointer(struct pt_regs *regs)
{
if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
return perf_guest_cbs->get_guest_ip();
return instruction_pointer(regs);
}
unsigned long perf_misc_flags(struct pt_regs *regs)
{
int misc = 0;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
if (perf_guest_cbs->is_user_mode())
misc |= PERF_RECORD_MISC_GUEST_USER;
else
misc |= PERF_RECORD_MISC_GUEST_KERNEL;
} else {
if (user_mode(regs))
misc |= PERF_RECORD_MISC_USER;
else
misc |= PERF_RECORD_MISC_KERNEL;
}
return misc;
}

View File

@ -45,9 +45,10 @@
#include <asm/compat.h>
#include <asm/cacheflush.h>
#include <asm/fpsimd.h>
#include <asm/mmu_context.h>
#include <asm/processor.h>
#include <asm/stacktrace.h>
#include <asm/fpsimd.h>
static void setup_restart(void)
{
@ -314,6 +315,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
/* the actual thread switch */
last = cpu_switch_to(prev, next);
contextidr_thread_switch(next);
return last;
}

211
arch/arm64/kernel/psci.c Normal file
View File

@ -0,0 +1,211 @@
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2013 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
*/
#define pr_fmt(fmt) "psci: " fmt
#include <linux/init.h>
#include <linux/of.h>
#include <asm/compiler.h>
#include <asm/errno.h>
#include <asm/psci.h>
struct psci_operations psci_ops;
static int (*invoke_psci_fn)(u64, u64, u64, u64);
enum psci_function {
PSCI_FN_CPU_SUSPEND,
PSCI_FN_CPU_ON,
PSCI_FN_CPU_OFF,
PSCI_FN_MIGRATE,
PSCI_FN_MAX,
};
static u32 psci_function_id[PSCI_FN_MAX];
#define PSCI_RET_SUCCESS 0
#define PSCI_RET_EOPNOTSUPP -1
#define PSCI_RET_EINVAL -2
#define PSCI_RET_EPERM -3
static int psci_to_linux_errno(int errno)
{
switch (errno) {
case PSCI_RET_SUCCESS:
return 0;
case PSCI_RET_EOPNOTSUPP:
return -EOPNOTSUPP;
case PSCI_RET_EINVAL:
return -EINVAL;
case PSCI_RET_EPERM:
return -EPERM;
};
return -EINVAL;
}
#define PSCI_POWER_STATE_ID_MASK 0xffff
#define PSCI_POWER_STATE_ID_SHIFT 0
#define PSCI_POWER_STATE_TYPE_MASK 0x1
#define PSCI_POWER_STATE_TYPE_SHIFT 16
#define PSCI_POWER_STATE_AFFL_MASK 0x3
#define PSCI_POWER_STATE_AFFL_SHIFT 24
static u32 psci_power_state_pack(struct psci_power_state state)
{
return ((state.id & PSCI_POWER_STATE_ID_MASK)
<< PSCI_POWER_STATE_ID_SHIFT) |
((state.type & PSCI_POWER_STATE_TYPE_MASK)
<< PSCI_POWER_STATE_TYPE_SHIFT) |
((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK)
<< PSCI_POWER_STATE_AFFL_SHIFT);
}
/*
* The following two functions are invoked via the invoke_psci_fn pointer
* and will not be inlined, allowing us to piggyback on the AAPCS.
*/
static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
u64 arg2)
{
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x3")
"hvc #0\n"
: "+r" (function_id)
: "r" (arg0), "r" (arg1), "r" (arg2));
return function_id;
}
static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
u64 arg2)
{
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x3")
"smc #0\n"
: "+r" (function_id)
: "r" (arg0), "r" (arg1), "r" (arg2));
return function_id;
}
static int psci_cpu_suspend(struct psci_power_state state,
unsigned long entry_point)
{
int err;
u32 fn, power_state;
fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
power_state = psci_power_state_pack(state);
err = invoke_psci_fn(fn, power_state, entry_point, 0);
return psci_to_linux_errno(err);
}
static int psci_cpu_off(struct psci_power_state state)
{
int err;
u32 fn, power_state;
fn = psci_function_id[PSCI_FN_CPU_OFF];
power_state = psci_power_state_pack(state);
err = invoke_psci_fn(fn, power_state, 0, 0);
return psci_to_linux_errno(err);
}
static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
{
int err;
u32 fn;
fn = psci_function_id[PSCI_FN_CPU_ON];
err = invoke_psci_fn(fn, cpuid, entry_point, 0);
return psci_to_linux_errno(err);
}
static int psci_migrate(unsigned long cpuid)
{
int err;
u32 fn;
fn = psci_function_id[PSCI_FN_MIGRATE];
err = invoke_psci_fn(fn, cpuid, 0, 0);
return psci_to_linux_errno(err);
}
static const struct of_device_id psci_of_match[] __initconst = {
{ .compatible = "arm,psci", },
{},
};
int __init psci_init(void)
{
struct device_node *np;
const char *method;
u32 id;
int err = 0;
np = of_find_matching_node(NULL, psci_of_match);
if (!np)
return -ENODEV;
pr_info("probing function IDs from device-tree\n");
if (of_property_read_string(np, "method", &method)) {
pr_warning("missing \"method\" property\n");
err = -ENXIO;
goto out_put_node;
}
if (!strcmp("hvc", method)) {
invoke_psci_fn = __invoke_psci_fn_hvc;
} else if (!strcmp("smc", method)) {
invoke_psci_fn = __invoke_psci_fn_smc;
} else {
pr_warning("invalid \"method\" property: %s\n", method);
err = -EINVAL;
goto out_put_node;
}
if (!of_property_read_u32(np, "cpu_suspend", &id)) {
psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
psci_ops.cpu_suspend = psci_cpu_suspend;
}
if (!of_property_read_u32(np, "cpu_off", &id)) {
psci_function_id[PSCI_FN_CPU_OFF] = id;
psci_ops.cpu_off = psci_cpu_off;
}
if (!of_property_read_u32(np, "cpu_on", &id)) {
psci_function_id[PSCI_FN_CPU_ON] = id;
psci_ops.cpu_on = psci_cpu_on;
}
if (!of_property_read_u32(np, "migrate", &id)) {
psci_function_id[PSCI_FN_MIGRATE] = id;
psci_ops.migrate = psci_migrate;
}
out_put_node:
of_node_put(np);
return err;
}

View File

@ -39,6 +39,7 @@
#include <linux/proc_fs.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <asm/cputype.h>
#include <asm/elf.h>
@ -49,6 +50,7 @@
#include <asm/tlbflush.h>
#include <asm/traps.h>
#include <asm/memblock.h>
#include <asm/psci.h>
unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
@ -260,6 +262,8 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
psci_init();
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
@ -289,6 +293,13 @@ static int __init topology_init(void)
}
subsys_initcall(topology_init);
static int __init arm64_device_probe(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
device_initcall(arm64_device_probe);
static const char *hwcap_str[] = {
"fp",
"asimd",

View File

@ -76,7 +76,7 @@ struct compat_sigcontext {
struct compat_ucontext {
compat_ulong_t uc_flags;
struct compat_ucontext *uc_link;
compat_uptr_t uc_link;
compat_stack_t uc_stack;
struct compat_sigcontext uc_mcontext;
compat_sigset_t uc_sigmask;
@ -703,7 +703,7 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= copy_siginfo_to_user32(&frame->info, info);
__put_user_error(0, &frame->sig.uc.uc_flags, err);
__put_user_error(NULL, &frame->sig.uc.uc_link, err);
__put_user_error(0, &frame->sig.uc.uc_link, err);
memset(&stack, 0, sizeof(stack));
stack.ss_sp = (compat_uptr_t)current->sas_ss_sp;

View File

@ -233,7 +233,28 @@ void __init smp_prepare_boot_cpu(void)
}
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
static phys_addr_t cpu_release_addr[NR_CPUS];
static const struct smp_enable_ops *enable_ops[] __initconst = {
&smp_spin_table_ops,
&smp_psci_ops,
NULL,
};
static const struct smp_enable_ops *smp_enable_ops[NR_CPUS];
static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
{
const struct smp_enable_ops *ops = enable_ops[0];
while (ops) {
if (!strcmp(name, ops->name))
return ops;
ops++;
}
return NULL;
}
/*
* Enumerate the possible CPU set from the device tree.
@ -252,21 +273,21 @@ void __init smp_init_cpus(void)
* We currently support only the "spin-table" enable-method.
*/
enable_method = of_get_property(dn, "enable-method", NULL);
if (!enable_method || strcmp(enable_method, "spin-table")) {
pr_err("CPU %d: missing or invalid enable-method property: %s\n",
if (!enable_method) {
pr_err("CPU %d: missing enable-method property\n", cpu);
goto next;
}
smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
if (!smp_enable_ops[cpu]) {
pr_err("CPU %d: invalid enable-method property: %s\n",
cpu, enable_method);
goto next;
}
/*
* Determine the address from which the CPU is polling.
*/
if (of_property_read_u64(dn, "cpu-release-addr",
&cpu_release_addr[cpu])) {
pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
cpu);
if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
goto next;
}
set_cpu_possible(cpu, true);
next:
@ -281,8 +302,7 @@ next:
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int cpu;
void **release_addr;
int cpu, err;
unsigned int ncores = num_possible_cpus();
/*
@ -291,30 +311,35 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if (max_cpus > ncores)
max_cpus = ncores;
/* Don't bother if we're effectively UP */
if (max_cpus <= 1)
return;
/*
* Initialise the present map (which describes the set of CPUs
* actually populated at the present time) and release the
* secondaries from the bootloader.
*
* Make sure we online at most (max_cpus - 1) additional CPUs.
*/
max_cpus--;
for_each_possible_cpu(cpu) {
if (max_cpus == 0)
break;
if (!cpu_release_addr[cpu])
if (cpu == smp_processor_id())
continue;
release_addr = __va(cpu_release_addr[cpu]);
release_addr[0] = (void *)__pa(secondary_holding_pen);
__flush_dcache_area(release_addr, sizeof(release_addr[0]));
if (!smp_enable_ops[cpu])
continue;
err = smp_enable_ops[cpu]->prepare_cpu(cpu);
if (err)
continue;
set_cpu_present(cpu, true);
max_cpus--;
}
/*
* Send an event to wake up the secondaries.
*/
sev();
}

View File

@ -0,0 +1,52 @@
/*
* PSCI SMP initialisation
*
* Copyright (C) 2013 ARM Ltd.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
#include <asm/psci.h>
static int __init smp_psci_init_cpu(struct device_node *dn, int cpu)
{
return 0;
}
static int __init smp_psci_prepare_cpu(int cpu)
{
int err;
if (!psci_ops.cpu_on) {
pr_err("psci: no cpu_on method, not booting CPU%d\n", cpu);
return -ENODEV;
}
err = psci_ops.cpu_on(cpu, __pa(secondary_holding_pen));
if (err) {
pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
return err;
}
return 0;
}
const struct smp_enable_ops smp_psci_ops __initconst = {
.name = "psci",
.init_cpu = smp_psci_init_cpu,
.prepare_cpu = smp_psci_prepare_cpu,
};

View File

@ -0,0 +1,66 @@
/*
* Spin Table SMP initialisation
*
* Copyright (C) 2013 ARM Ltd.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
#include <asm/cacheflush.h>
static phys_addr_t cpu_release_addr[NR_CPUS];
static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu)
{
/*
* Determine the address from which the CPU is polling.
*/
if (of_property_read_u64(dn, "cpu-release-addr",
&cpu_release_addr[cpu])) {
pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
cpu);
return -1;
}
return 0;
}
static int __init smp_spin_table_prepare_cpu(int cpu)
{
void **release_addr;
if (!cpu_release_addr[cpu])
return -ENODEV;
release_addr = __va(cpu_release_addr[cpu]);
release_addr[0] = (void *)__pa(secondary_holding_pen);
__flush_dcache_area(release_addr, sizeof(release_addr[0]));
/*
* Send an event to wake up the secondary CPU.
*/
sev();
return 0;
}
const struct smp_enable_ops smp_spin_table_ops __initconst = {
.name = "spin-table",
.init_cpu = smp_spin_table_init_cpu,
.prepare_cpu = smp_spin_table_prepare_cpu,
};

View File

@ -25,6 +25,7 @@
#include <linux/nodemask.h>
#include <linux/memblock.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <asm/cputype.h>
#include <asm/sections.h>
@ -251,6 +252,47 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
} while (pgd++, addr = next, addr != end);
}
#ifdef CONFIG_EARLY_PRINTK
/*
* Create an early I/O mapping using the pgd/pmd entries already populated
* in head.S as this function is called too early to allocated any memory. The
* mapping size is 2MB with 4KB pages or 64KB or 64KB pages.
*/
void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
{
unsigned long size, mask;
bool page64k = IS_ENABLED(ARM64_64K_PAGES);
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
/*
* No early pte entries with !ARM64_64K_PAGES configuration, so using
* sections (pmd).
*/
size = page64k ? PAGE_SIZE : SECTION_SIZE;
mask = ~(size - 1);
pgd = pgd_offset_k(virt);
pud = pud_offset(pgd, virt);
if (pud_none(*pud))
return NULL;
pmd = pmd_offset(pud, virt);
if (page64k) {
if (pmd_none(*pmd))
return NULL;
pte = pte_offset_kernel(pmd, virt);
set_pte(pte, __pte((phys & mask) | PROT_DEVICE_nGnRE));
} else {
set_pmd(pmd, __pmd((phys & mask) | PROT_SECT_DEVICE_nGnRE));
}
return (void __iomem *)((virt & mask) + (phys & ~mask));
}
#endif
static void __init map_mem(void)
{
struct memblock_region *reg;