summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2011-04-18 11:25:44 +0000
committerDavid S. Miller <davem@davemloft.net>2011-04-19 22:11:40 -0700
commit6baa9b20a68a88c2fd751cbe8d7652009379351b (patch)
tree999283be451c020ff35110c336292e9d698d2464
parent06010fb588700e7fcb29e720c56884e3de5fd327 (diff)
sparc32: genirq support
The conversion of sparc32 to genirq is based on original work done by David S. Miller. Daniel Hellstrom has helped in the conversion and implemented the shutdowm functionality. Marcel van Nies <morcles@gmail.com> has tested this on Sparc Station 20 Test status: sun4c - not tested sun4m,pci - not tested sun4m,sbus - tested (Sparc Classic, Sparc Station 5, Sparc Station 20) sun4d - not tested leon - tested on various combinations of leon boards, including SMP variants generic Introduce use of GENERIC_HARDIRQS and GENERIC_IRQ_SHOW Allocate 64 IRQs - which is enough even for SS2000 Use a table of irq_bucket to maintain uses IRQs irq_bucket is also used to chain several irq's that must be called when the same intrrupt is asserted Use irq_link to link a interrupt source to the irq All plafforms must now supply their own build_device_irq method handler_irq rewriten to use generic irq support floppy Read FLOPPY_IRQ from platform device Use generic request_irq to register the floppy interrupt Rewrote sparc_floppy_irq to use the generic irq support pcic: Introduce irq_chip Store mask in chip_data for use in mask/unmask functions Add build_device_irq for pcic Use pcic_build_device_irq in pci_time_init allocate virtual irqs in pcic_fill_irq sun4c: Introduce irq_chip Store mask in chip_data for use in mask/unmask functions Add build_device_irq for sun4c Use sun4c_build_device_irq in sun4c_init_timers sun4m: Introduce irq_chip Introduce dedicated mask/unmask methods Introduce sun4m_handler_data that allow easy access to necessary data in the mask/unmask functions Add a helper method to enable profile_timer (used from smp) Added sun4m_build_device_irq Use sun4m_build_device_irq in sun4m_init_timers TODO: There is no replacement for smp_rotate that always scheduled next CPU as interrupt target upon an interrupt sun4d: Introduce irq_chip Introduce dedicated mask/unmask methods Introduce sun4d_handler_data that allow easy access to necessary data in mask/unmask fuctions Rewrote sun4d_handler_irq to use generic irq support TODO: The original implmentation of enable/disable had: if (irq < NR_IRQS) return; The new implmentation does not distingush between SBUS and cpu interrupts. I am no sure what is right here. I assume we need to do something for the cpu interrupts. I have not succeeded booting my sun4d box (with or without this patch) and my understanding of this platfrom is limited. So I would be a bit suprised if this works. leon: Introduce irq_chip Store mask in chip_data for use in mask/unmask functions Add build_device_irq for leon Use leon_build_device_irq in leon_init_timers Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Acked-by: Daniel Hellstrom <daniel@gaisler.com> Tested-by: Daniel Hellstrom <daniel@gaisler.com> Tested-by: Marcel van Nies <morcles@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/Kconfig6
-rw-r--r--arch/sparc/include/asm/floppy_32.h40
-rw-r--r--arch/sparc/include/asm/irq_32.h6
-rw-r--r--arch/sparc/include/asm/system_32.h5
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/irq.h45
-rw-r--r--arch/sparc/kernel/irq_32.c494
-rw-r--r--arch/sparc/kernel/kernel.h1
-rw-r--r--arch/sparc/kernel/leon_kernel.c70
-rw-r--r--arch/sparc/kernel/pcic.c83
-rw-r--r--arch/sparc/kernel/sun4c_irq.c150
-rw-r--r--arch/sparc/kernel/sun4d_irq.c472
-rw-r--r--arch/sparc/kernel/sun4m_irq.c179
-rw-r--r--arch/sparc/kernel/sun4m_smp.c16
14 files changed, 636 insertions, 935 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index e560d102215a..a56630d4f14b 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -25,6 +25,10 @@ config SPARC
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_HARDIRQS_NO_DEPRECATED
+ select GENERIC_IRQ_SHOW
+
config SPARC32
def_bool !64BIT
@@ -50,8 +54,6 @@ config SPARC64
select RTC_DRV_STARFIRE
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
- select HAVE_GENERIC_HARDIRQS
- select GENERIC_IRQ_SHOW
select IRQ_PREFLOW_FASTEOI
config ARCH_DEFCONFIG
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index 86666f70322e..482c79e2a416 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -281,28 +281,27 @@ static inline void sun_fd_enable_dma(void)
pdma_areasize = pdma_size;
}
-/* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern int sparc_floppy_request_irq(int irq, unsigned long flags,
- irq_handler_t irq_handler);
+extern int sparc_floppy_request_irq(unsigned int irq,
+ irq_handler_t irq_handler);
static int sun_fd_request_irq(void)
{
static int once = 0;
- int error;
- if(!once) {
+ if (!once) {
once = 1;
- error = sparc_floppy_request_irq(FLOPPY_IRQ,
- IRQF_DISABLED,
- floppy_interrupt);
- return ((error == 0) ? 0 : -1);
- } else return 0;
+ return sparc_floppy_request_irq(FLOPPY_IRQ, floppy_interrupt);
+ } else {
+ return 0;
+ }
}
static struct linux_prom_registers fd_regs[2];
static int sun_floppy_init(void)
{
+ struct platform_device *op;
+ struct device_node *dp;
char state[128];
phandle tnode, fd_node;
int num_regs;
@@ -310,7 +309,6 @@ static int sun_floppy_init(void)
use_virtual_dma = 1;
- FLOPPY_IRQ = 11;
/* Forget it if we aren't on a machine that could possibly
* ever have a floppy drive.
*/
@@ -349,6 +347,26 @@ static int sun_floppy_init(void)
sun_fdc = (struct sun_flpy_controller *)
of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+ /* Look up irq in platform_device.
+ * We try "SUNW,fdtwo" and "fd"
+ */
+ for_each_node_by_name(dp, "SUNW,fdtwo") {
+ op = of_find_device_by_node(dp);
+ if (op)
+ break;
+ }
+ if (!op) {
+ for_each_node_by_name(dp, "fd") {
+ op = of_find_device_by_node(dp);
+ if (op)
+ break;
+ }
+ }
+ if (!op)
+ goto no_sun_fdc;
+
+ FLOPPY_IRQ = op->archdata.irqs[0];
+
/* Last minute sanity check... */
if(sun_fdc->status_82072 == 0xff) {
sun_fdc = NULL;
diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h
index eced3e3ebd30..2ae3acaeb1b3 100644
--- a/arch/sparc/include/asm/irq_32.h
+++ b/arch/sparc/include/asm/irq_32.h
@@ -6,7 +6,11 @@
#ifndef _SPARC_IRQ_H
#define _SPARC_IRQ_H
-#define NR_IRQS 16
+/* Allocated number of logical irq numbers.
+ * sun4d boxes (ss2000e) should be OK with ~32.
+ * Be on the safe side and make room for 64
+ */
+#define NR_IRQS 64
#include <linux/interrupt.h>
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index 890036b3689a..47a7e862474e 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -15,11 +15,6 @@
#include <linux/irqflags.h>
-static inline unsigned int probe_irq_mask(unsigned long val)
-{
- return 0;
-}
-
/*
* Sparc (general) CPU types
*/
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 99aa4db6e9c2..9cff2709a96d 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -71,10 +71,6 @@ obj-$(CONFIG_SPARC64) += pcr.o
obj-$(CONFIG_SPARC64) += nmi.o
obj-$(CONFIG_SPARC64_SMP) += cpumap.o
-# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
-obj-$(CONFIG_SPARC32) += devres.o
-devres-y := ../../../kernel/irq/devres.o
-
obj-y += dma.o
obj-$(CONFIG_SPARC32_PCI) += pcic.o
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 008453b798ec..a189c273f638 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -2,6 +2,23 @@
#include <asm/btfixup.h>
+struct irq_bucket {
+ struct irq_bucket *next;
+ unsigned int real_irq;
+ unsigned int irq;
+ unsigned int pil;
+};
+
+#define SUN4D_MAX_BOARD 10
+#define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5)
+
+/* Map between the irq identifier used in hw to the
+ * irq_bucket. The map is sufficient large to hold
+ * the sun4d hw identifiers.
+ */
+extern struct irq_bucket *irq_map[SUN4D_MAX_IRQ];
+
+
/* sun4m specific type definitions */
/* This maps direct to CPU specific interrupt registers */
@@ -35,6 +52,10 @@ struct sparc_irq_config {
};
extern struct sparc_irq_config sparc_irq_config;
+unsigned int irq_alloc(unsigned int real_irq, unsigned int pil);
+void irq_link(unsigned int irq);
+void irq_unlink(unsigned int irq);
+void handler_irq(unsigned int pil, struct pt_regs *regs);
/* Dave Redman (djhr@tadpole.co.uk)
* changed these to function pointers.. it saves cycles and will allow
@@ -44,33 +65,9 @@ extern struct sparc_irq_config sparc_irq_config;
* Changed these to btfixup entities... It saves cycles :)
*/
-BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, clear_clock_irq, void)
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-static inline void __disable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void __enable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_irq)(irq);
-}
-
-static inline void disable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_pil_irq)(irq);
-}
-
-static inline void enable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_pil_irq)(irq);
-}
-
static inline void clear_clock_irq(void)
{
BTFIXUP_CALL(clear_clock_irq)();
diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c
index b2dbb4ba8608..197e1ba85484 100644
--- a/arch/sparc/kernel/irq_32.c
+++ b/arch/sparc/kernel/irq_32.c
@@ -15,6 +15,7 @@
#include <linux/seq_file.h>
#include <asm/cacheflush.h>
+#include <asm/cpudata.h>
#include <asm/pcic.h>
#include <asm/leon.h>
@@ -101,284 +102,163 @@ EXPORT_SYMBOL(arch_local_irq_restore);
* directed CPU interrupts using the existing enable/disable irq code
* with tweaks.
*
+ * Sun4d complicates things even further. IRQ numbers are arbitrary
+ * 32-bit values in that case. Since this is similar to sparc64,
+ * we adopt a virtual IRQ numbering scheme as is done there.
+ * Virutal interrupt numbers are allocated by build_irq(). So NR_IRQS
+ * just becomes a limit of how many interrupt sources we can handle in
+ * a single system. Even fully loaded SS2000 machines top off at
+ * about 32 interrupt sources or so, therefore a NR_IRQS value of 64
+ * is more than enough.
+ *
+ * We keep a map of per-PIL enable interrupts. These get wired
+ * up via the irq_chip->startup() method which gets invoked by
+ * the generic IRQ layer during request_irq().
*/
+/* Table of allocated irqs. Unused entries has irq == 0 */
+static struct irq_bucket irq_table[NR_IRQS];
+/* Protect access to irq_table */
+static DEFINE_SPINLOCK(irq_table_lock);
-/*
- * Dave Redman (djhr@tadpole.co.uk)
- *
- * There used to be extern calls and hard coded values here.. very sucky!
- * instead, because some of the devices attach very early, I do something
- * equally sucky but at least we'll never try to free statically allocated
- * space or call kmalloc before kmalloc_init :(.
- *
- * In fact it's the timer10 that attaches first.. then timer14
- * then kmalloc_init is called.. then the tty interrupts attach.
- * hmmm....
- *
- */
-#define MAX_STATIC_ALLOC 4
-struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count;
-
-static struct {
- struct irqaction *action;
- int flags;
-} sparc_irq[NR_IRQS];
-#define SPARC_IRQ_INPROGRESS 1
-
-/* Used to protect the IRQ action lists */
-DEFINE_SPINLOCK(irq_action_lock);
+/* Map between the irq identifier used in hw to the irq_bucket. */
+struct irq_bucket *irq_map[SUN4D_MAX_IRQ];
+/* Protect access to irq_map */
+static DEFINE_SPINLOCK(irq_map_lock);
-int show_interrupts(struct seq_file *p, void *v)
+/* Allocate a new irq from the irq_table */
+unsigned int irq_alloc(unsigned int real_irq, unsigned int pil)
{
- int i = *(loff_t *)v;
- struct irqaction *action;
unsigned long flags;
-#ifdef CONFIG_SMP
- int j;
-#endif
+ unsigned int i;
+
+ spin_lock_irqsave(&irq_table_lock, flags);
+ for (i = 1; i < NR_IRQS; i++) {
+ if (irq_table[i].real_irq == real_irq && irq_table[i].pil == pil)
+ goto found;
+ }
- if (sparc_cpu_model == sun4d)
- return show_sun4d_interrupts(p, v);
+ for (i = 1; i < NR_IRQS; i++) {
+ if (!irq_table[i].irq)
+ break;
+ }
- spin_lock_irqsave(&irq_action_lock, flags);
if (i < NR_IRQS) {
- action = sparc_irq[i].action;
- if (!action)
- goto out_unlock;
- seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
- seq_printf(p, "%10u ", kstat_irqs(i));
-#else
- for_each_online_cpu(j) {
- seq_printf(p, "%10u ",
- kstat_cpu(j).irqs[i]);
- }
-#endif
- seq_printf(p, " %c %s",
- (action->flags & IRQF_DISABLED) ? '+' : ' ',
- action->name);
- for (action = action->next; action; action = action->next) {
- seq_printf(p, ",%s %s",
- (action->flags & IRQF_DISABLED) ? " +" : "",
- action->name);
- }
- seq_putc(p, '\n');
+ irq_table[i].real_irq = real_irq;
+ irq_table[i].irq = i;
+ irq_table[i].pil = pil;
+ } else {
+ printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
+ i = 0;
}
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return 0;
+found:
+ spin_unlock_irqrestore(&irq_table_lock, flags);
+
+ return i;
}
-void free_irq(unsigned int irq, void *dev_id)
+/* Based on a single pil handler_irq may need to call several
+ * interrupt handlers. Use irq_map as entry to irq_table,
+ * and let each entry in irq_table point to the next entry.
+ */
+void irq_link(unsigned int irq)
{
- struct irqaction *action;
- struct irqaction **actionp;
+ struct irq_bucket *p;
unsigned long flags;
- unsigned int cpu_irq;
+ unsigned int pil;
- if (sparc_cpu_model == sun4d) {
- sun4d_free_irq(irq, dev_id);
- return;
- }
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) { /* 14 irq levels on the sparc */
- printk(KERN_ERR "Trying to free bogus IRQ %d\n", irq);
- return;
- }
+ BUG_ON(irq >= NR_IRQS);
- spin_lock_irqsave(&irq_action_lock, flags);
+ spin_lock_irqsave(&irq_map_lock, flags);
- actionp = &sparc_irq[cpu_irq].action;
- action = *actionp;
+ p = &irq_table[irq];
+ pil = p->pil;
+ BUG_ON(pil > SUN4D_MAX_IRQ);
+ p->next = irq_map[pil];
+ irq_map[pil] = p;
- if (!action->handler) {
- printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
- goto out_unlock;
- }
- if (dev_id) {
- for (; action; action = action->next) {
- if (action->dev_id == dev_id)
- break;
- actionp = &action->next;
- }
- if (!action) {
- printk(KERN_ERR "Trying to free free shared IRQ%d\n",
- irq);
- goto out_unlock;
- }
- } else if (action->flags & IRQF_SHARED) {
- printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n",
- irq);
- goto out_unlock;
- }
- if (action->flags & SA_STATIC_ALLOC) {
- /*
- * This interrupt is marked as specially allocated
- * so it is a bad idea to free it.
- */
- printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n",
- irq, action->name);
- goto out_unlock;
- }
-
- *actionp = action->next;
-
- spin_unlock_irqrestore(&irq_action_lock, flags);
+ spin_unlock_irqrestore(&irq_map_lock, flags);
+}
- synchronize_irq(irq);
+void irq_unlink(unsigned int irq)
+{
+ struct irq_bucket *p, **pnext;
+ unsigned long flags;
- spin_lock_irqsave(&irq_action_lock, flags);
+ BUG_ON(irq >= NR_IRQS);
- kfree(action);
+ spin_lock_irqsave(&irq_map_lock, flags);
- if (!sparc_irq[cpu_irq].action)
- __disable_irq(irq);
+ p = &irq_table[irq];
+ BUG_ON(p->pil > SUN4D_MAX_IRQ);
+ pnext = &irq_map[p->pil];
+ while (*pnext != p)
+ pnext = &(*pnext)->next;
+ *pnext = p->next;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
+ spin_unlock_irqrestore(&irq_map_lock, flags);
}
-EXPORT_SYMBOL(free_irq);
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
- unsigned int cpu_irq;
- cpu_irq = irq & (NR_IRQS - 1);
- while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
- cpu_relax();
-}
-EXPORT_SYMBOL(synchronize_irq);
-#endif /* SMP */
-
-void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs)
+/* /proc/interrupts printing */
+int arch_show_interrupts(struct seq_file *p, int prec)
{
- int i;
- struct irqaction *action;
- unsigned int cpu_irq;
+ int j;
- cpu_irq = irq & (NR_IRQS - 1);
- action = sparc_irq[cpu_irq].action;
-
- printk(KERN_ERR "IO device interrupt, irq = %d\n", irq);
- printk(KERN_ERR "PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc,
- regs->npc, regs->u_regs[14]);
- if (action) {
- printk(KERN_ERR "Expecting: ");
- for (i = 0; i < 16; i++)
- if (action->handler)
- printk(KERN_CONT "[%s:%d:0x%x] ", action->name,
- i, (unsigned int)action->handler);
- }
- printk(KERN_ERR "AIEEE\n");
- panic("bogus interrupt received");
+ seq_printf(p, "NMI: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_data(j).counter);
+ seq_printf(p, " Non-maskable interrupts\n");
+ return 0;
}
-void handler_irq(int pil, struct pt_regs *regs)
+void handler_irq(unsigned int pil, struct pt_regs *regs)
{
struct pt_regs *old_regs;
- struct irqaction *action;
- int cpu = smp_processor_id();
+ struct irq_bucket *p;
+ BUG_ON(pil > 15);
old_regs = set_irq_regs(regs);
irq_enter();
- disable_pil_irq(pil);
-#ifdef CONFIG_SMP
- /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */
- if ((sparc_cpu_model==sun4m) && (pil < 10))
- smp4m_irq_rotate(cpu);
-#endif
- action = sparc_irq[pil].action;
- sparc_irq[pil].flags |= SPARC_IRQ_INPROGRESS;
- kstat_cpu(cpu).irqs[pil]++;
- do {
- if (!action || !action->handler)
- unexpected_irq(pil, NULL, regs);
- action->handler(pil, action->dev_id);
- action = action->next;
- } while (action);
- sparc_irq[pil].flags &= ~SPARC_IRQ_INPROGRESS;
- enable_pil_irq(pil);
+
+ p = irq_map[pil];
+ while (p) {
+ struct irq_bucket *next = p->next;
+
+ generic_handle_irq(p->irq);
+ p = next;
+ }
irq_exit();
set_irq_regs(old_regs);
}
#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+static unsigned int floppy_irq;
-/*
- * Fast IRQs on the Sparc can only have one routine attached to them,
- * thus no sharing possible.
- */
-static int request_fast_irq(unsigned int irq,
- void (*handler)(void),
- unsigned long irqflags, const char *devname)
+int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler)
{
- struct irqaction *action;
- unsigned long flags;
unsigned int cpu_irq;
- int ret;
+ int err;
+
#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON
struct tt_entry *trap_table;
#endif
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) {
- ret = -EINVAL;
- goto out;
- }
- if (!handler) {
- ret = -EINVAL;
- goto out;
- }
- spin_lock_irqsave(&irq_action_lock, flags);
+ err = request_irq(irq, irq_handler, 0, "floppy", NULL);
+ if (err)
+ return -1;
- action = sparc_irq[cpu_irq].action;
- if (action) {
- if (action->flags & IRQF_SHARED)
- panic("Trying to register fast irq when already shared.\n");
- if (irqflags & IRQF_SHARED)
- panic("Trying to register fast irq as shared.\n");
+ /* Save for later use in floppy interrupt handler */
+ floppy_irq = irq;
- /* Anyway, someone already owns it so cannot be made fast. */
- printk(KERN_ERR "request_fast_irq: Trying to register yet already owned.\n");
- ret = -EBUSY;
- goto out_unlock;
- }
-
- /*
- * If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk(KERN_ERR "Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
- irq, devname);
- }
-
- if (action == NULL)
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
- if (!action) {
- ret = -ENOMEM;
- goto out_unlock;
- }
+ cpu_irq = (irq & (NR_IRQS - 1));
/* Dork with trap table if we get this far. */
#define INSTANTIATE(table) \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \
- SPARC_BRANCH((unsigned long) handler, \
+ SPARC_BRANCH((unsigned long) floppy_hardint, \
(unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
@@ -399,22 +279,9 @@ static int request_fast_irq(unsigned int irq,
* writing we have no CPU-neutral interface to fine-grained flushes.
*/
flush_cache_all();
-
- action->flags = irqflags;
- action->name = devname;
- action->dev_id = NULL;
- action->next = NULL;
-
- sparc_irq[cpu_irq].action = action;
-
- __enable_irq(irq);
-
- ret = 0;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
- return ret;
+ return 0;
}
+EXPORT_SYMBOL(sparc_floppy_request_irq);
/*
* These variables are used to access state from the assembler
@@ -440,154 +307,23 @@ EXPORT_SYMBOL(pdma_base);
unsigned long pdma_areasize;
EXPORT_SYMBOL(pdma_areasize);
-static irq_handler_t floppy_irq_handler;
-
+/* Use the generic irq support to call floppy_interrupt
+ * which was setup using request_irq() in sparc_floppy_request_irq().
+ * We only have one floppy interrupt so we do not need to check
+ * for additional handlers being wired up by irq_link()
+ */
void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct pt_regs *old_regs;
- int cpu = smp_processor_id();
old_regs = set_irq_regs(regs);
- disable_pil_irq(irq);
irq_enter();
- kstat_cpu(cpu).irqs[irq]++;
- floppy_irq_handler(irq, dev_id);
+ generic_handle_irq(floppy_irq);
irq_exit();
- enable_pil_irq(irq);
set_irq_regs(old_regs);
- /*
- * XXX Eek, it's totally changed with preempt_count() and such
- * if (softirq_pending(cpu))
- * do_softirq();
- */
}
-
-int sparc_floppy_request_irq(int irq, unsigned long flags,
- irq_handler_t irq_handler)
-{
- floppy_irq_handler = irq_handler;
- return request_fast_irq(irq, floppy_hardint, flags, "floppy");
-}
-EXPORT_SYMBOL(sparc_floppy_request_irq);
-
#endif
-int request_irq(unsigned int irq,
- irq_handler_t handler,
- unsigned long irqflags, const char *devname, void *dev_id)
-{
- struct irqaction *action, **actionp;
- unsigned long flags;
- unsigned int cpu_irq;
- int ret;
-
- if (sparc_cpu_model == sun4d)
- return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
-
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) {
- ret = -EINVAL;
- goto out;
- }
- if (!handler) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&irq_action_lock, flags);
-
- actionp = &sparc_irq[cpu_irq].action;
- action = *actionp;
- if (action) {
- if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) {
- ret = -EBUSY;
- goto out_unlock;
- }
- if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) {
- printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n",
- irq);
- ret = -EBUSY;
- goto out_unlock;
- }
- for ( ; action; action = *actionp)
- actionp = &action->next;
- }
-
- /* If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
- irq, devname);
- }
- if (action == NULL)
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
- if (!action) {
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- action->handler = handler;
- action->flags = irqflags;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- *actionp = action;
-
- __enable_irq(irq);
-
- ret = 0;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
- return ret;
-}
-EXPORT_SYMBOL(request_irq);
-
-void disable_irq_nosync(unsigned int irq)
-{
- __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq_nosync);
-
-void disable_irq(unsigned int irq)
-{
- __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq);
-
-void enable_irq(unsigned int irq)
-{
- __enable_irq(irq);
-}
-EXPORT_SYMBOL(enable_irq);
-
-/*
- * We really don't need these at all on the Sparc. We only have
- * stubs here because they are exported to modules.
- */
-unsigned long probe_irq_on(void)
-{
- return 0;
-}
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off(unsigned long mask)
-{
- return 0;
-}
-EXPORT_SYMBOL(probe_irq_off);
-
-static unsigned int build_device_irq(struct platform_device *op,
- unsigned int real_irq)
-{
- return real_irq;
-}
-
/* djhr
* This could probably be made indirect too and assigned in the CPU
* bits of the code. That would be much nicer I think and would also
@@ -598,8 +334,6 @@ static unsigned int build_device_irq(struct platform_device *op,
void __init init_IRQ(void)
{
- sparc_irq_config.build_device_irq = build_device_irq;
-
switch (sparc_cpu_model) {
case sun4c:
case sun4:
@@ -629,9 +363,3 @@ void __init init_IRQ(void)
btfixup();
}
-#ifdef CONFIG_PROC_FS
-void init_irq_proc(void)
-{
- /* For now, nothing... */
-}
-#endif /* CONFIG_PROC_FS */
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 24ad449886be..487d67a4e7f6 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -37,6 +37,7 @@ extern void sun4c_init_IRQ(void);
extern unsigned int lvl14_resolution;
extern void sun4m_init_IRQ(void);
+extern void sun4m_unmask_profile_irq(void);
extern void sun4m_clear_profile_irq(int cpu);
/* sun4d_irq.c */
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index 2969f777fa11..8591cf124ecf 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -83,20 +83,22 @@ static inline unsigned long get_irqmask(unsigned int irq)
return mask;
}
-static void leon_enable_irq(unsigned int irq_nr)
+static void leon_unmask_irq(struct irq_data *data)
{
unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
+
+ mask = (unsigned long)data->chip_data;
local_irq_save(flags);
LEON3_BYPASS_STORE_PA(LEON_IMASK,
(LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask)));
local_irq_restore(flags);
}
-static void leon_disable_irq(unsigned int irq_nr)
+static void leon_mask_irq(struct irq_data *data)
{
unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
+
+ mask = (unsigned long)data->chip_data;
local_irq_save(flags);
LEON3_BYPASS_STORE_PA(LEON_IMASK,
(LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask)));
@@ -104,6 +106,50 @@ static void leon_disable_irq(unsigned int irq_nr)
}
+static unsigned int leon_startup_irq(struct irq_data *data)
+{
+ irq_link(data->irq);
+ leon_unmask_irq(data);
+ return 0;
+}
+
+static void leon_shutdown_irq(struct irq_data *data)
+{
+ leon_mask_irq(data);
+ irq_unlink(data->irq);
+}
+
+static struct irq_chip leon_irq = {
+ .name = "leon",
+ .irq_startup = leon_startup_irq,
+ .irq_shutdown = leon_shutdown_irq,
+ .irq_mask = leon_mask_irq,
+ .irq_unmask = leon_unmask_irq,
+};
+
+static unsigned int leon_build_device_irq(struct platform_device *op,
+ unsigned int real_irq)
+{
+ unsigned int irq;
+ unsigned long mask;
+
+ irq = 0;
+ mask = get_irqmask(real_irq);
+ if (mask == 0)
+ goto out;
+
+ irq = irq_alloc(real_irq, real_irq);
+ if (irq == 0)
+ goto out;
+
+ irq_set_chip_and_handler_name(irq, &leon_irq,
+ handle_simple_irq, "edge");
+ irq_set_chip_data(irq, (void *)mask);
+
+out:
+ return irq;
+}
+
void __init leon_init_timers(irq_handler_t counter_fn)
{
int irq;
@@ -112,6 +158,7 @@ void __init leon_init_timers(irq_handler_t counter_fn)
int len;
int cpu, icsel;
int ampopts;
+ int err;
leondebug_irq_disable = 0;
leon_debug_irqout = 0;
@@ -219,11 +266,10 @@ void __init leon_init_timers(irq_handler_t counter_fn)
goto bad;
}
- irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+ irq = leon_build_device_irq(NULL, leon3_gptimer_irq + leon3_gptimer_idx);
+ err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
- if (irq) {
+ if (err) {
printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n",
LEON_INTERRUPT_TIMER1);
prom_halt();
@@ -347,12 +393,8 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
void __init leon_init_IRQ(void)
{
- sparc_irq_config.init_timers = leon_init_timers;
-
- BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM);
+ sparc_irq_config.init_timers = leon_init_timers;
+ sparc_irq_config.build_device_irq = leon_build_device_irq;
BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq,
BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 2cdc131b50ac..948601a066ff 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -164,6 +164,9 @@ void __iomem *pcic_regs;
volatile int pcic_speculative;
volatile int pcic_trapped;
+/* forward */
+unsigned int pcic_build_device_irq(struct platform_device *op,
+ unsigned int real_irq);
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
@@ -523,6 +526,7 @@ static void
pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
{
struct pcic_ca2irq *p;
+ unsigned int real_irq;
int i, ivec;
char namebuf[64];
@@ -551,26 +555,25 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
i = p->pin;
if (i >= 0 && i < 4) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);
- dev->irq = ivec >> (i << 2) & 0xF;
+ real_irq = ivec >> (i << 2) & 0xF;
} else if (i >= 4 && i < 8) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
- dev->irq = ivec >> ((i-4) << 2) & 0xF;
+ real_irq = ivec >> ((i-4) << 2) & 0xF;
} else { /* Corrupted map */
printk("PCIC: BAD PIN %d\n", i); for (;;) {}
}
/* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); *