diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-26 23:31:05 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-26 23:31:05 +0300 |
commit | 7f9f44308c8993c9ab8078d174dad34bea3e82d7 (patch) | |
tree | cc6f3d146ff813e34ad0ab84673a7b2248a304c7 | |
parent | 63905bba5b0170492777b327ac5e2aaef64989d6 (diff) | |
parent | d939b52abe0cee9cc3167f554da6b864db86d3f2 (diff) | |
download | linux-7f9f44308c8993c9ab8078d174dad34bea3e82d7.tar.xz |
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
50 files changed, 325 insertions, 1145 deletions
diff --git a/Documentation/devicetree/bindings/cris/axis.txt b/Documentation/devicetree/bindings/cris/axis.txt new file mode 100644 index 000000000000..d209ca2a47c0 --- /dev/null +++ b/Documentation/devicetree/bindings/cris/axis.txt @@ -0,0 +1,9 @@ +Axis Communications AB +ARTPEC series SoC Device Tree Bindings + + +CRISv32 based SoCs are ETRAX FS and ARTPEC-3: + + - compatible = "axis,crisv32"; + + diff --git a/Documentation/devicetree/bindings/cris/boards.txt b/Documentation/devicetree/bindings/cris/boards.txt new file mode 100644 index 000000000000..533dd273ccf7 --- /dev/null +++ b/Documentation/devicetree/bindings/cris/boards.txt @@ -0,0 +1,8 @@ +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: + diff --git a/Documentation/devicetree/bindings/cris/interrupts.txt b/Documentation/devicetree/bindings/cris/interrupts.txt new file mode 100644 index 000000000000..e8b123b0a5e6 --- /dev/null +++ b/Documentation/devicetree/bindings/cris/interrupts.txt @@ -0,0 +1,23 @@ +* 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>; + }; + + diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 4a03911053ab..0314e325a669 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -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" diff --git a/arch/cris/Makefile b/arch/cris/Makefile index 39dc7d00083e..4a5404b3d0e4 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -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 diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile index 40358355d0cb..d9fc617ea253 100644 --- a/arch/cris/arch-v32/kernel/Makefile +++ b/arch/cris/arch-v32/kernel/Makefile @@ -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 diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index 2f19ac6217aa..026a0b21b8f0 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -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] @@ -278,43 +281,14 @@ _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 diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S index 51e34165ece7..74a66e0e3777 100644 --- a/arch/cris/arch-v32/kernel/head.S +++ b/arch/cris/arch-v32/kernel/head.S @@ -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 diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index 25437ae28128..6a881e0e92b4 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -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]); } diff --git a/arch/cris/arch-v32/kernel/setup.c b/arch/cris/arch-v32/kernel/setup.c index 81715c683baf..cd1865d68b2e 100644 --- a/arch/cris/arch-v32/kernel/setup.c +++ b/arch/cris/arch-v32/kernel/setup.c @@ -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++) { diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 0c9ce9eac614..3a36ae6b79d5 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -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 diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c deleted file mode 100644 index 0698582467ca..000000000000 --- a/arch/cris/arch-v32/kernel/smp.c +++ /dev/null @@ -1,358 +0,0 @@ -#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()); - - data.func = func; - data.info = info; - data.wait = wait; - - spin_lock(&call_lock); - call_data = &data; - ret = send_ipi(IPI_CALL, wait, cpu_mask); - spin_unlock(&call_lock); - - return ret; -} - -irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id) -{ - void (*func) (void *info) = call_data->func; - void *info = call_data->info; - reg_intr_vect_rw_ipi ipi; - - ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi); - - if (ipi.vector & IPI_SCHEDULE) { - scheduler_ipi(); - } - if (ipi.vector & IPI_CALL) { - func(info); - } - if (ipi.vector & IPI_FLUSH_TLB) { - if (flush_mm == FLUSH_ALL) - __flush_tlb_all(); - else if (flush_vma == FLUSH_ALL) - __flush_tlb_mm(flush_mm); - else - __flush_tlb_page(flush_vma, flush_addr); - } - - ipi.vector = 0; - REG_WR(intr_vect, irq_regs[smp_processor_id()], rw_ipi, ipi); - - return IRQ_HANDLED; -} - diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index c17b01abdc3b..4fce9f1f7cc0 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -8,12 +8,14 @@ #include <linux/timex.h> #include <linux/time.h> #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <linux/interrupt.h> #include <linux/swap.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/threads.h> #include <linux/cpufreq.h> +#include <linux/sched_clock.h> #include <linux/mm.h> #include <asm/types.h> #include <asm/signal.h> @@ -36,33 +38,11 @@ /* Number of 763 counts before watchdog bites */ #define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) -/* Register the continuos readonly timer available in FS and ARTPEC-3. */ -static cycle_t read_cont_rotime(struct clocksource *cs) -{ - return (u32)REG_RD(timer, regi_timer0, r_time); -} - -static struct clocksource cont_rotime = { - .name = "crisv32_rotime", - .rating = 300, - .read = read_cont_rotime, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init etrax_init_cont_rotime(void) -{ - clocksource_register_khz(&cont_rotime, 100000); - return 0; -} -arch_initcall(etrax_init_cont_rotime); +#define CRISV32_TIMER_FREQ (100000000lu) unsigned long timer_regs[NR_CPUS] = { regi_timer0, -#ifdef CONFIG_SMP - regi_timer2 -#endif }; extern int set_rtc_mmss(unsigned long nowtime); @@ -189,81 +169,104 @@ void handle_watchdog_bite(struct pt_regs *regs) #endif } -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick. - */ -extern void cris_do_profile(struct pt_regs *regs); +extern void cris_profile_sample(struct pt_regs *regs); +static void __iomem *timer_base; -static inline irqreturn_t timer_interrupt(int irq, void *dev_id) +static void crisv32_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *dev) { - struct pt_regs *regs = get_irq_regs(); - int cpu = smp_processor_id(); - reg_timer_r_masked_intr masked_intr; - reg_timer_rw_ack_intr ack_intr = { 0 }; - - /* Check if the timer interrupt is for us (a tmr0 int) */ - masked_intr = REG_RD(timer, timer_regs[cpu], r_masked_intr); - if (!masked_intr.tmr0) - return IRQ_NONE; + reg_timer_rw_tmr0_ctrl ctrl = { + .op = regk_timer_hold, + .freq = regk_timer_f100, + }; - /* Acknowledge the timer irq. */ - ack_intr.tmr0 = 1; - REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); + REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); +} - /* Reset watchdog otherwise it resets us! */ - reset_watchdog(); +static int crisv32_clkevt_next_event(unsigned long evt, + struct clock_event_device *dev) +{ + reg_timer_rw_tmr0_ctrl ctrl = { + .op = regk_timer_ld, + .freq = regk_timer_f100, + }; + + REG_WR(timer, timer_base, rw_tmr0_div, evt); + REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); + + ctrl.op = regk_timer_run; + REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); + + return 0; +} + +static irqreturn_t crisv32_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + reg_timer_rw_tmr0_ctrl ctrl = { + .op = regk_timer_hold, + .freq = regk_timer_f100, + }; + reg_timer_rw_ack_intr ack = { .tmr0 = 1 }; + reg_timer_r_masked_intr intr; + + intr = REG_RD(timer, timer_base, r_masked_intr); + if (!intr.tmr0) + return IRQ_NONE; - /* Update statistics. */ - update_process_times(user_mode(regs)); + REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); + REG_WR(timer, timer_base, rw_ack_intr, ack); - cris_do_profile(regs); /* Save profiling information */ + reset_watchdog(); +#ifdef CONFIG_SYSTEM_PROFILER + cris_profile_sample(get_irq_regs()); +#endif - /* The master CPU is responsible for the time keeping. */ - if (cpu != 0) - return IRQ_HANDLED; + evt->event_handler(evt); - /* Call the real timer interrupt handler */ - xtime_update(1); return IRQ_HANDLED; } +static struct clock_event_device crisv32_clockevent = { + .name = "crisv32-timer", + .rating = 300, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = crisv32_clkevt_mode, + .set_next_event = crisv32_clkevt_next_event, +}; + /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ static struct irqaction irq_timer = { - .handler = timer_interrupt, - .flags = IRQF_SHARED, - .name = "timer" + .handler = crisv32_timer_interrupt, + .flags = IRQF_TIMER | IRQF_SHARED, + .name = "crisv32-timer", + .dev_id = &crisv32_clockevent, }; -void __init cris_timer_init(void) +static u64 notrace crisv32_timer_sched_clock(void) { - int cpu = smp_processor_id(); - reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; - reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; - reg_timer_rw_intr_mask timer_intr_mask; + return REG_RD(timer, timer_base, r_time); +} - /* Setup the etrax timers. - * Base frequency is 100MHz, divider 1000000 -> 100 HZ - * We use timer0, so timer1 is free. - * The trig timer is used by the fasttimer API if enabled. - */ +static void __init crisv32_timer_init(void) +{ + reg_timer_rw_intr_mask timer_intr_mask; + reg_timer_rw_tmr0_ctrl ctrl = { + .op = regk_timer_hold, + .freq = regk_timer_f100, + }; - tmr0_ctrl.op = regk_timer_ld; - tmr0_ctrl.freq = regk_timer_f100; - REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); - REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ - tmr0_ctrl.op = regk_timer_run; - REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ + REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - /* Enable the timer irq. */ - timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); + timer_intr_mask = REG_RD(timer, timer_base, rw_intr_mask); timer_intr_mask.tmr0 = 1; - REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); + REG_WR(timer, timer_base, rw_intr_mask, timer_intr_mask); } void __init time_init(void) { - reg_intr_vect_rw_mask intr_mask; + int irq; + int ret; /* Probe for the RTC and read it if it exists. * Before the RTC can be probed the loops_per_usec variable needs @@ -273,17 +276,28 @@ void __init time_init(void) */ loops_per_usec = 50; - /* Start CPU local timer. */ - cris_timer_init(); + irq = TIMER0_INTR_VECT; + timer_base = (void __iomem *) regi_timer0; + + crisv32_timer_init(); + + sched_clock_register(crisv32_timer_sched_clock, 32, + CRISV32_TIMER_FREQ); + + clocksource_mmio_init(timer_base + REG_RD_ADDR_timer_r_time, + "crisv32-timer", CRISV32_TIMER_FREQ, + 300, 32, clocksource_mmio_readl_up); + + crisv32_clockevent.cpumask = cpu_possible_mask; + crisv32_clockevent.irq = irq; - /* Enable the timer irq in global config. */ - intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1); - intr_mask.timer0 = 1; - REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask); + ret = setup_irq(irq, &irq_timer); + if (ret) + pr_warn("failed to setup irq %d\n", irq); - /* Now actually register the timer irq handler that calls - * timer_interrupt(). */ - setup_irq(TIMER0_INTR_VECT, &irq_timer); + clockevents_config_and_register(&crisv32_clockevent, + CRISV32_TIMER_FREQ, + 2, 0xffffffff); /* Enable watchdog if we should use one. */ diff --git a/arch/cris/arch-v32/lib/Makefile b/arch/cris/arch-v32/lib/Makefile index dd296b9db034..e91cf02f625d 100644 --- a/arch/cris/arch-v32/lib/Makefile +++ b/arch/cris/arch-v32/lib/Makefile @@ -3,5 +3,5 @@ # lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o \ - csumcpfruser.o spinlock.o delay.o strcmp.o + csumcpfruser.o delay.o strcmp.o diff --git a/arch/cris/arch-v32/lib/spinlock.S b/arch/cris/arch-v32/lib/spinlock.S deleted file mode 100644 index fe610b9d775f..000000000000 --- a/arch/cris/arch-v32/lib/spinlock.S +++ /dev/null @@ -1,40 +0,0 @@ -;; Core of the spinlock implementation -;; -;; Copyright (C) 2004 Axis Communications AB. -;; -;; Author: Mikael Starvik - - - .global cris_spin_lock - .type cris_spin_lock,@function - .global cris_spin_trylock - .type cris_spin_trylock,@function - - .text - -cris_spin_lock: - clearf p -1: test.b [$r10] - beq 1b - clearf p - ax - clear.b [$r10] - bcs 1b - clearf p - ret - nop - - .size cris_spin_lock, . - cris_spin_lock - -cris_spin_trylock: - clearf p -1: move.b [$r10], $r11 - ax - clear.b [$r10] - bcs 1b - clearf p - ret - movu.b $r11,$r10 - - .size cris_spin_trylock, . - cris_spin_trylock - diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c index 3deca5253d91..f5438ca8122d 100644 --- a/arch/cris/arch-v32/mm/init.c +++ b/arch/cris/arch-v32/mm/init.c @@ -40,17 +40,6 @@ void __init cris_mmu_init(void) */ per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd; -#ifdef CONFIG_SMP - { - 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); - } -#endif - /* Initialise the TLB. Function found in tlb.c. */ tlb_init(); diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S index 72727c1d8e60..c0981044eccb 100644 --- a/arch/cris/arch-v32/mm/mmu.S +++ b/arch/cris/arch-v32/mm/mmu.S @@ -115,11 +115,7 @@ move.d $r0, [$r1] ; last_refill_cause = rw_mm_cause 3: ; Probably not in a loop, continue normal processing -#ifdef CONFIG_SMP - move $s7, $acr ; PGD -#else move.d current_pgd, $acr ; PGD -#endif ; Look up PMD in PGD lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) move.d [$acr], $acr ; PGD for the current process diff --git a/arch/cris/boot/dts/Makefile b/arch/cris/boot/dts/Makefile new file mode 100644 index 000000000000..faf69fb9919f --- /dev/null +++ b/arch/cris/boot/dts/Makefile @@ -0,0 +1,6 @@ +BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o +ifneq ($(CONFIG_BUILTIN_DTB),"") +obj-$(CONFIG_OF) += $(BUILTIN_DTB) +endif + +clean-files := *.dtb.S diff --git a/arch/cris/boot/dts/dev88.dts b/arch/cris/boot/dts/dev88.dts new file mode 100644 index 000000000000..4fa5a3f9d0ec --- /dev/null +++ b/arch/cris/boot/dts/dev88.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/include/ "etraxfs.dtsi" + +/ { + model = "Axis 88 Developer Board"; + compatible = "axis,dev88"; + + aliases { + serial0 = &uart0; + }; + + soc { + uart0: serial@b00260000 { + status = "okay"; + }; + }; +}; diff --git a/arch/cris/boot/dts/etraxfs.dtsi b/arch/cris/boot/dts/etraxfs.dtsi new file mode 100644 index 000000000000..909bcedc3565 --- /dev/null +++ b/arch/cris/boot/dts/etraxfs.dtsi @@ -0,0 +1,38 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "axis,crisv32"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "etraxfs"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + intc: interrupt-controller { + compatible = "axis,crisv32-intc"; + reg = <0xb001c000 0x1000>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + serial@b00260000 { + compatible = "axis,etraxfs-uart"; + reg = <0xb0026000 0x1000>; + interrupts = <68>; + status = "disabled"; + }; + }; +}; diff --git a/arch/cris/include/arch-v10/arch/atomic.h b/arch/cris/include/arch-v10/arch/atomic.h deleted file mode 100644 index 6ef5e7d09024..000000000000 --- a/arch/cris/include/arch-v10/arch/atomic.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_CRIS_ARCH_ATOMIC__ -#define __ASM_CRIS_ARCH_ATOMIC__ - -#define cris_atomic_save(addr, flags) local_irq_save(flags); -#define cris_atomic_restore(addr, flags) local_irq_restore(flags); - -#endif diff --git a/arch/cris/include/arch-v10/arch/system.h b/arch/cris/include/arch-v10/arch/system.h index 935fde34aa15..9b5580f58b96 100644 --- a/arch/cris/include/arch-v10/arch/system.h +++ b/arch/cris/include/arch-v10/arch/system.h @@ -36,12 +36,4 @@ static inline unsigned long _get_base(char * addr) return 0; } -#define nop() __asm__ __volatile__ ("nop"); - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -#define tas(ptr) (xchg((ptr),1)) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) - #endif diff --git a/arch/cris/include/arch-v32/arch/atomic.h b/arch/cris/include/arch-v32/arch/atomic.h deleted file mode 100644 index 852ceff8013f..000000000000 --- a/arch/cris/include/arch-v32/arch/atomic.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __ASM_CRIS_ARCH_ATOMIC__ -#define __ASM_CRIS_ARCH_ATOMIC__ - -#include <linux/spinlock_types.h> - -extern void cris_spin_unlock(void *l, int val); -extern void cris_spin_lock(void *l); -extern int cris_spin_trylock(void* l); - -#ifndef CONFIG_SMP -#define cris_atomic_save(addr, flags) local_irq_save(flags); -#define cris_atomic_restore(addr, flags) local_irq_restore(flags); -#else - -extern spinlock_t cris_atomic_locks[]; -#define LOCK_COUNT 128 -#define HASH_ADDR(a) (((int)a) & 127) - -#define cris_atomic_save(addr, flags) \ - local_irq_save(flags); \ - cris_spin_lock((void *)&cris_atomic_locks[HASH_ADDR(addr)].raw_lock.slock); - -#define cris_atomic_restore(addr, flags) \ - { \ - spinlock_t *lock = (void*)&cris_atomic_locks[HASH_ADDR(addr)]; \ - __asm__ volatile ("move.d %1,%0" \ - : "=m" (lock->raw_lock.slock) \ - : "r" (1) \ - : "memory"); \ - local_irq_restore(flags); \ - } - -#endif - -#endif - diff --git a/arch/cris/include/arch-v32/arch/processor.h b/arch/cris/include/arch-v32/arch/processor.h index a024b7d32fed..568759271ab5 100644 --- a/arch/cris/include/arch-v32/arch/processor.h +++ b/arch/cris/include/arch-v32/arch/processor.h @@ -25,8 +25,7 @@ struct thread_struct { */ #define TASK_SIZE (0xB0000000UL) -/* CCS I=1, enable interrupts. */ -#define INIT_THREAD { 0, 0, (1 << I_CCS_BITNR) } +#define INIT_THREAD { } #define KSTK_EIP(tsk) \ ({ \ diff --git a/arch/cris/include/arch-v32/arch/spinlock.h b/arch/cris/include/arch-v32/arch/spinlock.h deleted file mode 100644 index f13275522f4d..000000000000 --- a/arch/cris/include/arch-v32/arch/spinlock.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef __ASM_ARCH_SPINLOCK_H -#define __ASM_ARCH_SPINLOCK_H - -#include <linux/spinlock_types.h> - -#define RW_LOCK_BIAS 0x01000000 - -extern void cris_spin_unlock(void *l, int val); -extern void cris_spin_lock(void *l); -extern int cris_spin_trylock(void *l); - -static inline int arch_spin_is_locked(arch_spinlock_t *x) -{ - return *(volatile signed char *)(&(x)->slock) <= 0; -} - -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - __asm__ volatile ("move.d %1,%0" \ - : "=m" (lock->slock) \ - : "r" (1) \ - : "memory"); -} - -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ - while (arch_spin_is_locked(lock)) - cpu_relax(); -} - -static inline int arch_spin_trylock(arch_spinlock_t *lock) -{ - return cris_spin_trylock((void *)&lock->slock); -} - -static inline void arch_spin_lock(arch_spinlock_t *lock) -{ - cris_spin_lock((void *)&lock->slock); -} - -static inline void -arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags) -{ - arch_spin_lock(lock); -} - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - * - */ - -static inline int arch_read_can_lock(arch_rwlock_t *x) -{ - return (int)(x)->lock > 0; -} - -static inline int arch_write_can_lock(arch_rwlock_t *x) -{ - return (x)->lock == RW_LOCK_BIAS; -} - -static inline void arch_read_lock(arch_rwlock_t *rw) -{ - arch_spin_lock(&rw->slock); - while (rw->lock == 0); - rw->lock--; - arch_spin_unlock(&rw->slock); -} - -static inline void arch_write_lock(arch_rwlock_t *rw) -{ - arch_spin_lock(&rw->slock); - while (rw->lock != RW_LOCK_BIAS); - rw->lock = 0; - arch_spin_unlock(&rw->slock); -} - -static inline void arch_read_unlock(arch_rwlock_t *rw) -{ - arch_spin_lock(&rw->slock); - rw->lock++; - arch_spin_unlock(&rw->slock); -} - -static inline void arch_write_unlock(arch_rwlock_t *rw) -{ - arch_spin_lock(&rw->slock); - while (rw->lock != RW_LOCK_BIAS); - rw->lock = RW_LOCK_BIAS; - arch_spin_unlock(&rw->slock); -} - -static inline int arch_read_trylock(arch_rwlock_t *rw) -{ - int ret = 0; - arch_spin_lock(&rw->slock); - if (rw->lock != 0) { - rw->lock--; - ret = 1; - } - arch_spin_unlock(&rw->slock); - return ret; -} - -static inline int arch_write_trylock(arch_rwlock_t *rw) -{ - int ret = 0; - arch_spin_lock(&rw->slock); - if (rw->lock == RW_LOCK_BIAS) { - rw->lock = 0; - ret = 1; - } - arch_spin_unlock(&rw->slock); - return ret; -} - -#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock) -#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock) - -#define arch_spin_relax(lock) cpu_relax() -#define arch_read_relax(lock) cpu_relax() -#define arch_write_relax(lock) cpu_relax() - -#endif /* __ASM_ARCH_SPINLOCK_H */ diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 889f2de050a3..057e51859b0a 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -1,16 +1,29 @@ - +generic-y += atomic.h generic-y += barrier.h generic-y += clkdev.h +generic-y += cmpxchg.h generic-y += cputime.h +generic-y += device.h +generic-y += div64.h generic-y += exec.h +generic-y += emergency-restart.h +generic-y += futex.h +generic-y += hardirq.h +generic-y += irq_regs.h generic-y += irq_work.h +generic-y += kdebug.h +generic-y += kmap_types.h generic-y += kvm_para.h generic-y += linkage.h +generic-y += local.h +generic-y += local64.h generic-y += mcs_spinlock.h generic-y += module.h +generic-y += percpu.h generic-y += preempt.h generic-y += scatterlist.h generic-y += sections.h +generic-y += topology.h generic-y += trace_clock.h generic-y += vga.h generic-y += xor.h diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h deleted file mode 100644 index 279766a70664..000000000000 --- a/arch/cris/include/asm/atomic.h +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */ - -#ifndef __ASM_CRIS_ATOMIC__ -#define __ASM_CRIS_ATOMIC__ - -#include <linux/compiler.h> -#include <linux/types.h> -#include <asm/cmpxchg.h> -#include <arch/atomic.h> -#include <arch/system.h> -#include <asm/barrier.h> - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - */ - -#define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) - -/* These should be written in asm but we do it in C for now. */ - -#define ATOMIC_OP(op, c_op) \ -static inline void atomic_##op(int i, volatile atomic_t *v) \ -{ \ - unsigned long flags; \ - cris_atomic_save(v, flags); \ - v->counter c_op i; \ - cris_atomic_restore(v, flags); \ -} \ - -#define ATOMIC_OP_RETURN(op, c_op) \ -static inline int atomic_##op##_return(int i, volatile atomic_t *v) \ -{ \ - unsigned long flags; \ - int retval; \ - cris_atomic_save(v, flags); \ - retval = (v->counter c_op i); \ - cris_atomic_restore(v, flags); \ - return retval; \ -} - -#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) - -ATOMIC_OPS(add, +=) -ATOMIC_OPS(sub, -=) - -#undef ATOMIC_OPS -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP - -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) - -static inline int atomic_sub_and_test(int i, volatile atomic_t *v) -{ - int retval; - unsigned long flags; - cris_atomic_save(v, flags); - retval = (v->counter -= i) == 0; - cris_atomic_restore(v, flags); - return retval; -} - -static inline void atomic_inc(volatile atomic_t *v) -{ - unsigned long flags; - cris_atomic_save(v, flags); - (v->counter)++; - cris_atomic_restore(v, flags); -} - -static inline void atomic_dec(volatile atomic_t *v) -{ - unsigned long flags; - cris_atomic_save(v, flags); - (v->counter)--; - cris_atomic_restore(v, flags); -} - -static inline int atomic_inc_return(volatile atomic_t *v) -{ - unsigned long flags; - int retval; - cris_atomic_save(v, flags); - retval = ++(v->counter); - cris_atomic_restore(v, flags); - return retval; -} - -static inline int atomic_dec_return(volatile atomic_t *v) -{ - unsigned long flags; - int retval; - cris_atomic_save(v, flags); - retval = --(v->counter); - cris_atomic_restore(v, flags); - return retval; -} -static inline int atomic_dec_and_test(volatile atomic_t *v) -{ - int retval; - unsigned long flags; - cris_atomic_save(v, flags); - retval = --(v->counter) == 0; - cris_atomic_restore(v, flags); - return retval; -} - -static inline int atomic_inc_and_test(volatile atomic_t *v) -{ - int retval; - unsigned long flags; - cris_atomic_save(v, flags); - retval = ++(v->counter) == 0; - cris_atomic_restore(v, flags); - return retval; -} - -static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - int ret; - unsigned long flags; - - cris_atomic_save(v, flags); - ret = v->counter; - if (likely(ret == old)) - v->counter = new; - cris_atomic_restore(v, flags); - return ret; -} - -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -static inline int __atomic_add_unless(atomic_t *v, int a, int u) -{ - int ret; - unsigned long flags; - - cris_atomic_save(v, flags); - ret = v->counter; - if (ret != u) - v->counter += a; - cris_atomic_restore(v, flags); - return ret; -} - -#endif diff --git a/arch/cris/include/asm/bitops.h b/arch/cris/include/asm/bitops.h index bd49a546f4f5..8062cb52d343 100644 --- a/arch/cris/include/asm/bitops.h +++ b/arch/cris/include/asm/bitops.h @@ -19,119 +19,10 @@ #endif #include <arch/bitops.h> -#include <linux/atomic.h> #include <linux/compiler.h> #include <asm/barrier.h> -/* - * set_bit - Atomically set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * This function is atomic and may not be reordered. See __set_bit() - * if you do not require the atomic guarantees. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ - -#define set_bit(nr, addr) (void)test_and_set_bit(nr, addr) - -/* - * clear_bit - Clears a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * clear_bit() is atomic and may not be reordered. However, it does - * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() - * in order to ensure changes are visible on other processors. - */ - -#define clear_bit(nr, addr) (void)test_and_clear_bit(nr, addr) - -/* - * change_bit - Toggle a bit in memory - * @nr: Bit to change - * @addr: Address to start counting from - * - * change_bit() is atomic and may not be reordered. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ - -#define change_bit(nr, addr) (void)test_and_change_bit(nr, addr) - -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ - -static inline int test_and_set_bit(int nr, volatile unsigned long *addr) -{ - unsigned int mask, retval; - unsigned long flags; - unsigned int *adr = (unsigned int *)addr; - - adr += nr >> 5; - mask = 1 << (nr & 0x1f); - cris_atomic_save(addr, flags); - retval = (mask & *adr) != 0; - *adr |= mask; - cris_atomic_restore(addr, flags); - return retval; -} - -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ - -static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned int mask, retval; - unsigned long flags; - unsigned int *adr = (unsigned int *)addr; - - adr += nr >> 5; - mask = 1 << (nr & 0x1f); - cris_atomic_save(addr, flags); - retval = (mask & *adr) != 0; - *adr &= ~mask; - cris_atomic_restore(addr, flags); - return retval; -} - -/** - * test_and_change_bit - Change a bit and return its old value - * @nr: Bit to change - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ - -static inline int test_and_change_bit(int nr, volatile unsigned long *addr) -{ - unsigned int mask, retval; - unsigned long flags; - unsigned int *adr = (unsigned int *)addr; - adr += nr >> 5; - mask = 1 << (nr & 0x1f); - cris_atomic_save(addr, flags); - retval = (mask & *adr) != 0; - *adr ^= mask; - cris_atomic_restore(addr, flags); - return retval; -} - +#include <asm-generic/bitops/atomic.h> #include <asm-generic/bitops/non-atomic.h> /* diff --git a/arch/cris/include/asm/cmpxchg.h b/arch/cris/include/asm/cmpxchg.h deleted file mode 100644 index b756dac8aa3f..000000000000 --- a/arch/cris/include/asm/cmpxchg.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __ASM_CRIS_CMPXCHG__ -#define __ASM_CRIS_CMPXCHG__ - -#include <linux/irqflags.h> - -static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) -{ - /* since Etrax doesn't have any atomic xchg instructions, we need to disable - irq's (if enabled) and do it with move.d's */ - unsigned long flags,temp; - local_irq_save(flags); /* save flags, including irq enable bit and shut off irqs */ - switch (size) { - case 1: - *((unsigned char *)&temp) = x; - x = *(unsigned char *)ptr; - *(unsigned char *)ptr = *((unsigned char *)&temp); - break; - case 2: - *((unsigned short *)&temp) = x; - x = *(unsigned short *)ptr; - *(unsigned short *)ptr = *((unsigned short *)&temp); - break; - case 4: - temp = x; - x = *(unsigned long *)ptr; - *(unsigned long *)ptr = temp; - break; - } - local_irq_restore(flags); /* restore irq enable bit */ - return x; -} - -#define xchg(ptr,x) \ - ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) - -#define tas(ptr) (xchg((ptr),1)) - -#include <asm-generic/cmpxchg-local.h> - -/* - * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make - * them available. - */ -#define cmpxchg_local(ptr, o, n) \ - ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ - (unsigned long)(n), sizeof(*(ptr)))) -#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) - -#ifndef CONFIG_SMP -#include <asm-generic/cmpxchg.h> -#endif - -#endif /* __ASM_CRIS_CMPXCHG__ */ diff --git a/arch/cris/include/asm/device.h b/arch/cris/include/asm/device.h deleted file mode 100644 index d8f9872b0e2d..000000000000 --- a/arch/cris/include/asm/device.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Arch specific extensions to struct device - * - * This file is released under the GPLv2 - */ -#include <asm-generic/device.h> - diff --git a/arch/cris/include/asm/div64.h b/arch/cris/include/asm/div64.h deleted file mode 100644 index 6cd978cefb28..000000000000 --- a/arch/cris/include/asm/div64.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/div64.h> diff --git a/arch/cris/include/asm/elf.h b/arch/cris/include/asm/elf.h index 30ded8fbf592..c2a394ff55ff 100644 --- a/arch/cris/include/asm/elf.h +++ b/arch/cris/include/asm/elf.h @@ -71,7 +71,7 @@ typedef unsigned long elf_fpregset_t; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff --git a/arch/cris/include/asm/emergency-restart.h b/arch/cris/include/asm/emergency-restart.h deleted file mode 100644 index 108d8c48e42e..000000000000 --- a/arch/cris/include/asm/emergency-restart.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_EMERGENCY_RESTART_H -#define _ASM_EMERGENCY_RESTART_H - -#include <asm-generic/emergency-restart.h> - -#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/arch/cris/include/asm/futex.h b/arch/cris/include/asm/futex.h deleted file mode 100644 index 6a332a9f099c..000000000000 --- a/arch/cris/include/asm/futex.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_FUTEX_H -#define _ASM_FUTEX_H - -#include <asm-generic/futex.h> - -#endif diff --git a/arch/cris/include/asm/hardirq.h b/arch/cris/include/asm/hardirq.h deleted file mode 100644 index 04126f7bfab2..000000000000 --- a/arch/cris/include/asm/hardirq.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_HARDIRQ_H -#define __ASM_HARDIRQ_H - -#include <asm/irq.h> -#include <asm-generic/hardirq.h> - -#endif /* __ASM_HARDIRQ_H */ diff --git a/arch/cris/include/asm/irq_regs.h b/arch/cris/include/asm/irq_regs.h deleted file mode 100644 index 3dd9c0b70270..000000000000 --- a/arch/cris/include/asm/irq_regs.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/irq_regs.h> diff --git a/arch/cris/include/asm/kdebug.h b/arch/cris/include/asm/kdebug.h deleted file mode 100644 index 6ece1b037665..000000000000 --- a/arch/cris/include/asm/kdebug.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/kdebug.h> diff --git a/arch/cris/include/asm/kmap_types.h b/arch/cris/include/asm/kmap_types.h deleted file mode 100644 index d2d643c4ea59..000000000000 --- a/arch/cris/include/asm/kmap_types.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASM_KMAP_TYPES_H -#define _ASM_KMAP_TYPES_H - -/* Dummy header just to define km_type. None of this - * is actually used on cris. - */ - -#include <asm-generic/kmap_types.h> - -#endif diff --git a/arch/cris/include/asm/local.h b/arch/cris/include/asm/local.h deleted file mode 100644 index c11c530f74d0..000000000000 --- a/arch/cris/include/asm/local.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/local.h> diff --git a/arch/cris/include/asm/local64.h b/arch/cris/include/asm/local64.h deleted file mode 100644 index 36c93b5cc239..000000000000 --- a/arch/cris/include/asm/local64.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/local64.h> diff --git a/arch/cris/include/asm/percpu.h b/arch/cris/include/asm/percpu.h deleted file mode 100644 index 6db9b43cf80a..000000000000 --- a/arch/cris/include/asm/percpu.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_PERCPU_H -#define _CRIS_PERCPU_H - -#include <asm-generic/percpu.h> - -#endif /* _CRIS_PERCPU_H */ diff --git a/arch/cris/include/asm/smp.h b/arch/cris/include/asm/smp.h deleted file mode 100644 index c615a06dd757..000000000000 --- a/arch/cris/include/asm/smp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_SMP_H -#define __ASM_SMP_H - -#include <linux/cpumask.h> - -extern cpumask_t phys_cpu_present_map; - -#define raw_smp_processor_id() (current_thread_info()->cpu) - -#endif diff --git a/arch/cris/include/asm/spinlock.h b/arch/cris/include/asm/spinlock.h deleted file mode 100644 index ed816b57face..000000000000 --- a/arch/cris/include/asm/spinlock.h +++ /dev/null @@ -1 +0,0 @@ -#include <arch/spinlock.h> diff --git a/arch/cris/include/asm/tlbflush.h b/arch/cris/include/asm/tlbflush.h index 20697e7ef4f2..b424f43a9fd6 100644 --- a/arch/cris/include/asm/tlbflush.h +++ b/arch/cris/include/asm/tlbflush.h @@ -22,16 +22,9 @@ extern void __flush_tlb_mm(struct mm_struct *mm); extern void __flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); -#ifdef CONFIG_SMP -extern void flush_tlb_all(void); -extern void flush_tlb_mm(struct mm_struct *mm); -extern void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr); -#else #define flush_tlb_all __flush_tlb_all #define flush_tlb_mm __flush_tlb_mm #define flush_tlb_page __flush_tlb_page -#endif static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end) { diff --git a/arch/cris/include/asm/topology.h b/arch/cris/include/asm/topology.h deleted file mode 100644 index 2ac613d32a89..000000000000 --- a/arch/cris/include/asm/topology.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_CRIS_TOPOLOGY_H -#define _ASM_CRIS_TOPOLOGY_H - -#include <asm-generic/topology.h> - -#endif /* _ASM_CRIS_TOPOLOGY_H */ diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile index b45640b3e600..edef71f12bb8 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -7,6 +7,7 @@ CPPFLAGS_vmlinux.lds := -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) extra-y := vmlinux.lds obj-y := process.o traps.o irq.o ptrace.o setup.o time.o sys_cris.o +obj-y += devicetree.o obj-$(CONFIG_MODULES) += crisksyms.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/cris/kernel/devicetree.c b/arch/cris/kernel/devicetree.c new file mode 100644 index 000000000000..53ff8d73e7e1 --- /dev/null +++ b/arch/cris/kernel/devicetree.c @@ -0,0 +1,14 @@ +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/printk.h> + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + pr_err("%s(%llx, %llx)\n", + __func__, base, size); +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return alloc_bootmem_align(size, align); +} diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index 58d44ee1a71f..fd3427e563c5 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -42,3 +42,26 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, tracehook_notify_resume(regs); } } + +void do_work_pending(int syscall, struct pt_regs *regs, + unsigned int thread_flags) +{ + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + do_signal(syscall, regs); + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); +} diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 905b70ea9939..bb12aa93201d 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -19,6 +19,9 @@ #include <linux/utsname.h> #include <linux/pfn.h> #include <linux/cpu.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> #include <asm/setup.h> #include <arch/system.h> @@ -64,6 +67,10 @@ void __init setup_arch(char **cmdline_p) unsigned long start_pfn, max_pfn; unsigned long memory_start; +#ifdef CONFIG_OF + early_init_dt_scan(__dtb_start); +#endif + /* register an initial console printing routine for printk's */ init_etrax_debug(); @@ -141,6 +148,8 @@ void __init setup_arch(char **cmdline_p) reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size, BOOTMEM_DEFAULT); + unflatten_and_copy_device_tree(); + /* paging_init() sets up the MMU and marks all pages as reserved */ paging_init(); @@ -204,3 +213,9 @@ static int __init topology_init(void) subsys_initcall(topology_init); +static int __init cris_of_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; +} +core_initcall(cris_of_init); diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index fe6acdabbc8d..7780d379522f 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -79,11 +79,13 @@ cris_do_profile(struct pt_regs* regs) #endif } +#ifndef CONFIG_GENERIC_SCHED_CLOCK unsigned long long sched_clock(void) { return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ) + get_ns_in_jiffie(); } +#endif static int __init init_udelay(void) |