#include <linux/random.h>
#include <linux/sched.h>
-#include <asm/bitops.h>
#include <asm/mipsregs.h>
#include <asm/signal.h>
#include <asm/system.h>
#include <asm/ip32/ip32_ints.h>
/* issue a PIO read to make sure no PIO writes are pending */
-#define flush_crime_bus() crime_read(CRIME_CONTROL);
+static void inline flush_crime_bus(void)
+{
+ crime->control;
+}
+
static void inline flush_mace_bus(void)
{
- volatile unsigned long junk = mace_perif_ctrl_read(misc);
+ mace->perif.ctrl.misc;
}
#undef DEBUG_IRQ
* IRQ spinlock - Ralf says not to disable CPU interrupts,
* and I think he knows better.
*/
-static spinlock_t ip32_irq_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ip32_irq_lock);
/* Some initial interrupts to set up */
extern irqreturn_t crime_memerr_intr (int irq, void *dev_id,
struct pt_regs *regs);
struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
- 0, "CRIME memory error", NULL, NULL };
+ CPU_MASK_NONE, "CRIME memory error", NULL, NULL };
struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
- 0, "CRIME CPU error", NULL, NULL };
-
-extern void ip32_handle_int(void);
+ CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
/*
* For interrupts wired from a single device to the CPU. Only the clock
#define mask_and_ack_cpu_irq disable_cpu_irq
static struct hw_interrupt_type ip32_cpu_interrupt = {
- "IP32 CPU",
- startup_cpu_irq,
- shutdown_cpu_irq,
- enable_cpu_irq,
- disable_cpu_irq,
- mask_and_ack_cpu_irq,
- end_cpu_irq,
- NULL
+ .typename = "IP32 CPU",
+ .startup = startup_cpu_irq,
+ .shutdown = shutdown_cpu_irq,
+ .enable = enable_cpu_irq,
+ .disable = disable_cpu_irq,
+ .ack = mask_and_ack_cpu_irq,
+ .end = end_cpu_irq,
};
/*
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask |= 1 << (irq - 1);
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask &= ~(1 << (irq - 1));
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
flush_crime_bus();
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
|| (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
uint64_t crime_int;
spin_lock_irqsave(&ip32_irq_lock, flags);
- crime_int = crime_read(CRIME_HARD_INT);
+ crime_int = crime->hard_int;
crime_int &= ~(1 << (irq - 1));
- crime_write(crime_int, CRIME_HARD_INT);
+ crime->hard_int = crime_int;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
disable_crime_irq(irq);
#define shutdown_crime_irq disable_crime_irq
static struct hw_interrupt_type ip32_crime_interrupt = {
- "IP32 CRIME",
- startup_crime_irq,
- shutdown_crime_irq,
- enable_crime_irq,
- disable_crime_irq,
- mask_and_ack_crime_irq,
- end_crime_irq,
- NULL
+ .typename = "IP32 CRIME",
+ .startup = startup_crime_irq,
+ .shutdown = shutdown_crime_irq,
+ .enable = enable_crime_irq,
+ .disable = disable_crime_irq,
+ .ack = mask_and_ack_crime_irq,
+ .end = end_crime_irq,
};
/*
macepci_mask |= MACEPCI_CONTROL_INT(irq - 9);
mace->pci.control = macepci_mask;
crime_mask |= 1 << (irq - 1);
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask &= ~(1 << (irq - 1));
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
flush_crime_bus();
macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
mace->pci.control = macepci_mask;
#define mask_and_ack_macepci_irq disable_macepci_irq
static struct hw_interrupt_type ip32_macepci_interrupt = {
- "IP32 MACE PCI",
- startup_macepci_irq,
- shutdown_macepci_irq,
- enable_macepci_irq,
- disable_macepci_irq,
- mask_and_ack_macepci_irq,
- end_macepci_irq,
- NULL
+ .typename = "IP32 MACE PCI",
+ .startup = startup_macepci_irq,
+ .shutdown = shutdown_macepci_irq,
+ .enable = enable_macepci_irq,
+ .disable = disable_macepci_irq,
+ .ack = mask_and_ack_macepci_irq,
+ .end = end_macepci_irq,
};
/* This is used for MACE ISA interrupts. That means bits 4-6 in the
DBG ("crime_int %08x enabled\n", crime_int);
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask |= crime_int;
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
maceisa_mask |= 1 << (irq - 33);
- mace_perif_ctrl_write(maceisa_mask, imask);
+ mace->perif.ctrl.imask = maceisa_mask;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
if(!(maceisa_mask & MACEISA_SUPERIO_INT))
crime_int |= MACE_SUPERIO_INT;
crime_mask &= ~crime_int;
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
flush_crime_bus();
- mace_perif_ctrl_write(maceisa_mask, imask);
+ mace->perif.ctrl.imask = maceisa_mask;
flush_mace_bus();
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
case MACEISA_SERIAL2_TDMAPR_IRQ:
/* edge triggered */
spin_lock_irqsave(&ip32_irq_lock, flags);
- mace_int = mace_perif_ctrl_read(istat);
+ mace_int = mace->perif.ctrl.istat;
mace_int &= ~(1 << (irq - 33));
- mace_perif_ctrl_write(mace_int, istat);
+ mace->perif.ctrl.istat = mace_int;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
break;
}
#define shutdown_maceisa_irq disable_maceisa_irq
static struct hw_interrupt_type ip32_maceisa_interrupt = {
- "IP32 MACE ISA",
- startup_maceisa_irq,
- shutdown_maceisa_irq,
- enable_maceisa_irq,
- disable_maceisa_irq,
- mask_and_ack_maceisa_irq,
- end_maceisa_irq,
- NULL
+ .typename = "IP32 MACE ISA",
+ .startup = startup_maceisa_irq,
+ .shutdown = shutdown_maceisa_irq,
+ .enable = enable_maceisa_irq,
+ .disable = disable_maceisa_irq,
+ .ack = mask_and_ack_maceisa_irq,
+ .end = end_maceisa_irq,
};
/* This is used for regular non-ISA, non-PCI MACE interrupts. That means
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask |= 1 << (irq - 1);
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
spin_lock_irqsave(&ip32_irq_lock, flags);
crime_mask &= ~(1 << (irq - 1));
- crime_write(crime_mask, CRIME_INT_MASK);
+ crime->imask = crime_mask;
flush_crime_bus();
spin_unlock_irqrestore(&ip32_irq_lock, flags);
}
#define mask_and_ack_mace_irq disable_mace_irq
static struct hw_interrupt_type ip32_mace_interrupt = {
- "IP32 MACE",
- startup_mace_irq,
- shutdown_mace_irq,
- enable_mace_irq,
- disable_mace_irq,
- mask_and_ack_mace_irq,
- end_mace_irq,
- NULL
+ .typename = "IP32 MACE",
+ .startup = startup_mace_irq,
+ .shutdown = shutdown_mace_irq,
+ .enable = enable_mace_irq,
+ .disable = disable_mace_irq,
+ .ack = mask_and_ack_mace_irq,
+ .end = end_mace_irq,
};
static void ip32_unknown_interrupt(struct pt_regs *regs)
{
- uint64_t crime;
-
printk ("Unknown interrupt occurred!\n");
printk ("cp0_status: %08x\n", read_c0_status());
printk ("cp0_cause: %08x\n", read_c0_cause());
- crime = crime_read(CRIME_INT_MASK);
- printk ("CRIME intr mask: %016lx\n", crime);
- crime = crime_read(CRIME_INT_STAT);
- printk ("CRIME intr status: %016lx\n", crime);
- crime = crime_read(CRIME_HARD_INT);
- printk ("CRIME hardware intr register: %016lx\n", crime);
- printk ("MACE ISA intr mask: %08lx\n", mace_perif_ctrl_read(imask));
- printk ("MACE ISA intr status: %08lx\n", mace_perif_ctrl_read(istat));
+ printk ("CRIME intr mask: %016lx\n", crime->imask);
+ printk ("CRIME intr status: %016lx\n", crime->istat);
+ printk ("CRIME hardware intr register: %016lx\n", crime->hard_int);
+ printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask);
+ printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat);
printk ("MACE PCI control register: %08x\n", mace->pci.control);
printk("Register dump:\n");
/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
/* change this to loop over all edge-triggered irqs, exception masked out ones */
-void ip32_irq0(struct pt_regs *regs)
+static void ip32_irq0(struct pt_regs *regs)
{
uint64_t crime_int;
int irq = 0;
- crime_int = crime_read(CRIME_INT_STAT) & crime_mask;
- irq = ffs(crime_int);
- crime_int = 1 << (irq - 1);
+ crime_int = crime->istat & crime_mask;
+ irq = __ffs(crime_int);
+ crime_int = 1 << irq;
if (crime_int & CRIME_MACEISA_INT_MASK) {
- unsigned long mace_int = mace_perif_ctrl_read(istat);
- irq = ffs(mace_int & maceisa_mask) + 32;
+ unsigned long mace_int = mace->perif.ctrl.istat;
+ irq = __ffs(mace_int & maceisa_mask) + 32;
}
+ irq++;
DBG("*irq %u*\n", irq);
do_IRQ(irq, regs);
}
-void ip32_irq1(struct pt_regs *regs)
+static void ip32_irq1(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq2(struct pt_regs *regs)
+static void ip32_irq2(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq3(struct pt_regs *regs)
+static void ip32_irq3(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq4(struct pt_regs *regs)
+static void ip32_irq4(struct pt_regs *regs)
{
ip32_unknown_interrupt(regs);
}
-void ip32_irq5(struct pt_regs *regs)
+static void ip32_irq5(struct pt_regs *regs)
{
ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
}
-void __init init_IRQ(void)
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_cause();
+
+ if (likely(pending & IE_IRQ0))
+ ip32_irq0(regs);
+ else if (unlikely(pending & IE_IRQ1))
+ ip32_irq1(regs);
+ else if (unlikely(pending & IE_IRQ2))
+ ip32_irq2(regs);
+ else if (unlikely(pending & IE_IRQ3))
+ ip32_irq3(regs);
+ else if (unlikely(pending & IE_IRQ4))
+ ip32_irq4(regs);
+ else if (likely(pending & IE_IRQ5))
+ ip32_irq5(regs);
+}
+
+void __init arch_init_irq(void)
{
unsigned int irq;
- init_generic_irq();
/* Install our interrupt handler, then clear and disable all
* CRIME and MACE interrupts. */
- crime_write(0, CRIME_INT_MASK);
- crime_write(0, CRIME_HARD_INT);
- crime_write(0, CRIME_SOFT_INT);
- mace_perif_ctrl_write(0, istat);
- mace_perif_ctrl_write(0, imask);
- set_except_vector(0, ip32_handle_int);
+ crime->imask = 0;
+ crime->hard_int = 0;
+ crime->soft_int = 0;
+ mace->perif.ctrl.istat = 0;
+ mace->perif.ctrl.imask = 0;
for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
hw_irq_controller *controller;