Commit 7f9f4430 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'cris-for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris

Pull arch/cris updates from Jesper Nilsson:
 "Some much needed love for the CRIS-port.

  There's a bunch of changes this time, giving the CRISv32 port a bit of
  modern makeover with device-tree, irq domain and gpiolib support, and
  more switchover to generic frameworks.

  Some small fixes and removal of the theoretical SMP support brings up
  the rear"

* tag 'cris-for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris:
  cris: fix integer overflow in ELF_ET_DYN_BASE
  CRISv32: use GENERIC_SCHED_CLOCK
  CRISv32: use MMIO clocksource
  CRISv32: use generic clockevents
  CRIS: use generic headers via Kbuild
  CRIS: use generic cmpxchg.h
  CRIS: use generic atomic.h
  CRIS: use generic atomic bitops
  CRISv10: remove redundant macros from system.h
  CRIS: remove SMP code
  CRISv32: don't enable irqs in INIT_THREAD
  CRISv32: handle multiple signals
  CRISv32: prevent bogus restarts on sigreturn
  CRISv32: don't attempt syscall restart on irq exit
  Add binding documentation for CRIS
  CRIS: add Axis 88 board device tree
  CRISv32: add device tree support
  CRISv32: add irq domains support
  CRIS: enable GPIOLIB
parents 63905bba d939b52a
Axis Communications AB
ARTPEC series SoC Device Tree Bindings
CRISv32 based SoCs are ETRAX FS and ARTPEC-3:
- compatible = "axis,crisv32";
Boards based on the CRIS SoCs:
Required root node properties:
- compatible = should be one or more of the following:
- "axis,dev88" - for Axis devboard 88 with ETRAX FS
Optional:
* CRISv32 Interrupt Controller
Interrupt controller for the CRISv32 SoCs.
Main node required properties:
- compatible : should be:
"axis,crisv32-intc"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The type shall be a <u32> and the value shall be 1.
- reg: physical base address and size of the intc registers map.
Example:
intc: interrupt-controller {
compatible = "axis,crisv32-intc";
reg = <0xb001c000 0x1000>;
interrupt-controller;
#interrupt-cells = <1>;
};
......@@ -46,12 +46,18 @@ config CRIS
select ARCH_WANT_IPC_PARSE_VERSION
select GENERIC_IRQ_SHOW
select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
select GENERIC_CMOS_UPDATE
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS2
select OLD_SIGSUSPEND
select OLD_SIGACTION
select ARCH_REQUIRE_GPIOLIB
select IRQ_DOMAIN if ETRAX_ARCH_V32
select OF if ETRAX_ARCH_V32
select OF_EARLY_FLATTREE if ETRAX_ARCH_V32
select CLKSRC_MMIO if ETRAX_ARCH_V32
select GENERIC_CLOCKEVENTS if ETRAX_ARCH_V32
select GENERIC_SCHED_CLOCK if ETRAX_ARCH_V32
config HZ
int
......@@ -61,6 +67,10 @@ config NR_CPUS
int
default "1"
config BUILTIN_DTB
string "DTB to build into the kernel image"
depends on OF
source "init/Kconfig"
source "kernel/Kconfig.freezer"
......
......@@ -40,6 +40,10 @@ else
MACH :=
endif
ifneq ($(CONFIG_BUILTIN_DTB),"")
core-$(CONFIG_OF) += arch/cris/boot/dts/
endif
LD = $(CROSS_COMPILE)ld -mcrislinux
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
......
......@@ -9,7 +9,6 @@ obj-y := entry.o traps.o irq.o debugport.o \
process.o ptrace.o setup.o signal.o traps.o time.o \
cache.o cacheflush.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_ETRAX_KGDB) += kgdb.o kgdb_asm.o
obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
obj-$(CONFIG_MODULES) += crisksyms.o
......
......@@ -99,6 +99,8 @@ ret_from_kernel_thread:
.type ret_from_intr,@function
ret_from_intr:
moveq 0, $r9 ; not a syscall
;; Check for resched if preemptive kernel, or if we're going back to
;; user-mode. This test matches the user_regs(regs) macro. Don't simply
;; test CCS since that doesn't necessarily reflect what mode we'll
......@@ -145,7 +147,7 @@ system_call:
;; Stack-frame similar to the irq heads, which is reversed in
;; ret_from_sys_call.
sub.d 92, $sp ; Skip EXS and EDA.
sub.d 92, $sp ; Skip EDA.
movem $r13, [$sp]
move.d $sp, $r8
addq 14*4, $r8
......@@ -156,8 +158,9 @@ system_call:
move $ccs, $r4
move $srp, $r5
move $erp, $r6
move.d $r9, $r7 ; Store syscall number in EXS
subq 4, $sp
movem $r6, [$r8]
movem $r7, [$r8]
ei ; Enable interrupts while processing syscalls.
move.d $r10, [$sp]
......@@ -277,44 +280,15 @@ _syscall_exit_work:
.type _work_pending,@function
_work_pending:
addoq +TI_flags, $r0, $acr
move.d [$acr], $r10
btstq TIF_NEED_RESCHED, $r10 ; Need resched?
bpl _work_notifysig ; No, must be signal/notify.
nop
.size _work_pending, . - _work_pending
.type _work_resched,@function
_work_resched:
move.d $r9, $r1 ; Preserve R9.
jsr schedule
nop
move.d $r1, $r9
di
addoq +TI_flags, $r0, $acr
move.d [$acr], $r1
and.d _TIF_WORK_MASK, $r1 ; Ignore sycall trace counter.
beq _Rexit
nop
btstq TIF_NEED_RESCHED, $r1
bmi _work_resched ; current->work.need_resched.
nop
.size _work_resched, . - _work_resched
.type _work_notifysig,@function
_work_notifysig:
;; Deal with pending signals and notify-resume requests.
addoq +TI_flags, $r0, $acr
move.d [$acr], $r12 ; The thread_info_flags parameter.
move.d $sp, $r11 ; The regs param.
jsr do_notify_resume
move.d $r9, $r10 ; do_notify_resume syscall/irq param.
jsr do_work_pending
move.d $r9, $r10 ; The syscall/irq param.
ba _Rexit
nop
.size _work_notifysig, . - _work_notifysig
.size _work_pending, . - _work_pending
;; We get here as a sidetrack when we've entered a syscall with the
;; trace-bit set. We need to call do_syscall_trace and then continue
......
......@@ -52,11 +52,6 @@ tstart:
GIO_INIT
#ifdef CONFIG_SMP
secondary_cpu_entry: /* Entry point for secondary CPUs */
di
#endif
;; Setup and enable the MMU. Use same configuration for both the data
;; and the instruction MMU.
;;
......@@ -164,33 +159,6 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
nop
nop
#ifdef CONFIG_SMP
;; Read CPU ID
move 0, $srs
nop
nop
nop
move $s12, $r0
cmpq 0, $r0
beq master_cpu
nop
slave_cpu:
; Time to boot-up. Get stack location provided by master CPU.
move.d smp_init_current_idle_thread, $r1
move.d [$r1], $sp
add.d 8192, $sp
move.d ebp_start, $r0 ; Defined in linker-script.
move $r0, $ebp
jsr smp_callin
nop
master_cpu:
/* Set up entry point for secondary CPUs. The boot ROM has set up
* EBP at start of internal memory. The CPU will get there
* later when we issue an IPI to them... */
move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0
move.d secondary_cpu_entry, $r1
move.d $r1, [$r0]
#endif
; Check if starting from DRAM (network->RAM boot or unpacked
; compressed kernel), or directly from flash.
lapcq ., $r0
......
......@@ -10,6 +10,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/profile.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/threads.h>
......@@ -56,9 +58,6 @@ struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] =
static unsigned long irq_regs[NR_CPUS] =
{
regi_irq,
#ifdef CONFIG_SMP
regi_irq2,
#endif
};
#if NR_REAL_IRQS > 32
......@@ -431,6 +430,19 @@ crisv32_do_multiple(struct pt_regs* regs)
irq_exit();
}
static int crisv32_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw_irq_num)
{
irq_set_chip_and_handler(virq, &crisv32_irq_type, handle_simple_irq);
return 0;
}
static struct irq_domain_ops crisv32_irq_ops = {
.map = crisv32_irq_map,
.xlate = irq_domain_xlate_onecell,
};
/*
* This is called by start_kernel. It fixes the IRQ masks and setup the
* interrupt vector table to point to bad_interrupt pointers.
......@@ -441,6 +453,8 @@ init_IRQ(void)
int i;
int j;
reg_intr_vect_rw_mask vect_mask = {0};
struct device_node *np;
struct irq_domain *domain;
/* Clear all interrupts masks. */
for (i = 0; i < NBR_REGS; i++)
......@@ -449,10 +463,15 @@ init_IRQ(void)
for (i = 0; i < 256; i++)
etrax_irv->v[i] = weird_irq;
/* Point all IRQ's to bad handlers. */
np = of_find_compatible_node(NULL, NULL, "axis,crisv32-intc");
domain = irq_domain_add_legacy(np, NR_IRQS - FIRST_IRQ,
FIRST_IRQ, FIRST_IRQ,
&crisv32_irq_ops, NULL);
BUG_ON(!domain);
irq_set_default_host(domain);
of_node_put(np);
for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
irq_set_chip_and_handler(j, &crisv32_irq_type,
handle_simple_irq);
set_exception_vector(i, interrupt[j]);
}
......
......@@ -63,11 +63,6 @@ int show_cpuinfo(struct seq_file *m, void *v)
info = &cpinfo[ARRAY_SIZE(cpinfo) - 1];
#ifdef CONFIG_SMP
if (!cpu_online(cpu))
return 0;
#endif
revision = rdvr();
for (i = 0; i < ARRAY_SIZE(cpinfo); i++) {
......
......@@ -72,6 +72,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
/* Make that the user-mode flag is set. */
regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT));
/* Don't perform syscall restarting */
regs->exs = -1;
/* Restore the old USP. */
err |= __get_user(old_usp, &sc->usp);
wrusp(old_usp);
......@@ -425,6 +428,8 @@ do_signal(int canrestart, struct pt_regs *regs)
{
struct ksignal ksig;
canrestart = canrestart && ((int)regs->exs >= 0);
/*
* The common case should go fast, which is why this point is
* reached from kernel-mode. If that's the case, just return
......
#include <linux/types.h>
#include <asm/delay.h>
#include <irq.h>
#include <hwregs/intr_vect.h>
#include <hwregs/intr_vect_defs.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <hwregs/asm/mmu_defs_asm.h>
#include <hwregs/supp_reg.h>
#include <linux/atomic.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/timex.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/cpumask.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#define IPI_SCHEDULE 1
#define IPI_CALL 2
#define IPI_FLUSH_TLB 4
#define IPI_BOOT 8
#define FLUSH_ALL (void*)0xffffffff
/* Vector of locks used for various atomic operations */
spinlock_t cris_atomic_locks[] = {
[0 ... LOCK_COUNT - 1] = __SPIN_LOCK_UNLOCKED(cris_atomic_locks)
};
/* CPU masks */
cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
EXPORT_SYMBOL(phys_cpu_present_map);
/* Variables used during SMP boot */
volatile int cpu_now_booting = 0;
volatile struct thread_info *smp_init_current_idle_thread;
/* Variables used during IPI */
static DEFINE_SPINLOCK(call_lock);
static DEFINE_SPINLOCK(tlbstate_lock);
struct call_data_struct {
void (*func) (void *info);
void *info;
int wait;
};
static struct call_data_struct * call_data;
static struct mm_struct* flush_mm;
static struct vm_area_struct* flush_vma;
static unsigned long flush_addr;
/* Mode registers */
static unsigned long irq_regs[NR_CPUS] = {
regi_irq,
regi_irq2
};
static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id);
static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
static struct irqaction irq_ipi = {
.handler = crisv32_ipi_interrupt,
.flags = 0,
.name = "ipi",
};
extern void cris_mmu_init(void);
extern void cris_timer_init(void);
/* SMP initialization */
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int i;
/* From now on we can expect IPIs so set them up */
setup_irq(IPI_INTR_VECT, &irq_ipi);
/* Mark all possible CPUs as present */
for (i = 0; i < max_cpus; i++)
cpumask_set_cpu(i, &phys_cpu_present_map);
}
void smp_prepare_boot_cpu(void)
{
/* PGD pointer has moved after per_cpu initialization so
* update the MMU.
*/
pgd_t **pgd;
pgd = (pgd_t**)&per_cpu(current_pgd, smp_processor_id());
SUPP_BANK_SEL(1);
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
SUPP_BANK_SEL(2);
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
set_cpu_online(0, true);
cpumask_set_cpu(0, &phys_cpu_present_map);
set_cpu_possible(0, true);
}
void __init smp_cpus_done(unsigned int max_cpus)
{
}
/* Bring one cpu online.*/
static int __init
smp_boot_one_cpu(int cpuid, struct task_struct idle)
{
unsigned timeout;
cpumask_t cpu_mask;
cpumask_clear(&cpu_mask);
task_thread_info(idle)->cpu = cpuid;
/* Information to the CPU that is about to boot */
smp_init_current_idle_thread = task_thread_info(idle);
cpu_now_booting = cpuid;
/* Kick it */
set_cpu_online(cpuid, true);
cpumask_set_cpu(cpuid, &cpu_mask);
send_ipi(IPI_BOOT, 0, cpu_mask);
set_cpu_online(cpuid, false);
/* Wait for CPU to come online */
for (timeout = 0; timeout < 10000; timeout++) {
if(cpu_online(cpuid)) {
cpu_now_booting = 0;
smp_init_current_idle_thread = NULL;
return 0; /* CPU online */
}
udelay(100);
barrier();
}
printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
return -1;
}
/* Secondary CPUs starts using C here. Here we need to setup CPU
* specific stuff such as the local timer and the MMU. */
void __init smp_callin(void)
{
int cpu = cpu_now_booting;
reg_intr_vect_rw_mask vect_mask = {0};
/* Initialise the idle task for this CPU */
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
/* Set up MMU */
cris_mmu_init();
__flush_tlb_all();
/* Setup local timer. */
cris_timer_init();
/* Enable IRQ and idle */
REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
crisv32_unmask_irq(IPI_INTR_VECT);
crisv32_unmask_irq(TIMER0_INTR_VECT);
preempt_disable();
notify_cpu_starting(cpu);
local_irq_enable();
set_cpu_online(cpu, true);
cpu_startup_entry(CPUHP_ONLINE);
}
/* Stop execution on this CPU.*/
void stop_this_cpu(void* dummy)
{
local_irq_disable();
asm volatile("halt");
}
/* Other calls */
void smp_send_stop(void)
{
smp_call_function(stop_this_cpu, NULL, 0);
}
int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
}
/* cache_decay_ticks is used by the scheduler to decide if a process
* is "hot" on one CPU. A higher value means a higher penalty to move
* a process to another CPU. Our cache is rather small so we report
* 1 tick.
*/
unsigned long cache_decay_ticks = 1;
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
smp_boot_one_cpu(cpu, tidle);
return cpu_online(cpu) ? 0 : -ENOSYS;
}
void smp_send_reschedule(int cpu)
{
cpumask_t cpu_mask;
cpumask_clear(&cpu_mask);
cpumask_set_cpu(cpu, &cpu_mask);
send_ipi(IPI_SCHEDULE, 0, cpu_mask);
}
/* TLB flushing
*
* Flush needs to be done on the local CPU and on any other CPU that
* may have the same mapping. The mm->cpu_vm_mask is used to keep track
* of which CPUs that a specific process has been executed on.
*/
void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, unsigned long addr)
{
unsigned long flags;
cpumask_t cpu_mask;
spin_lock_irqsave(&tlbstate_lock, flags);
cpu_mask = (mm == FLUSH_ALL ? cpu_all_mask : *mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
flush_mm = mm;
flush_vma = vma;
flush_addr = addr;
send_ipi(IPI_FLUSH_TLB, 1, cpu_mask);
spin_unlock_irqrestore(&tlbstate_lock, flags);
}
void flush_tlb_all(void)
{
__flush_tlb_all();
flush_tlb_common(FLUSH_ALL, FLUSH_ALL, 0);
}
void flush_tlb_mm(struct mm_struct *mm)
{
__flush_tlb_mm(mm);
flush_tlb_common(mm, FLUSH_ALL, 0);
/* No more mappings in other CPUs */
cpumask_clear(mm_cpumask(mm));
cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
}
void flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr)
{
__flush_tlb_page(vma, addr);
flush_tlb_common(vma->vm_mm, vma, addr);
}
/* Inter processor interrupts
*
* The IPIs are used for:
* * Force a schedule on a CPU
* * FLush TLB on other CPUs
* * Call a function on other CPUs
*/
int send_ipi(int vector, int wait, cpumask_t cpu_mask)
{
int i = 0;
reg_intr_vect_rw_ipi ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
int ret = 0;
/* Calculate CPUs to send to. */
cpumask_and(&cpu_mask, &cpu_mask, cpu_online_mask);
/* Send the IPI. */
for_each_cpu(i, &cpu_mask)
{
ipi.vector |= vector;
REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
}
/* Wait for IPI to finish on other CPUS */
if (wait) {
for_each_cpu(i, &cpu_mask) {
int j;
for (j = 0 ; j < 1000; j++) {
ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
if (!ipi.vector)
break;
udelay(100);
}
/* Timeout? */
if (ipi.vector) {
printk("SMP call timeout from %d to %d\n", smp_processor_id(), i);
ret = -ETIMEDOUT;
dump_stack();
}
}
}
return ret;
}
/*
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
int smp_call_function(void (*func)(void *info), void *info, int wait)
{
cpumask_t cpu_mask;
struct call_data_struct data;
int ret;
cpumask_setall(&cpu_mask);
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
WARN_ON(irqs_disabled());