aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c')
-rw-r--r--target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c597
1 files changed, 0 insertions, 597 deletions
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c
deleted file mode 100644
index c041f23e25..0000000000
--- a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * arch/ubicom32/kernel/irq.c
- * Ubicom32 architecture IRQ support.
- *
- * (C) Copyright 2009, Ubicom, Inc.
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is part of the Ubicom32 Linux Kernel Port.
- *
- * The Ubicom32 Linux Kernel Port is free software: you can redistribute
- * it and/or modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 2 of the
- * License, or (at your option) any later version.
- *
- * The Ubicom32 Linux Kernel Port is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Ubicom32 Linux Kernel Port. If not,
- * see <http://www.gnu.org/licenses/>.
- *
- * Ubicom32 implementation derived from (with many thanks):
- * arch/m68knommu
- * arch/blackfin
- * arch/parisc
- */
-
-#include <linux/types.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/ldsr.h>
-#include <asm/ip5000.h>
-#include <asm/machdep.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread.h>
-#include <asm/devtree.h>
-
-unsigned int irq_soft_avail;
-static struct irqaction ubicom32_reserve_action[NR_IRQS];
-
-#if !defined(CONFIG_DEBUG_IRQMEASURE)
-#define IRQ_DECLARE_MEASUREMENT
-#define IRQ_MEASUREMENT_START()
-#define IRQ_MEASUREMENT_END(irq)
-#else
-#define IRQ_DECLARE_MEASUREMENT \
- int __diff; \
- unsigned int __tstart;
-
-#define IRQ_MEASUREMENT_START() \
- __tstart = UBICOM32_IO_TIMER->sysval;
-
-#define IRQ_MEASUREMENT_END(irq) \
- __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \
- irq_measurement_update((irq), __diff);
-
-/*
- * We keep track of the time spent in both irq_enter()
- * and irq_exit().
- */
-#define IRQ_WEIGHT 32
-
-struct irq_measurement {
- volatile unsigned int min;
- volatile unsigned int avg;
- volatile unsigned int max;
-};
-
-static DEFINE_SPINLOCK(irq_measurement_lock);
-
-/*
- * Add 1 in for softirq (irq_exit());
- */
-static struct irq_measurement irq_measurements[NR_IRQS + 1];
-
-/*
- * irq_measurement_update()
- * Update an entry in the measurement array for this irq.
- */
-static void irq_measurement_update(int irq, int sample)
-{
- struct irq_measurement *im = &irq_measurements[irq];
- spin_lock(&irq_measurement_lock);
- if ((im->min == 0) || (im->min > sample)) {
- im->min = sample;
- }
- if (im->max < sample) {
- im->max = sample;
- }
- im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT;
- spin_unlock(&irq_measurement_lock);
-}
-#endif
-
-/*
- * irq_kernel_stack_check()
- * See if the kernel stack is within STACK_WARN of the end.
- */
-static void irq_kernel_stack_check(int irq, struct pt_regs *regs)
-{
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
- unsigned long sp;
-
- /*
- * Make sure that we are not close to the top of the stack and thus
- * can not really service this interrupt.
- */
- asm volatile (
- "and.4 %0, SP, %1 \n\t"
- : "=d" (sp)
- : "d" (THREAD_SIZE - 1)
- : "cc"
- );
-
- if (sp < (sizeof(struct thread_info) + STACK_WARN)) {
- printk(KERN_WARNING
- "cpu[%d]: possible overflow detected sp remain: %p, "
- "irq: %d, regs: %p\n",
- thread_get_self(), (void *)sp, irq, regs);
- dump_stack();
- }
-
- if (sp < (sizeof(struct thread_info) + 16)) {
- THREAD_STALL;
- }
-#endif
-}
-
-/*
- * irq_get_lsb()
- * Get the LSB set in value
- */
-static int irq_get_lsb(unsigned int value)
-{
- static unsigned char irq_bits[8] = {
- 3, 0, 1, 0, 2, 0, 1, 0
- };
- u32_t nextbit = 0;
-
- value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit));
-
- /*
- * It's unlikely that we find that we execute the body of this while
- * loop. 50% of the time we won't take this at all and then of the
- * cases where we do about 50% of those we only execute once.
- */
- if (!(value & 0xffff)) {
- nextbit += 0x10;
- value >>= 16;
- }
-
- if (!(value & 0xff)) {
- nextbit += 0x08;
- value >>= 8;
- }
-
- if (!(value & 0xf)) {
- nextbit += 0x04;
- value >>= 4;
- }
-
- nextbit += irq_bits[value & 0x7];
- if (nextbit > 63) {
- panic("nextbit out of range: %d\n", nextbit);
- }
- return nextbit;
-}
-
-/*
- * ubicom32_reserve_handler()
- * Bogus handler associated with pre-reserved IRQ(s).
- */
-static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id)
-{
- BUG();
- return IRQ_HANDLED;
-}
-
-/*
- * __irq_disable_vector()
- * Disable the interrupt by clearing the appropriate bit in the
- * LDSR Mask Register.
- */
-static void __irq_disable_vector(unsigned int irq)
-{
- ldsr_disable_vector(irq);
-}
-
-/*
- * __irq_ack_vector()
- * Acknowledge the specific interrupt by clearing the associate bit in
- * hardware
- */
-static void __irq_ack_vector(unsigned int irq)
-{
- if (irq < 32) {
- asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq));
- } else {
- asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32)));
- }
-}
-
-/*
- * __irq_enable_vector()
- * Clean and then enable the interrupt by setting the appropriate bit in
- * the LDSR Mask Register.
- */
-static void __irq_enable_vector(unsigned int irq)
-{
- /*
- * Acknowledge, really clear the vector.
- */
- __irq_ack_vector(irq);
- ldsr_enable_vector(irq);
-}
-
-/*
- * __irq_mask_vector()
- */
-static void __irq_mask_vector(unsigned int irq)
-{
- ldsr_mask_vector(irq);
-}
-
-/*
- * __irq_unmask_vector()
- */
-static void __irq_unmask_vector(unsigned int irq)
-{
- ldsr_unmask_vector(irq);
-}
-
-/*
- * __irq_end_vector()
- * Called once an interrupt is completed (reset the LDSR mask).
- */
-static void __irq_end_vector(unsigned int irq)
-{
- ldsr_unmask_vector(irq);
-}
-
-#if defined(CONFIG_SMP)
-/*
- * __irq_set_affinity()
- * Set the cpu affinity for this interrupt.
- * affinity container allocated at boot
- */
-static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest)
-{
- smp_set_affinity(irq, dest);
- cpumask_copy(irq_desc[irq].affinity, dest);
-}
-#endif
-
-/*
- * On-Chip Generic Interrupt function handling.
- */
-static struct irq_chip ubicom32_irq_chip = {
- .name = "Ubicom32",
- .startup = NULL,
- .shutdown = NULL,
- .enable = __irq_enable_vector,
- .disable = __irq_disable_vector,
- .ack = __irq_ack_vector,
- .mask = __irq_mask_vector,
- .unmask = __irq_unmask_vector,
- .end = __irq_end_vector,
-#if defined(CONFIG_SMP)
- .set_affinity = __irq_set_affinity,
-#endif
-};
-
-/*
- * do_IRQ()
- * Primary interface for handling IRQ() requests.
- */
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
-{
- struct pt_regs *oldregs;
- struct thread_info *ti = current_thread_info();
-
- IRQ_DECLARE_MEASUREMENT;
-
- /*
- * Mark that we are inside of an interrupt and
- * that interrupts are disabled.
- */
- oldregs = set_irq_regs(regs);
- ti->interrupt_nesting++;
- trace_hardirqs_off();
- irq_kernel_stack_check(irq, regs);
-
- /*
- * Start the interrupt sequence
- */
- irq_enter();
-
- /*
- * Execute the IRQ handler and any pending SoftIRQ requests.
- */
- BUG_ON(!irqs_disabled());
- IRQ_MEASUREMENT_START();
- __do_IRQ(irq);
- IRQ_MEASUREMENT_END(irq);
- BUG_ON(!irqs_disabled());
-
- /*
- * TODO: Since IRQ's are disabled when calling irq_exit()
- * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag.
- * This will slightly improve performance by enabling
- * softirq handling to avoid disabling/disabled interrupts.
- */
- IRQ_MEASUREMENT_START();
- irq_exit();
- IRQ_MEASUREMENT_END(NR_IRQS);
- BUG_ON(!irqs_disabled());
-
- /*
- * Outside of an interrupt (or nested exit).
- */
- set_irq_regs(oldregs);
- trace_hardirqs_on();
- ti->interrupt_nesting--;
-}
-
-/*
- * irq_soft_alloc()
- * Allocate a soft IRQ.
- */
-int irq_soft_alloc(unsigned int *soft)
-{
- if (irq_soft_avail == 0) {
- printk(KERN_NOTICE "no soft irqs to allocate\n");
- return -EFAULT;
- }
-
- *soft = irq_get_lsb(irq_soft_avail);
- irq_soft_avail &= ~(1 << *soft);
- return 0;
-}
-
-/*
- * ack_bad_irq()
- * Called to handle an bad irq request.
- */
-void ack_bad_irq(unsigned int irq)
-{
- printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
- __irq_end_vector(irq);
-}
-
-/*
- * show_interrupts()
- * Return a string that displays the state of each of the interrupts.
- */
-int show_interrupts(struct seq_file *p, void *v)
-{
- struct irqaction *ap;
- int irq = *((loff_t *) v);
- int j;
-
- if (irq >= NR_IRQS) {
- return 0;
- }
-
- if (irq == 0) {
- seq_puts(p, " ");
- for_each_online_cpu(j) {
- seq_printf(p, "CPU%d ", j);
- }
- seq_putc(p, '\n');
- }
-
- ap = irq_desc[irq].action;
- if (ap) {
- seq_printf(p, "%3d: ", irq);
- for_each_online_cpu(j) {
- seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j));
- }
- seq_printf(p, "%14s ", irq_desc[irq].chip->name);
- seq_printf(p, "%s", ap->name);
- for (ap = ap->next; ap; ap = ap->next) {
- seq_printf(p, ", %s", ap->name);
- }
- seq_putc(p, '\n');
- }
- return 0;
-}
-
-#if defined(CONFIG_DEBUG_IRQMEASURE)
-static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency)
-{
- unsigned int micro = (cycles / (frequency / 1000000));
- return micro;
-}
-
-/*
- * irq_measurement_show()
- * Print out the min, avg, max values for each IRQ
- *
- * By request, the max value is reset after each dump.
- */
-static int irq_measurement_show(struct seq_file *p, void *v)
-{
- struct irqaction *ap;
- unsigned int freq = processor_frequency();
- int irq = *((loff_t *) v);
-
-
- if (irq == 0) {
- seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n");
- }
-
- if (irq > NR_IRQS) {
- return 0;
- }
-
- if (irq == NR_IRQS) {
- unsigned int min, avg, max;
- spin_lock(&irq_measurement_lock);
- min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
- avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
- max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
- irq_measurements[irq].max = 0;
- spin_unlock(&irq_measurement_lock);
- seq_printf(p, " \t%u\t%u\t%u\tsoftirq\n", min, avg, max);
- return 0;
- }
-
- ap = irq_desc[irq].action;
- if (ap) {
- unsigned int min, avg, max;
- spin_lock(&irq_measurement_lock);
- min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
- avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
- max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
- irq_measurements[irq].max = 0;
- spin_unlock(&irq_measurement_lock);
- seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name);
- }
- return 0;
-}
-
-static void *irq_measurement_start(struct seq_file *f, loff_t *pos)
-{
- return (*pos <= NR_IRQS) ? pos : NULL;
-}
-
-static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos)
-{
- (*pos)++;
- if (*pos > NR_IRQS)
- return NULL;
- return pos;
-}
-
-static void irq_measurement_stop(struct seq_file *f, void *v)
-{
- /* Nothing to do */
-}
-
-static const struct seq_operations irq_measurement_seq_ops = {
- .start = irq_measurement_start,
- .next = irq_measurement_next,
- .stop = irq_measurement_stop,
- .show = irq_measurement_show,
-};
-
-static int irq_measurement_open(struct inode *inode, struct file *filp)
-{
- return seq_open(filp, &irq_measurement_seq_ops);
-}
-
-static const struct file_operations irq_measurement_fops = {
- .open = irq_measurement_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static int __init irq_measurement_init(void)
-{
- proc_create("irq_measurements", 0, NULL, &irq_measurement_fops);
- return 0;
-}
-module_init(irq_measurement_init);
-#endif
-
-/*
- * init_IRQ(void)
- * Initialize the on-chip IRQ subsystem.
- */
-void __init init_IRQ(void)
-{
- int irq;
- struct devtree_node *p = NULL;
- struct devtree_node *iter = NULL;
- unsigned int mask = 0;
- unsigned int reserved = 0;
-
- /*
- * Pull out the list of software interrupts that are avialable to
- * Linux and provide an allocation function for them. The first
- * 24 interrupts of INT0 are software interrupts.
- */
- irq_soft_avail = 0;
- if (processor_interrupts(&irq_soft_avail, NULL) < 0) {
- printk(KERN_WARNING "No Soft IRQ(s) available\n");
- }
- irq_soft_avail &= ((1 << 24) - 1);
-
- /*
- * Initialize all of the on-chip interrupt handling
- * to use a common set of interrupt functions.
- */
- for (irq = 0; irq < NR_IRQS; irq++) {
- irq_desc[irq].status = IRQ_DISABLED;
- irq_desc[irq].action = NULL;
- irq_desc[irq].depth = 1;
- set_irq_chip(irq, &ubicom32_irq_chip);
- }
-
- /*
- * The sendirq of a devnode is not registered within Linux but instead
- * is used by the software I/O thread. These interrupts are reserved.
- * The recvirq is used by Linux and registered by a device driver, these
- * are not reserved.
- *
- * recvirq(s) that are in the software interrupt range are not supposed
- * to be marked as reserved. We track this while we scan the device
- * nodes.
- */
- p = devtree_find_next(&iter);
- while (p) {
- unsigned char sendirq, recvirq;
- devtree_irq(p, &sendirq, &recvirq);
-
- /*
- * If the sendirq is valid, mark that irq as taken by the
- * devtree node.
- */
- if (sendirq < NR_IRQS) {
- ubicom32_reserve_action[sendirq].handler =
- ubicom32_reserve_handler;
- ubicom32_reserve_action[sendirq].name = p->name;
- irq_desc[sendirq].action =
- &ubicom32_reserve_action[sendirq];
- mask |= (1 << sendirq);
- }
-
- /*
- * Track the relevant recieve IRQ(s)
- */
- if (recvirq < 24) {
- mask |= (1 << recvirq);
- }
-
- /*
- * Move to the next node.
- */
- p = devtree_find_next(&iter);
- }
-
- /*
- * Remove these bits from the irq_soft_avail list and then use the
- * result as the list of pre-reserved IRQ(s).
- */
- reserved = ~irq_soft_avail & ~mask;
- for (irq = 0; irq < 24; irq++) {
- if ((reserved & (1 << irq))) {
- ubicom32_reserve_action[irq].handler =
- ubicom32_reserve_handler;
- ubicom32_reserve_action[irq].name = "reserved";
- irq_desc[irq].action = &ubicom32_reserve_action[irq];
- }
- }
-
- /*
- * Initialize the LDSR which is the Ubicom32 programmable
- * interrupt controller.
- */
- ldsr_init();
-
- /*
- * The Ubicom trap code needs a 2nd init after IRQ(s) are setup.
- */
- trap_init_interrupt();
-}