diff options
Diffstat (limited to 'arch/sparc/kernel/leon_kernel.c')
| -rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 129 |
1 files changed, 69 insertions, 60 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index b7c68976cbc7..a43cf794bb1e 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB @@ -7,9 +8,7 @@ #include <linux/errno.h> #include <linux/mutex.h> #include <linux/of.h> -#include <linux/of_platform.h> #include <linux/interrupt.h> -#include <linux/of_device.h> #include <linux/clocksource.h> #include <linux/clockchips.h> @@ -32,12 +31,13 @@ struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base addr int leondebug_irq_disable; int leon_debug_irqout; -static int dummy_master_l10_counter; +static volatile u32 dummy_master_l10_counter; unsigned long amba_system_id; static DEFINE_SPINLOCK(leon_irq_lock); +static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ +static unsigned long leon3_gptimer_ackmask; /* For clearing pending bit */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ -unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned int sparc_leon_eirq; #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IACK (&leon3_irqctrl_regs->iclear) @@ -52,7 +52,7 @@ static inline unsigned int leon_eirq_get(int cpu) } /* Handle one or multiple IRQs from the extended interrupt controller */ -static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) +static void leon_handle_ext_irq(struct irq_desc *desc) { unsigned int eirq; struct irq_bucket *p; @@ -65,7 +65,7 @@ static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) } /* The extended IRQ controller has been found, this function registers it */ -void leon_eirq_setup(unsigned int eirq) +static void leon_eirq_setup(unsigned int eirq) { unsigned long mask, oldmask; unsigned int veirq; @@ -106,13 +106,12 @@ unsigned long leon_get_irqmask(unsigned int irq) #ifdef CONFIG_SMP static int irq_choose_cpu(const struct cpumask *affinity) { - cpumask_t mask; + unsigned int cpu = cpumask_first_and(affinity, cpu_online_mask); - cpumask_and(&mask, cpu_online_mask, affinity); - if (cpumask_equal(&mask, cpu_online_mask) || cpumask_empty(&mask)) + if (cpumask_subset(cpu_online_mask, affinity) || cpu >= nr_cpu_ids) return boot_cpu_id; else - return cpumask_first(&mask); + return cpu; } #else #define irq_choose_cpu(affinity) boot_cpu_id @@ -125,7 +124,7 @@ static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest, int oldcpu, newcpu; mask = (unsigned long)data->chip_data; - oldcpu = irq_choose_cpu(data->affinity); + oldcpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); newcpu = irq_choose_cpu(dest); if (oldcpu == newcpu) @@ -148,7 +147,7 @@ static void leon_unmask_irq(struct irq_data *data) int cpu; mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); + cpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); spin_lock_irqsave(&leon_irq_lock, flags); oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask)); @@ -161,7 +160,7 @@ static void leon_mask_irq(struct irq_data *data) int cpu; mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); + cpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); spin_lock_irqsave(&leon_irq_lock, flags); oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask)); @@ -202,7 +201,7 @@ static struct irq_chip leon_irq = { /* * Build a LEON IRQ for the edge triggered LEON IRQ controller: - * Edge (normal) IRQ - handle_simple_irq, ack=DONT-CARE, never ack + * Edge (normal) IRQ - handle_simple_irq, ack=DON'T-CARE, never ack * Level IRQ (PCI|Level-GPIO) - handle_fasteoi_irq, ack=1, ack after ISR * Per-CPU Edge - handle_percpu_irq, ack=0 */ @@ -260,17 +259,25 @@ void leon_update_virq_handling(unsigned int virq, static u32 leon_cycles_offset(void) { - u32 rld, val, off; + u32 rld, val, ctrl, off; + rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld); val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val); - off = rld - val; - return rld - val; + ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl); + if (LEON3_GPTIMER_CTRL_ISPENDING(ctrl)) { + val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val); + off = 2 * rld - val; + } else { + off = rld - val; + } + + return off; } #ifdef CONFIG_SMP /* smp clockevent irq */ -irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) +static irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) { struct clock_event_device *ce; int cpu = smp_processor_id(); @@ -302,6 +309,7 @@ void __init leon_init_timers(void) int ampopts; int err; u32 config; + u32 ctrl; sparc_config.get_cycles_offset = leon_cycles_offset; sparc_config.cs_period = 1000000 / HZ; @@ -313,7 +321,7 @@ void __init leon_init_timers(void) leondebug_irq_disable = 0; leon_debug_irqout = 0; - master_l10_counter = (unsigned int *)&dummy_master_l10_counter; + master_l10_counter = (u32 __iomem *)&dummy_master_l10_counter; dummy_master_l10_counter = 0; rootnp = of_find_node_by_path("/ambapp0"); @@ -339,41 +347,51 @@ void __init leon_init_timers(void) /* Find GPTIMER Timer Registers base address otherwise bail out. */ nnp = rootnp; - do { - np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); - if (!np) { - np = of_find_node_by_name(nnp, "01_011"); - if (!np) - goto bad; - } - ampopts = 0; - pp = of_find_property(np, "ampopts", &len); - if (pp) { - ampopts = *(int *)pp->value; - if (ampopts == 0) { - /* Skip this instance, resource already - * allocated by other OS */ - nnp = np; - continue; - } +retry: + np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); + if (!np) { + np = of_find_node_by_name(nnp, "01_011"); + if (!np) + goto bad; + } + + ampopts = 0; + pp = of_find_property(np, "ampopts", &len); + if (pp) { + ampopts = *(int *)pp->value; + if (ampopts == 0) { + /* Skip this instance, resource already + * allocated by other OS */ + nnp = np; + goto retry; } + } - /* Select Timer-Instance on Timer Core. Default is zero */ - leon3_gptimer_idx = ampopts & 0x7; + /* Select Timer-Instance on Timer Core. Default is zero */ + leon3_gptimer_idx = ampopts & 0x7; - pp = of_find_property(np, "reg", &len); - if (pp) - leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **) - pp->value; - pp = of_find_property(np, "interrupts", &len); - if (pp) - leon3_gptimer_irq = *(unsigned int *)pp->value; - } while (0); + pp = of_find_property(np, "reg", &len); + if (pp) + leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **) + pp->value; + pp = of_find_property(np, "interrupts", &len); + if (pp) + leon3_gptimer_irq = *(unsigned int *)pp->value; if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq)) goto bad; + ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl); + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, + ctrl | LEON3_GPTIMER_CTRL_PENDING); + ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl); + + if ((ctrl & LEON3_GPTIMER_CTRL_PENDING) != 0) + leon3_gptimer_ackmask = ~LEON3_GPTIMER_CTRL_PENDING; + else + leon3_gptimer_ackmask = ~0; + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld, (((1000000 / HZ) - 1))); @@ -452,24 +470,15 @@ bad: static void leon_clear_clock_irq(void) { -} + u32 ctrl; -static void leon_load_profile_irq(int cpu, unsigned int limit) -{ + ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl); + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, + ctrl & leon3_gptimer_ackmask); } -void __init leon_trans_init(struct device_node *dp) +static void leon_load_profile_irq(int cpu, unsigned int limit) { - if (strcmp(dp->type, "cpu") == 0 && strcmp(dp->name, "<NULL>") == 0) { - struct property *p; - p = of_find_property(dp, "mid", (void *)0); - if (p) { - int mid; - dp->name = prom_early_alloc(5 + 1); - memcpy(&mid, p->value, p->length); - sprintf((char *)dp->name, "cpu%.2d", mid); - } - } } #ifdef CONFIG_SMP |
