/* irq.c: UltraSparc IRQ handling/init/registry.
*
- * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 2007, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/hypervisor.h>
#include <asm/cacheflush.h>
-/* UPA nodes send interrupt packet to UltraSparc with first data reg
- * value low 5 (7 on Starfire) bits holding the IRQ identifier being
- * delivered. We must translate this into a non-vector IRQ so we can
- * set the softint on this cpu.
- *
- * To make processing these packets efficient and race free we use
- * an array of irq buckets below. The interrupt vector handler in
- * entry.S feeds incoming packets into per-cpu pil-indexed lists.
- *
- * If you make changes to ino_bucket, please update hand coded assembler
- * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
- */
-struct ino_bucket {
-/*0x00*/unsigned long __irq_chain_pa;
-
- /* Virtual interrupt number assigned to this INO. */
-/*0x08*/unsigned int __virt_irq;
-/*0x0c*/unsigned int __pad;
-};
+#include "entry.h"
#define NUM_IVECS (IMAP_INR + 1)
+
struct ino_bucket *ivector_table;
unsigned long ivector_table_pa;
unsigned long imap;
void (*pre_handler)(unsigned int, void *, void *);
- void *pre_handler_arg1;
- void *pre_handler_arg2;
+ void *arg1;
+ void *arg2;
};
#ifdef CONFIG_SMP
IMAP_AID_SAFARI | IMAP_NID_SAFARI);
val |= tid | IMAP_VALID;
upa_writeq(val, imap);
+ upa_writeq(ICLR_IDLE, data->iclr);
}
}
}
}
-static void sun4u_irq_end(unsigned int virt_irq)
+static void sun4u_irq_eoi(unsigned int virt_irq)
{
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
struct irq_desc *desc = irq_desc + virt_irq;
"err(%d)\n", ino, err);
}
-static void sun4v_irq_end(unsigned int virt_irq)
+static void sun4v_irq_eoi(unsigned int virt_irq)
{
unsigned int ino = virt_irq_table[virt_irq].dev_ino;
struct irq_desc *desc = irq_desc + virt_irq;
dev_handle, dev_ino, err);
}
-static void sun4v_virq_end(unsigned int virt_irq)
+static void sun4v_virq_eoi(unsigned int virt_irq)
{
struct irq_desc *desc = irq_desc + virt_irq;
unsigned long dev_handle, dev_ino;
dev_handle, dev_ino, err);
}
-static void run_pre_handler(unsigned int virt_irq)
-{
- struct irq_handler_data *data = get_irq_chip_data(virt_irq);
- unsigned int ino;
-
- ino = virt_irq_table[virt_irq].dev_ino;
- if (likely(data->pre_handler)) {
- data->pre_handler(ino,
- data->pre_handler_arg1,
- data->pre_handler_arg2);
- }
-}
-
static struct irq_chip sun4u_irq = {
.typename = "sun4u",
.enable = sun4u_irq_enable,
.disable = sun4u_irq_disable,
- .end = sun4u_irq_end,
- .set_affinity = sun4u_set_affinity,
-};
-
-static struct irq_chip sun4u_irq_ack = {
- .typename = "sun4u+ack",
- .enable = sun4u_irq_enable,
- .disable = sun4u_irq_disable,
- .ack = run_pre_handler,
- .end = sun4u_irq_end,
+ .eoi = sun4u_irq_eoi,
.set_affinity = sun4u_set_affinity,
};
.typename = "sun4v",
.enable = sun4v_irq_enable,
.disable = sun4v_irq_disable,
- .end = sun4v_irq_end,
+ .eoi = sun4v_irq_eoi,
.set_affinity = sun4v_set_affinity,
};
.typename = "vsun4v",
.enable = sun4v_virq_enable,
.disable = sun4v_virq_disable,
- .end = sun4v_virq_end,
+ .eoi = sun4v_virq_eoi,
.set_affinity = sun4v_virt_set_affinity,
};
+static void pre_flow_handler(unsigned int virt_irq,
+ struct irq_desc *desc)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+
+ data->pre_handler(ino, data->arg1, data->arg2);
+
+ handle_fasteoi_irq(virt_irq, desc);
+}
+
void irq_install_pre_handler(int virt_irq,
void (*func)(unsigned int, void *, void *),
void *arg1, void *arg2)
{
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
- struct irq_chip *chip = get_irq_chip(virt_irq);
-
- if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
- printk(KERN_ERR "IRQ: Trying to install pre-handler on "
- "sun4v irq %u\n", virt_irq);
- return;
- }
+ struct irq_desc *desc = irq_desc + virt_irq;
data->pre_handler = func;
- data->pre_handler_arg1 = arg1;
- data->pre_handler_arg2 = arg2;
+ data->arg1 = arg1;
+ data->arg2 = arg2;
- if (chip == &sun4u_irq_ack)
- return;
-
- set_irq_chip(virt_irq, &sun4u_irq_ack);
+ desc->handle_irq = pre_flow_handler;
}
unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
if (!virt_irq) {
virt_irq = virt_irq_alloc(0, ino);
bucket_set_virt_irq(__pa(bucket), virt_irq);
- set_irq_chip(virt_irq, &sun4u_irq);
+ set_irq_chip_and_handler_name(virt_irq,
+ &sun4u_irq,
+ handle_fasteoi_irq,
+ "IVEC");
}
data = get_irq_chip_data(virt_irq);
if (!virt_irq) {
virt_irq = virt_irq_alloc(0, sysino);
bucket_set_virt_irq(__pa(bucket), virt_irq);
- set_irq_chip(virt_irq, chip);
+ set_irq_chip_and_handler_name(virt_irq, chip,
+ handle_fasteoi_irq,
+ "IVEC");
}
data = get_irq_chip_data(virt_irq);
virt_irq = virt_irq_alloc(devhandle, devino);
bucket_set_virt_irq(__pa(bucket), virt_irq);
- set_irq_chip(virt_irq, &sun4v_virq);
+
+ set_irq_chip_and_handler_name(virt_irq, &sun4v_virq,
+ handle_fasteoi_irq,
+ "IVEC");
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data))
: "memory");
while (bucket_pa) {
+ struct irq_desc *desc;
unsigned long next_pa;
unsigned int virt_irq;
virt_irq = bucket_get_virt_irq(bucket_pa);
bucket_clear_chain_pa(bucket_pa);
- __do_IRQ(virt_irq);
+ desc = irq_desc + virt_irq;
+
+ desc->handle_irq(virt_irq, desc);
bucket_pa = next_pa;
}