summaryrefslogtreecommitdiff
path: root/arch/arc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r--arch/arc/kernel/Makefile2
-rw-r--r--arch/arc/kernel/entry-arcv2.S24
-rw-r--r--arch/arc/kernel/entry-compact.S2
-rw-r--r--arch/arc/kernel/head.S14
-rw-r--r--arch/arc/kernel/intc-arcv2.c16
-rw-r--r--arch/arc/kernel/intc-compact.c4
-rw-r--r--arch/arc/kernel/mcip.c61
-rw-r--r--arch/arc/kernel/module.c4
-rw-r--r--arch/arc/kernel/setup.c17
-rw-r--r--arch/arc/kernel/smp.c25
-rw-r--r--arch/arc/kernel/time.c382
-rw-r--r--arch/arc/kernel/unaligned.c3
12 files changed, 103 insertions, 451 deletions
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index cfcdedf52ff8..8942c5c3b4c5 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -8,7 +8,7 @@
# Pass UTS_MACHINE for user_regset definition
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
-obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
+obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o
obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o
obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o
diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S
index 7a1c124ff021..0b6388a5f0b8 100644
--- a/arch/arc/kernel/entry-arcv2.S
+++ b/arch/arc/kernel/entry-arcv2.S
@@ -67,12 +67,23 @@ ENTRY(handle_interrupt)
INTERRUPT_PROLOGUE irq
- clri ; To make status32.IE agree with CPU internal state
-
-#ifdef CONFIG_TRACE_IRQFLAGS
- TRACE_ASM_IRQ_DISABLE
-#endif
-
+ # irq control APIs local_irq_save/restore/disable/enable fiddle with
+ # global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio)
+ # However a taken interrupt doesn't clear these bits. Thus irqs_disabled()
+ # query in hard ISR path would return false (since .IE is set) which would
+ # trips genirq interrupt handling asserts.
+ #
+ # So do a "soft" disable of interrutps here.
+ #
+ # Note this disable is only for consistent book-keeping as further interrupts
+ # will be disabled anyways even w/o this. Hardware tracks active interrupts
+ # seperately in AUX_IRQ_ACTIVE.active and will not take new interrupts
+ # unless this one returns (or higher prio becomes pending in 2-prio scheme)
+
+ IRQ_DISABLE
+
+ ; icause is banked: one per priority level
+ ; so a higher prio interrupt taken here won't clobber prev prio icause
lr r0, [ICAUSE]
mov blink, ret_from_exception
@@ -171,6 +182,7 @@ END(EV_TLBProtV)
; All 2 entry points to here already disable interrupts
.Lrestore_regs:
+restore_regs:
# Interrpts are actually disabled from this point on, but will get
# reenabled after we return from interrupt/exception.
diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S
index 98812c1248df..9211707634dc 100644
--- a/arch/arc/kernel/entry-compact.S
+++ b/arch/arc/kernel/entry-compact.S
@@ -259,7 +259,7 @@ ENTRY(EV_TLBProtV)
EXCEPTION_PROLOGUE
- lr r2, [ecr]
+ mov r2, r9 ; ECR set into r9 already
lr r0, [efa] ; Faulting Data address (not part of pt_regs saved above)
; Exception auto-disables further Intr/exceptions.
diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S
index 689dd867fdff..8b90d25a15cc 100644
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -71,14 +71,14 @@ ENTRY(stext)
GET_CPU_ID r5
cmp r5, 0
mov.nz r0, r5
-#ifdef CONFIG_ARC_SMP_HALT_ON_RESET
- ; Non-Master can proceed as system would be booted sufficiently
- jnz first_lines_of_secondary
-#else
+ bz .Lmaster_proceed
+
; Non-Masters wait for Master to boot enough and bring them up
- jnz arc_platform_smp_wait_to_boot
-#endif
- ; Master falls thru
+ ; when they resume, tail-call to entry point
+ mov blink, @first_lines_of_secondary
+ j arc_platform_smp_wait_to_boot
+
+.Lmaster_proceed:
#endif
; Clear BSS before updating any globals
diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c
index 62b59409a5d9..ecef0fb0b66c 100644
--- a/arch/arc/kernel/intc-arcv2.c
+++ b/arch/arc/kernel/intc-arcv2.c
@@ -14,8 +14,6 @@
#include <linux/irqchip.h>
#include <asm/irq.h>
-static int irq_prio;
-
/*
* Early Hardware specific Interrupt setup
* -Called very early (start_kernel -> setup_arch -> setup_processor)
@@ -24,7 +22,7 @@ static int irq_prio;
*/
void arc_init_IRQ(void)
{
- unsigned int tmp;
+ unsigned int tmp, irq_prio;
struct irq_build {
#ifdef CONFIG_CPU_BIG_ENDIAN
@@ -67,33 +65,33 @@ void arc_init_IRQ(void)
irq_prio = irq_bcr.prio; /* Encoded as N-1 for N levels */
pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
- irq_prio + 1, irq_prio,
+ irq_prio + 1, ARCV2_IRQ_DEF_PRIO,
irq_bcr.firq ? " FIRQ (not used)":"");
/* setup status32, don't enable intr yet as kernel doesn't want */
tmp = read_aux_reg(0xa);
- tmp |= STATUS_AD_MASK | (irq_prio << 1);
+ tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1);
tmp &= ~STATUS_IE_MASK;
asm volatile("kflag %0 \n"::"r"(tmp));
}
static void arcv2_irq_mask(struct irq_data *data)
{
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
write_aux_reg(AUX_IRQ_ENABLE, 0);
}
static void arcv2_irq_unmask(struct irq_data *data)
{
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
write_aux_reg(AUX_IRQ_ENABLE, 1);
}
void arcv2_irq_enable(struct irq_data *data)
{
/* set default priority */
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
- write_aux_reg(AUX_IRQ_PRIORITY, irq_prio);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
+ write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
/*
* hw auto enables (linux unmask) all by default
diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c
index ce9deb953ca9..8c1fd5c00782 100644
--- a/arch/arc/kernel/intc-compact.c
+++ b/arch/arc/kernel/intc-compact.c
@@ -57,7 +57,7 @@ static void arc_irq_mask(struct irq_data *data)
unsigned int ienb;
ienb = read_aux_reg(AUX_IENABLE);
- ienb &= ~(1 << data->irq);
+ ienb &= ~(1 << data->hwirq);
write_aux_reg(AUX_IENABLE, ienb);
}
@@ -66,7 +66,7 @@ static void arc_irq_unmask(struct irq_data *data)
unsigned int ienb;
ienb = read_aux_reg(AUX_IENABLE);
- ienb |= (1 << data->irq);
+ ienb |= (1 << data->hwirq);
write_aux_reg(AUX_IENABLE, ienb);
}
diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c
index f39142acc89e..9f6b68fd4f3b 100644
--- a/arch/arc/kernel/mcip.c
+++ b/arch/arc/kernel/mcip.c
@@ -10,9 +10,10 @@
#include <linux/smp.h>
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
+#include <soc/arc/mcip.h>
#include <asm/irqflags-arcv2.h>
-#include <asm/mcip.h>
#include <asm/setup.h>
static DEFINE_RAW_SPINLOCK(mcip_lock);
@@ -92,11 +93,10 @@ static void mcip_probe_n_setup(void)
READ_BCR(ARC_REG_MCIP_BCR, mp);
sprintf(smp_cpuinfo_buf,
- "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s%s\n",
+ "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
mp.ver, mp.num_cores,
IS_AVAIL1(mp.ipi, "IPI "),
IS_AVAIL1(mp.idu, "IDU "),
- IS_AVAIL1(mp.llm, "LLM "),
IS_AVAIL1(mp.dbg, "DEBUG "),
IS_AVAIL1(mp.gfrc, "GFRC"));
@@ -174,7 +174,6 @@ static void idu_irq_unmask(struct irq_data *data)
raw_spin_unlock_irqrestore(&mcip_lock, flags);
}
-#ifdef CONFIG_SMP
static int
idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
bool force)
@@ -204,12 +203,27 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
return IRQ_SET_MASK_OK;
}
-#endif
+
+static void idu_irq_enable(struct irq_data *data)
+{
+ /*
+ * By default send all common interrupts to all available online CPUs.
+ * The affinity of common interrupts in IDU must be set manually since
+ * in some cases the kernel will not call irq_set_affinity() by itself:
+ * 1. When the kernel is not configured with support of SMP.
+ * 2. When the kernel is configured with support of SMP but upper
+ * interrupt controllers does not support setting of the affinity
+ * and cannot propagate it to IDU.
+ */
+ idu_irq_set_affinity(data, cpu_online_mask, false);
+ idu_irq_unmask(data);
+}
static struct irq_chip idu_irq_chip = {
.name = "MCIP IDU Intc",
.irq_mask = idu_irq_mask,
.irq_unmask = idu_irq_unmask,
+ .irq_enable = idu_irq_enable,
#ifdef CONFIG_SMP
.irq_set_affinity = idu_irq_set_affinity,
#endif
@@ -221,10 +235,13 @@ static irq_hw_number_t idu_first_hwirq;
static void idu_cascade_isr(struct irq_desc *desc)
{
struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
+ struct irq_chip *core_chip = irq_desc_get_chip(desc);
irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
+ chained_irq_enter(core_chip, desc);
generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
+ chained_irq_exit(core_chip, desc);
}
static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
@@ -239,36 +256,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type)
{
- irq_hw_number_t hwirq = *out_hwirq = intspec[0];
- int distri = intspec[1];
- unsigned long flags;
-
+ /*
+ * Ignore value of interrupt distribution mode for common interrupts in
+ * IDU which resides in intspec[1] since setting an affinity using value
+ * from Device Tree is deprecated in ARC.
+ */
+ *out_hwirq = intspec[0];
*out_type = IRQ_TYPE_NONE;
- /* XXX: validate distribution scheme again online cpu mask */
- if (distri == 0) {
- /* 0 - Round Robin to all cpus, otherwise 1 bit per core */
- raw_spin_lock_irqsave(&mcip_lock, flags);
- idu_set_dest(hwirq, BIT(num_online_cpus()) - 1);
- idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR);
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
- } else {
- /*
- * DEST based distribution for Level Triggered intr can only
- * have 1 CPU, so generalize it to always contain 1 cpu
- */
- int cpu = ffs(distri);
-
- if (cpu != fls(distri))
- pr_warn("IDU irq %lx distri mode set to cpu %x\n",
- hwirq, cpu);
-
- raw_spin_lock_irqsave(&mcip_lock, flags);
- idu_set_dest(hwirq, cpu);
- idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST);
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
- }
-
return 0;
}
diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c
index 42e964db2967..3d99a6091332 100644
--- a/arch/arc/kernel/module.c
+++ b/arch/arc/kernel/module.c
@@ -32,8 +32,8 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
#ifdef CONFIG_ARC_DW2_UNWIND
mod->arch.unw_sec_idx = 0;
mod->arch.unw_info = NULL;
- mod->arch.secstr = secstr;
#endif
+ mod->arch.secstr = secstr;
return 0;
}
@@ -113,8 +113,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
}
+#ifdef CONFIG_ARC_DW2_UNWIND
if (strcmp(module->arch.secstr+sechdrs[tgtsec].sh_name, ".eh_frame") == 0)
module->arch.unw_sec_idx = tgtsec;
+#endif
return 0;
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 0385df77a697..3093fa898a23 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -10,6 +10,8 @@
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/root_dev.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/cpu.h>
@@ -234,11 +236,11 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
is_isa_arcompact() ? "ARCompact" : "ARCv2",
IS_AVAIL1(cpu->isa.be, "[Big-Endian]"));
- n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
+ n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ",
IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
- IS_AVAIL2(cpu->extn.rtc, "Local-64-bit-Ctr ",
- CONFIG_ARC_HAS_RTC));
+ IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
+ IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT));
n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s",
IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
@@ -449,6 +451,15 @@ void __init setup_arch(char **cmdline_p)
arc_unwind_init();
}
+/*
+ * Called from start_kernel() - boot CPU only
+ */
+void __init time_init(void)
+{
+ of_clk_init(NULL);
+ clocksource_probe();
+}
+
static int __init customize_machine(void)
{
if (machine_desc->init_machine)
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 88674d972c9d..2afbafadb6ab 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -90,22 +90,37 @@ void __init smp_cpus_done(unsigned int max_cpus)
*/
static volatile int wake_flag;
+#ifdef CONFIG_ISA_ARCOMPACT
+
+#define __boot_read(f) f
+#define __boot_write(f, v) f = v
+
+#else
+
+#define __boot_read(f) arc_read_uncached_32(&f)
+#define __boot_write(f, v) arc_write_uncached_32(&f, v)
+
+#endif
+
static void arc_default_smp_cpu_kick(int cpu, unsigned long pc)
{
BUG_ON(cpu == 0);
- wake_flag = cpu;
+
+ __boot_write(wake_flag, cpu);
}
void arc_platform_smp_wait_to_boot(int cpu)
{
- while (wake_flag != cpu)
+ /* for halt-on-reset, we've waited already */
+ if (IS_ENABLED(CONFIG_ARC_SMP_HALT_ON_RESET))
+ return;
+
+ while (__boot_read(wake_flag) != cpu)
;
- wake_flag = 0;
- __asm__ __volatile__("j @first_lines_of_secondary \n");
+ __boot_write(wake_flag, 0);
}
-
const char *arc_platform_smp_cpuinfo(void)
{
return plat_smp_ops.info ? : "";
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
deleted file mode 100644
index c10390d1ddb6..000000000000
--- a/arch/arc/kernel/time.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.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.
- *
- * vineetg: Jan 1011
- * -sched_clock( ) no longer jiffies based. Uses the same clocksource
- * as gtod
- *
- * Rajeshwarr/Vineetg: Mar 2008
- * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code)
- * for arch independent gettimeofday()
- * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers
- *
- * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c
- */
-
-/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1
- * Each can programmed to go from @count to @limit and optionally
- * interrupt when that happens.
- * A write to Control Register clears the Interrupt
- *
- * We've designated TIMER0 for events (clockevents)
- * while TIMER1 for free running (clocksource)
- *
- * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1
- * which however is currently broken
- */
-
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/cpu.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <asm/irq.h>
-#include <asm/arcregs.h>
-
-#include <asm/mcip.h>
-
-/* Timer related Aux registers */
-#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */
-#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */
-#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */
-#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */
-#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */
-#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */
-
-#define TIMER_CTRL_IE (1 << 0) /* Interrupt when Count reaches limit */
-#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */
-
-#define ARC_TIMER_MAX 0xFFFFFFFF
-
-static unsigned long arc_timer_freq;
-
-static int noinline arc_get_timer_clk(struct device_node *node)
-{
- struct clk *clk;
- int ret;
-
- clk = of_clk_get(node, 0);
- if (IS_ERR(clk)) {
- pr_err("timer missing clk");
- return PTR_ERR(clk);
- }
-
- ret = clk_prepare_enable(clk);
- if (ret) {
- pr_err("Couldn't enable parent clk\n");
- return ret;
- }
-
- arc_timer_freq = clk_get_rate(clk);
-
- return 0;
-}
-
-/********** Clock Source Device *********/
-
-#ifdef CONFIG_ARC_HAS_GFRC
-
-static cycle_t arc_read_gfrc(struct clocksource *cs)
-{
- unsigned long flags;
- union {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- struct { u32 h, l; };
-#else
- struct { u32 l, h; };
-#endif
- cycle_t full;
- } stamp;
-
- local_irq_save(flags);
-
- __mcip_cmd(CMD_GFRC_READ_LO, 0);
- stamp.l = read_aux_reg(ARC_REG_MCIP_READBACK);
-
- __mcip_cmd(CMD_GFRC_READ_HI, 0);
- stamp.h = read_aux_reg(ARC_REG_MCIP_READBACK);
-
- local_irq_restore(flags);
-
- return stamp.full;
-}
-
-static struct clocksource arc_counter_gfrc = {
- .name = "ARConnect GFRC",
- .rating = 400,
- .read = arc_read_gfrc,
- .mask = CLOCKSOURCE_MASK(64),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init arc_cs_setup_gfrc(struct device_node *node)
-{
- int exists = cpuinfo_arc700[0].extn.gfrc;
- int ret;
-
- if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected"))
- return -ENXIO;
-
- ret = arc_get_timer_clk(node);
- if (ret)
- return ret;
-
- return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
-}
-CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
-
-#endif
-
-#ifdef CONFIG_ARC_HAS_RTC
-
-#define AUX_RTC_CTRL 0x103
-#define AUX_RTC_LOW 0x104
-#define AUX_RTC_HIGH 0x105
-
-static cycle_t arc_read_rtc(struct clocksource *cs)
-{
- unsigned long status;
- union {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- struct { u32 high, low; };
-#else
- struct { u32 low, high; };
-#endif
- cycle_t full;
- } stamp;
-
- /*
- * hardware has an internal state machine which tracks readout of
- * low/high and updates the CTRL.status if
- * - interrupt/exception taken between the two reads
- * - high increments after low has been read
- */
- do {
- stamp.low = read_aux_reg(AUX_RTC_LOW);
- stamp.high = read_aux_reg(AUX_RTC_HIGH);
- status = read_aux_reg(AUX_RTC_CTRL);
- } while (!(status & _BITUL(31)));
-
- return stamp.full;
-}
-
-static struct clocksource arc_counter_rtc = {
- .name = "ARCv2 RTC",
- .rating = 350,
- .read = arc_read_rtc,
- .mask = CLOCKSOURCE_MASK(64),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init arc_cs_setup_rtc(struct device_node *node)
-{
- int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc;
- int ret;
-
- if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected"))
- return -ENXIO;
-
- /* Local to CPU hence not usable in SMP */
- if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP"))
- return -EINVAL;
-
- ret = arc_get_timer_clk(node);
- if (ret)
- return ret;
-
- write_aux_reg(AUX_RTC_CTRL, 1);
-
- return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
-}
-CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
-
-#endif
-
-/*
- * 32bit TIMER1 to keep counting monotonically and wraparound
- */
-
-static cycle_t arc_read_timer1(struct clocksource *cs)
-{
- return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT);
-}
-
-static struct clocksource arc_counter_timer1 = {
- .name = "ARC Timer1",
- .rating = 300,
- .read = arc_read_timer1,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init arc_cs_setup_timer1(struct device_node *node)
-{
- int ret;
-
- /* Local to CPU hence not usable in SMP */
- if (IS_ENABLED(CONFIG_SMP))
- return -EINVAL;
-
- ret = arc_get_timer_clk(node);
- if (ret)
- return ret;
-
- write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
- write_aux_reg(ARC_REG_TIMER1_CNT, 0);
- write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
-
- return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq);
-}
-
-/********** Clock Event Device *********/
-
-static int arc_timer_irq;
-
-/*
- * Arm the timer to interrupt after @cycles
- * The distinction for oneshot/periodic is done in arc_event_timer_ack() below
- */
-static void arc_timer_event_setup(unsigned int cycles)
-{
- write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles);
- write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */
-
- write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH);
-}
-
-
-static int arc_clkevent_set_next_event(unsigned long delta,
- struct clock_event_device *dev)
-{
- arc_timer_event_setup(delta);
- return 0;
-}
-
-static int arc_clkevent_set_periodic(struct clock_event_device *dev)
-{
- /*
- * At X Hz, 1 sec = 1000ms -> X cycles;
- * 10ms -> X / 100 cycles
- */
- arc_timer_event_setup(arc_timer_freq / HZ);
- return 0;
-}
-
-static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
- .name = "ARC Timer0",
- .features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_PERIODIC,
- .rating = 300,
- .set_next_event = arc_clkevent_set_next_event,
- .set_state_periodic = arc_clkevent_set_periodic,
-};
-
-static irqreturn_t timer_irq_handler(int irq, void *dev_id)
-{
- /*
- * Note that generic IRQ core could have passed @evt for @dev_id if
- * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
- */
- struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
- int irq_reenable = clockevent_state_periodic(evt);
-
- /*
- * Any write to CTRL reg ACks the interrupt, we rewrite the
- * Count when [N]ot [H]alted bit.
- * And re-arm it if perioid by [I]nterrupt [E]nable bit
- */
- write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-
-static int arc_timer_starting_cpu(unsigned int cpu)
-{
- struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
-
- evt->cpumask = cpumask_of(smp_processor_id());
-
- clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX);
- enable_percpu_irq(arc_timer_irq, 0);
- return 0;
-}
-
-static int arc_timer_dying_cpu(unsigned int cpu)
-{
- disable_percpu_irq(arc_timer_irq);
- return 0;
-}
-
-/*
- * clockevent setup for boot CPU
- */
-static int __init arc_clockevent_setup(struct device_node *node)
-{
- struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
- int ret;
-
- arc_timer_irq = irq_of_parse_and_map(node, 0);
- if (arc_timer_irq <= 0) {
- pr_err("clockevent: missing irq");
- return -EINVAL;
- }
-
- ret = arc_get_timer_clk(node);
- if (ret) {
- pr_err("clockevent: missing clk");
- return ret;
- }
-
- /* Needs apriori irq_set_percpu_devid() done in intc map function */
- ret = request_percpu_irq(arc_timer_irq, timer_irq_handler,
- "Timer0 (per-cpu-tick)", evt);
- if (ret) {
- pr_err("clockevent: unable to request irq\n");
- return ret;
- }
-
- ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING,
- "AP_ARC_TIMER_STARTING",
- arc_timer_starting_cpu,
- arc_timer_dying_cpu);
- if (ret) {
- pr_err("Failed to setup hotplug state");
- return ret;
- }
- return 0;
-}
-
-static int __init arc_of_timer_init(struct device_node *np)
-{
- static int init_count = 0;
- int ret;
-
- if (!init_count) {
- init_count = 1;
- ret = arc_clockevent_setup(np);
- } else {
- ret = arc_cs_setup_timer1(np);
- }
-
- return ret;
-}
-CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init);
-
-/*
- * Called from start_kernel() - boot CPU only
- */
-void __init time_init(void)
-{
- of_clk_init(NULL);
- clocksource_probe();
-}
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c
index abd961f3e763..5f69c3bd59bb 100644
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -241,8 +241,9 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs,
if (state.fault)
goto fault;
+ /* clear any remanants of delay slot */
if (delay_mode(regs)) {
- regs->ret = regs->bta;
+ regs->ret = regs->bta & ~1U;
regs->status32 &= ~STATUS_DE_MASK;
} else {
regs->ret += state.instr_len;