Commit a5888e32 authored by Don Mahurin's avatar Don Mahurin Committed by Dmitriy Cherkasov

ARM64: ipipe: add pipeline core

parent 21099751
......@@ -82,7 +82,7 @@ config ARM64
select HAVE_CC_STACKPROTECTOR
select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL
select HAVE_CONTEXT_TRACKING
select HAVE_CONTEXT_TRACKING if !IPIPE
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG
......@@ -678,6 +678,7 @@ config HOLES_IN_ZONE
def_bool y
depends on NUMA
source kernel/ipipe/Kconfig
source kernel/Kconfig.preempt
source kernel/Kconfig.hz
......
......@@ -51,6 +51,18 @@
msr daif, \flags
.endm
.macro disable_irq_cond
#ifdef CONFIG_IPIPE
msr daifset, #2
#endif
.endm
.macro enable_irq_cond
#ifdef CONFIG_IPIPE
msr daifclr, #2
#endif
.endm
/*
* Enable and disable debug exceptions.
*/
......
/* -*- linux-c -*-
* arch/arm/include/asm/ipipe.h
*
* Copyright (C) 2002-2005 Philippe Gerum.
* Copyright (C) 2005 Stelian Pop.
* Copyright (C) 2006-2008 Gilles Chanteperdrix.
* Copyright (C) 2010 Philippe Gerum (SMP port).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
* USA; either version 2 of the License, or (at your option) any later
* version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __ARM_IPIPE_H
#define __ARM_IPIPE_H
#include <linux/irqdomain.h>
#ifdef CONFIG_IPIPE
#include <linux/jump_label.h>
#include <linux/ipipe_trace.h>
#include <linux/ipipe_debug.h>
#define IPIPE_CORE_RELEASE 2
struct ipipe_domain;
#define IPIPE_TSC_TYPE_NONE 0
#define IPIPE_TSC_TYPE_FREERUNNING 1
#define IPIPE_TSC_TYPE_DECREMENTER 2
#define IPIPE_TSC_TYPE_FREERUNNING_COUNTDOWN 3
#define IPIPE_TSC_TYPE_FREERUNNING_TWICE 4
#define IPIPE_TSC_TYPE_FREERUNNING_ARCH 5
/* tscinfo, exported to user-space */
struct __ipipe_tscinfo {
unsigned type;
unsigned freq;
unsigned long counter_vaddr;
union {
struct {
unsigned long counter_paddr;
unsigned long long mask;
};
struct {
unsigned *counter; /* Hw counter physical address */
unsigned long long mask; /* Significant bits in the hw counter. */
unsigned long long *tsc; /* 64 bits tsc value. */
} fr;
struct {
unsigned *counter; /* Hw counter physical address */
unsigned long long mask; /* Significant bits in the hw counter. */
unsigned *last_cnt; /* Counter value when updating
tsc value. */
unsigned long long *tsc; /* 64 bits tsc value. */
} dec;
} u;
};
struct ipipe_arch_sysinfo {
struct __ipipe_tscinfo tsc;
};
/* arch specific stuff */
void __ipipe_mach_get_tscinfo(struct __ipipe_tscinfo *info);
static inline void __ipipe_mach_update_tsc(void) {}
static inline notrace unsigned long long __ipipe_mach_get_tsc(void)
{
return arch_counter_get_cntvct();
}
#define __ipipe_tsc_get() __ipipe_mach_get_tsc()
void __ipipe_tsc_register(struct __ipipe_tscinfo *info);
static inline void __ipipe_tsc_update(void) {}
#ifndef __ipipe_hrclock_freq
extern unsigned long __ipipe_hrtimer_freq;
#define __ipipe_hrclock_freq __ipipe_hrtimer_freq
#endif /* !__ipipe_mach_hrclock_freq */
#ifdef CONFIG_IPIPE_DEBUG_INTERNAL
extern void (*__ipipe_mach_hrtimer_debug)(unsigned irq);
#endif /* CONFIG_IPIPE_DEBUG_INTERNAL */
#define ipipe_mm_switch_protect(__flags) \
do { \
(__flags) = hard_cond_local_irq_save(); \
} while (0)
#define ipipe_mm_switch_unprotect(__flags) \
hard_cond_local_irq_restore(__flags)
#define ipipe_read_tsc(t) do { t = __ipipe_tsc_get(); } while(0)
#define __ipipe_read_timebase() __ipipe_tsc_get()
#define ipipe_tsc2ns(t) \
({ \
unsigned long long delta = (t)*1000; \
do_div(delta, __ipipe_hrclock_freq / 1000000 + 1); \
(unsigned long)delta; \
})
#define ipipe_tsc2us(t) \
({ \
unsigned long long delta = (t); \
do_div(delta, __ipipe_hrclock_freq / 1000000 + 1); \
(unsigned long)delta; \
})
static inline const char *ipipe_clock_name(void)
{
return "ipipe_tsc";
}
/* Private interface -- Internal use only */
#define __ipipe_enable_irq(irq) enable_irq(irq)
#define __ipipe_disable_irq(irq) disable_irq(irq)
/* PIC muting */
struct ipipe_mach_pic_muter {
void (*enable_irqdesc)(struct ipipe_domain *ipd, unsigned irq);
void (*disable_irqdesc)(struct ipipe_domain *ipd, unsigned irq);
void (*mute)(void);
void (*unmute)(void);
};
extern struct ipipe_mach_pic_muter ipipe_pic_muter;
void ipipe_pic_muter_register(struct ipipe_mach_pic_muter *muter);
void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq);
void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq);
static inline void ipipe_mute_pic(void)
{
if (ipipe_pic_muter.mute)
ipipe_pic_muter.mute();
}
static inline void ipipe_unmute_pic(void)
{
if (ipipe_pic_muter.unmute)
ipipe_pic_muter.unmute();
}
#define ipipe_notify_root_preemption() do { } while(0)
#ifdef CONFIG_SMP
void __ipipe_early_core_setup(void);
void __ipipe_hook_critical_ipi(struct ipipe_domain *ipd);
void __ipipe_root_localtimer(unsigned int irq, void *cookie);
void __ipipe_grab_ipi(unsigned svc, struct pt_regs *regs);
void __ipipe_ipis_alloc(void);
void __ipipe_ipis_request(void);
static inline void ipipe_handle_multi_ipi(int irq, struct pt_regs *regs)
{
__ipipe_grab_ipi(irq, regs);
}
#ifdef CONFIG_SMP_ON_UP
extern struct static_key __ipipe_smp_key;
#define ipipe_smp_p (static_key_true(&__ipipe_smp_key))
#endif /* SMP_ON_UP */
#else /* !CONFIG_SMP */
#define __ipipe_early_core_setup() do { } while(0)
#define __ipipe_hook_critical_ipi(ipd) do { } while(0)
#endif /* !CONFIG_SMP */
#ifndef __ipipe_mach_init_platform
#define __ipipe_mach_init_platform() do { } while(0)
#endif
void __ipipe_enable_pipeline(void);
void __ipipe_do_critical_sync(unsigned irq, void *cookie);
void __ipipe_grab_irq(int irq, struct pt_regs *regs);
void __ipipe_exit_irq(struct pt_regs *regs);
static inline
int ipipe_handle_domain_irq(struct irq_domain *domain,
unsigned int hwirq, struct pt_regs *regs)
{
unsigned int irq;
irq = irq_find_mapping(domain, hwirq);
__ipipe_grab_irq(irq, regs);
return 0;
}
static inline unsigned long __ipipe_ffnz(unsigned long ul)
{
int __r;
/* zero input is not valid */
IPIPE_WARN(ul == 0);
__asm__ ("rbit\t%0, %1\n"
"clz\t%0, %0\n"
: "=r" (__r) : "r"(ul) : "cc");
return __r;
}
#define __ipipe_syscall_watched_p(p, sc) \
(ipipe_notifier_enabled_p(p) || (unsigned long)sc >= __NR_syscalls)
#define __ipipe_root_tick_p(regs) (!arch_irqs_disabled_flags(regs->pstate))
#else /* !CONFIG_IPIPE */
#include <linux/irq.h>
#include <linux/irqdesc.h>
#define __ipipe_tsc_update() do { } while(0)
#define hard_smp_processor_id() smp_processor_id()
#define ipipe_mm_switch_protect(flags) \
do { \
(void) (flags); \
} while(0)
#define ipipe_mm_switch_unprotect(flags) \
do { \
(void) (flags); \
} while(0)
#ifdef CONFIG_SMP
static inline void ipipe_handle_multi_ipi(int irq, struct pt_regs *regs)
{
handle_IPI(irq, regs);
}
#endif /* CONFIG_SMP */
static inline
int ipipe_handle_domain_irq(struct irq_domain *domain,
unsigned int hwirq, struct pt_regs *regs)
{
return handle_domain_irq(domain, hwirq, regs);
}
#endif /* CONFIG_IPIPE */
#endif /* !__ARM_IPIPE_H */
/* -*- linux-c -*-
* arch/arm/include/asm/ipipe_base.h
*
* Copyright (C) 2007 Gilles Chanteperdrix.
* Copyright (C) 2010 Philippe Gerum (SMP port).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
* USA; either version 2 of the License, or (at your option) any later
* version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __ASM_ARM_IPIPE_BASE_H
#define __ASM_ARM_IPIPE_BASE_H
#include <asm-generic/ipipe.h>
#ifdef CONFIG_IPIPE
#define IPIPE_NR_ROOT_IRQS 1024
#define IPIPE_NR_XIRQS IPIPE_NR_ROOT_IRQS
#ifdef CONFIG_SMP
extern unsigned __ipipe_first_ipi;
#define IPIPE_CRITICAL_IPI __ipipe_first_ipi
#define IPIPE_HRTIMER_IPI (IPIPE_CRITICAL_IPI + 1)
#define IPIPE_RESCHEDULE_IPI (IPIPE_CRITICAL_IPI + 2)
#define IPIPE_LAST_IPI IPIPE_RESCHEDULE_IPI
#ifdef CONFIG_IPIPE_LEGACY
#define hard_smp_processor_id() \
({ \
unsigned int cpunum; \
__asm__ __volatile__ ("\n" \
"1: mrc p15, 0, %0, c0, c0, 5\n" \
" .pushsection \".alt.smp.init\", \"a\"\n" \
" .long 1b\n" \
" mov %0, #0\n" \
" .popsection" \
: "=r" (cpunum)); \
cpunum &= 0xFF; \
})
extern u32 __cpu_logical_map[];
#define ipipe_processor_id() (__cpu_logical_map[hard_smp_processor_id()])
#else /* !legacy */
#define hard_smp_processor_id() raw_smp_processor_id()
#ifdef CONFIG_SMP_ON_UP
unsigned __ipipe_processor_id(void);
#define ipipe_processor_id() \
({ \
register unsigned int cpunum __asm__ ("r0"); \
register unsigned int r1 __asm__ ("r1"); \
register unsigned int r2 __asm__ ("r2"); \
register unsigned int r3 __asm__ ("r3"); \
register unsigned int ip __asm__ ("ip"); \
register unsigned int lr __asm__ ("lr"); \
__asm__ __volatile__ ("\n" \
"1: bl __ipipe_processor_id\n" \
" .pushsection \".alt.smp.init\", \"a\"\n" \
" .long 1b\n" \
" mov %0, #0\n" \
" .popsection" \
: "=r"(cpunum), "=r"(r1), "=r"(r2), "=r"(r3), \
"=r"(ip), "=r"(lr) \
: /* */ : "cc"); \
cpunum; \
})
#else /* !SMP_ON_UP */
#define ipipe_processor_id() raw_smp_processor_id()
#endif /* !SMP_ON_UP */
#endif /* !legacy */
#define IPIPE_ARCH_HAVE_VIRQ_IPI
#else /* !CONFIG_SMP */
#define ipipe_processor_id() (0)
#endif /* !CONFIG_IPIPE */
/* ARM traps */
#define IPIPE_TRAP_ACCESS 0 /* Data or instruction access exception */
#define IPIPE_TRAP_SECTION 1 /* Section fault */
#define IPIPE_TRAP_DABT 2 /* Generic data abort */
#define IPIPE_TRAP_UNKNOWN 3 /* Unknown exception */
#define IPIPE_TRAP_BREAK 4 /* Instruction breakpoint */
#define IPIPE_TRAP_FPU_ACC 5 /* Floating point access */
#define IPIPE_TRAP_FPU_EXC 6 /* Floating point exception */
#define IPIPE_TRAP_UNDEFINSTR 7 /* Undefined instruction */
#define IPIPE_TRAP_ALIGNMENT 8 /* Unaligned access exception */
#define IPIPE_TRAP_MAYDAY 9 /* Internal recovery trap */
#define IPIPE_NR_FAULTS 10
#ifndef __ASSEMBLY__
#ifdef CONFIG_SMP
void ipipe_stall_root(void);
unsigned long ipipe_test_and_stall_root(void);
unsigned long ipipe_test_root(void);
#else /* !CONFIG_SMP */
#include <asm/irqflags.h>
#if __GNUC__ >= 4
/* Alias to ipipe_root_cpudom_var(status) */
extern unsigned long __ipipe_root_status;
#else
extern unsigned long *const __ipipe_root_status_addr;
#define __ipipe_root_status (*__ipipe_root_status_addr)
#endif
static inline void ipipe_stall_root(void)
{
unsigned long flags;
flags = hard_local_irq_save();
__ipipe_root_status |= 1;
hard_local_irq_restore(flags);
}
static inline unsigned ipipe_test_root(void)
{
return __ipipe_root_status & 1;
}
static inline unsigned ipipe_test_and_stall_root(void)
{
unsigned long flags, res;
flags = hard_local_irq_save();
res = __ipipe_root_status;
__ipipe_root_status = res | 1;
hard_local_irq_restore(flags);
return res & 1;
}
#endif /* !CONFIG_SMP */
#endif /* !__ASSEMBLY__ */
#endif /* CONFIG_IPIPE */
#endif /* __ASM_ARM_IPIPE_BASE_H */
/* -*- linux-c -*-
* arch/arm/include/asm/ipipe_hwirq.h
*
* Copyright (C) 2002-2005 Philippe Gerum.
* Copyright (C) 2005 Stelian Pop.
* Copyright (C) 2006-2008 Gilles Chanteperdrix.
* Copyright (C) 2010 Philippe Gerum (SMP port).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
* USA; either version 2 of the License, or (at your option) any later
* version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _ASM_ARM_IPIPE_HWIRQ_H
#define _ASM_ARM_IPIPE_HWIRQ_H
#define hard_local_irq_restore_notrace(x) \
__asm__ __volatile__( \
"msr daif, %0" \
: \
: "r" (x) \
: "memory", "cc")
static inline void hard_local_irq_disable_notrace(void)
{
__asm__ __volatile__("msr daifset, #2" : : : "memory", "cc");
}
static inline void hard_local_irq_enable_notrace(void)
{
__asm__ __volatile__("msr daifclr, #2" : : : "memory", "cc");
}
static inline void hard_local_fiq_disable_notrace(void)
{
__asm__ __volatile__("msr daifset, #1" : : : "memory", "cc");
}
static inline void hard_local_fiq_enable_notrace(void)
{
__asm__ __volatile__("msr daifclr, #1" : : : "memory", "cc");
}
static inline unsigned long hard_local_irq_save_notrace(void)
{
unsigned long res;
__asm__ __volatile__(
"mrs %0, daif\n"
"msr daifset, #2"
: "=r" (res) : : "memory", "cc");
return res;
}
#include <asm-generic/ipipe.h>
#ifdef CONFIG_IPIPE
#include <linux/ipipe_trace.h>
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return (int)((flags) & PSR_I_BIT);
}
static inline unsigned long hard_local_save_flags(void)
{
unsigned long flags;
__asm__ __volatile__(
"mrs %0, daif"
: "=r" (flags) : : "memory", "cc");
return flags;
}
#define hard_irqs_disabled_flags(flags) arch_irqs_disabled_flags(flags)
static inline int hard_irqs_disabled(void)
{
return hard_irqs_disabled_flags(hard_local_save_flags());
}
#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
static inline void hard_local_irq_disable(void)
{
if (!hard_irqs_disabled()) {
hard_local_irq_disable_notrace();
ipipe_trace_begin(0x80000000);
}
}
static inline void hard_local_irq_enable(void)
{
if (hard_irqs_disabled()) {
ipipe_trace_end(0x80000000);
hard_local_irq_enable_notrace();
}
}
static inline unsigned long hard_local_irq_save(void)
{
unsigned long flags;
flags = hard_local_irq_save_notrace();
if (!arch_irqs_disabled_flags(flags))
ipipe_trace_begin(0x80000001);
return flags;
}
static inline void hard_local_irq_restore(unsigned long x)
{
if (!arch_irqs_disabled_flags(x))
ipipe_trace_end(0x80000001);
hard_local_irq_restore_notrace(x);
}
#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
#define hard_local_irq_disable hard_local_irq_disable_notrace
#define hard_local_irq_enable hard_local_irq_enable_notrace
#define hard_local_irq_save hard_local_irq_save_notrace
#define hard_local_irq_restore hard_local_irq_restore_notrace
#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
#define arch_local_irq_disable() \
({ \
ipipe_stall_root(); \
barrier(); \
})
#define arch_local_irq_enable() \
do { \
barrier(); \
ipipe_unstall_root(); \
} while (0)
#define local_fiq_enable() hard_local_fiq_enable_notrace()
#define local_fiq_disable() hard_local_fiq_disable_notrace()
#define arch_local_irq_restore(flags) \
do { \
if (!arch_irqs_disabled_flags(flags)) \
arch_local_irq_enable(); \
} while (0)
#define arch_local_irq_save() \
({ \
unsigned long _flags; \
_flags = ipipe_test_and_stall_root() << 7; \
barrier(); \
_flags; \
})
#define arch_local_save_flags() \
({ \
unsigned long _flags; \
_flags = ipipe_test_root() << 7; \
barrier(); \
_flags; \
})
#define arch_irqs_disabled() ipipe_test_root()
#define hard_irq_disable() hard_local_irq_disable()
static inline unsigned long arch_mangle_irq_bits(int virt, unsigned long real)
{
/* Merge virtual and real interrupt mask bits into a single
32bit word. */
return (real & ~(1L << 8)) | ((virt != 0) << 8);
}
static inline int arch_demangle_irq_bits(unsigned long *x)
{
int virt = (*x & (1 << 8)) != 0;
*x &= ~(1L << 8);
return virt;
}
#else /* !CONFIG_IPIPE */
#define hard_local_irq_save() arch_local_irq_save()
#define hard_local_irq_restore(x) arch_local_irq_restore(x)
#define hard_local_irq_enable() arch_local_irq_enable()
#define hard_local_irq_disable() arch_local_irq_disable()
#define hard_irqs_disabled() irqs_disabled()
#define hard_cond_local_irq_enable() do { } while(0)
#define hard_cond_local_irq_disable() do { } while(0)
#define hard_cond_local_irq_save() 0
#define hard_cond_local_irq_restore(flags) do { (void)(flags); } while(0)
#endif /* !CONFIG_IPIPE */
#if defined(CONFIG_SMP) && defined(CONFIG_IPIPE)
#define hard_smp_local_irq_save() hard_local_irq_save()
#define hard_smp_local_irq_restore(flags) hard_local_irq_restore(flags)
#else /* !CONFIG_SMP */
#define hard_smp_local_irq_save() 0
#define hard_smp_local_irq_restore(flags) do { (void)(flags); } while(0)
#endif /* CONFIG_SMP */
#endif /* _ASM_ARM_IPIPE_HWIRQ_H */
......@@ -20,6 +20,10 @@
#include <asm/ptrace.h>
#include <asm/ipipe_hwirq.h>
#ifndef CONFIG_IPIPE
/*
* CPU interrupt mask handling.
*/
......@@ -56,8 +60,6 @@ static inline void arch_local_irq_disable(void)
#define local_fiq_enable() asm("msr daifclr, #1" : : : "memory")
#define local_fiq_disable() asm("msr daifset, #1" : : : "memory")
#define local_async_enable() asm("msr daifclr, #4" : : : "memory")
#define local_async_disable() asm("msr daifset, #4" : : : "memory")
/*
* Save the current interrupt enable state.
......@@ -90,6 +92,7 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
return flags & PSR_I_BIT;
}
#endif /* CONFIG_IPIPE */
/*
* save and restore debug state
*/
......@@ -110,5 +113,8 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
: : "r" (flags) : "memory"); \
} while (0)
#define local_async_enable() asm("msr daifclr, #4" : : : "memory")
#define local_async_disable() asm("msr daifset, #4" : : : "memory")
#endif
#endif
......@@ -17,6 +17,7 @@
#define __ASM_PERCPU_H
#include <asm/stack_pointer.h>
#include <asm/ipipe_base.h>
static inline void set_my_cpu_offset(unsigned long off)
{
......
......@@ -39,7 +39,7 @@ static inline u32 mpidr_hash_size(void)
/*
* Logical CPU mapping.
*/
extern u64 __cpu_logical_map[NR_CPUS];
extern u64 __cpu_logical_map[];
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
/*
* Retrieve logical cpu index corresponding to a given MPIDR.Aff*
......
......@@ -30,6 +30,7 @@ struct task_struct;
#include <asm/memory.h>
#include <asm/stack_pointer.h>
#include <asm/types.h>
#include <ipipe/thread_info.h>
typedef unsigned long mm_segment_t;
......@@ -43,6 +44,10 @@ struct thread_info {
u64 ttbr0; /* saved TTBR0_EL1 */
#endif
int preempt_count; /* 0 => preemptable, <0 => bug */
#ifdef CONFIG_IPIPE
unsigned long ipipe_flags;
#endif
struct ipipe_threadinfo ipipe_data;
};
#define INIT_THREAD_INFO(tsk) \
......@@ -114,5 +119,14 @@ void arch_setup_new_exec(void);
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \