X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=arch%2Fmips%2Fpmc-sierra%2Fyosemite%2Firq.c;h=e8b7ed63eaa0e0dedef41ac160760083e41844da;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=294290f8ae4c84376fc1f1bd4d2957591bb09108;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c index 294290f8a..e8b7ed63e 100644 --- a/arch/mips/pmc-sierra/yosemite/irq.c +++ b/arch/mips/pmc-sierra/yosemite/irq.c @@ -41,207 +41,116 @@ #include #include #include +#include #include #include +#include /* Hypertransport specific */ -#define IRQ_STATUS_REG_CPU0 0xbb001b30 /* INT# 3 status register on CPU 0*/ -#define IRQ_STATUS_REG_CPU1 0xbb002b30 /* INT# 3 status register on CPU 1*/ -#define IRQ_ACK_BITS 0x00000000 /* Ack bits */ -#define IRQ_CLEAR_REG_CPU0 0xbb002b3c /* IRQ clear register on CPU 0*/ -#define IRQ_CLEAR_REG_CPU0 0xbb002b3c /* IRQ clear register on CPU 1*/ +#define IRQ_ACK_BITS 0x00000000 /* Ack bits */ -#define HYPERTRANSPORT_EOI 0xbb0006E0 /* End of Interrupt */ -#define HYPERTRANSPORT_INTA 0x78 /* INTA# */ -#define HYPERTRANSPORT_INTB 0x79 /* INTB# */ -#define HYPERTRANSPORT_INTC 0x7a /* INTC# */ -#define HYPERTRANSPORT_INTD 0x7b /* INTD# */ - -#define read_32bit_cp0_set1_register(source) \ -({ int __res; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set\treorder\n\t" \ - "cfc0\t%0,"STR(source)"\n\t" \ - ".set\tpop" \ - : "=r" (__res)); \ - __res;}) - -#define write_32bit_cp0_set1_register(register,value) \ - __asm__ __volatile__( \ - "ctc0\t%0,"STR(register)"\n\t" \ - "nop" \ - : : "r" (value)); - -static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; - -/* Function for careful CP0 interrupt mask access */ -static inline void modify_cp0_intmask(unsigned clr_mask_in, unsigned set_mask_in) -{ - unsigned long status; - unsigned clr_mask; - unsigned set_mask; - - /* do the low 8 bits first */ - clr_mask = 0xff & clr_mask_in; - set_mask = 0xff & set_mask_in; - status = read_c0_status(); - status &= ~((clr_mask & 0xFF) << 8); - status |= (set_mask & 0xFF) << 8 | 0x0000FF00; - write_c0_status(status); - - /* do the high 8 bits */ - clr_mask = 0xff & (clr_mask_in >> 8); - set_mask = 0xff & (set_mask_in >> 8); - status = read_32bit_cp0_set1_register(CP0_S1_INTCONTROL); - status &= ~((clr_mask & 0xFF) << 8); - status |= (set_mask & 0xFF) << 8; - write_32bit_cp0_set1_register(CP0_S1_INTCONTROL, status); -} - -static inline void mask_irq(unsigned int irq) -{ - modify_cp0_intmask(irq, 0); -} - -static inline void unmask_irq(unsigned int irq) -{ - modify_cp0_intmask(0, irq); -} - -static void enable_rm9000_irq(unsigned int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - unmask_irq(1 << (irq-1)); - spin_unlock_irqrestore(&irq_lock, flags); -} - -static unsigned int startup_rm9000_irq(unsigned int irq) -{ - enable_rm9000_irq(irq); - - return 0; /* never anything pending */ -} - -static void disable_rm9000_irq(unsigned int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - mask_irq(1 << (irq-1)); - spin_unlock_irqrestore(&irq_lock, flags); -} - -#define shutdown_rm9000_irq disable_rm9000_irq - -static void mask_and_ack_rm9000_irq(unsigned int irq) -{ - mask_irq(1 << (irq-1)); -} - -static void end_rm9000_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - unmask_irq(1 << (irq-1)); -} - -static struct hw_interrupt_type rm9000_hpcdma_irq_type = { - "RM9000", - startup_rm9000_irq, - shutdown_rm9000_irq, - enable_rm9000_irq, - disable_rm9000_irq, - mask_and_ack_rm9000_irq, - end_rm9000_irq, - NULL -}; +#define HYPERTRANSPORT_INTA 0x78 /* INTA# */ +#define HYPERTRANSPORT_INTB 0x79 /* INTB# */ +#define HYPERTRANSPORT_INTC 0x7a /* INTC# */ +#define HYPERTRANSPORT_INTD 0x7b /* INTD# */ extern asmlinkage void titan_handle_int(void); extern void jaguar_mailbox_irq(struct pt_regs *); /* - * Handle hypertransport & SMP interrupts. The interrupt lines are scarce. For interprocessor - * interrupts, the best thing to do is to use the INTMSG register. We use the same external - * interrupt line, i.e. INTB3 and monitor another status bit + * Handle hypertransport & SMP interrupts. The interrupt lines are scarce. + * For interprocessor interrupts, the best thing to do is to use the INTMSG + * register. We use the same external interrupt line, i.e. INTB3 and monitor + * another status bit */ asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs) { - u32 status; - status = *(volatile uint32_t *)(IRQ_STATUS_REG_CPU0); + u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4); /* Ack all the bits that correspond to the interrupt sources */ if (status != 0) - *(volatile uint32_t *)(IRQ_STATUS_REG_CPU0) = IRQ_ACK_BITS; + OCD_WRITE(RM9000x2_OCD_INTP0STATUS4, IRQ_ACK_BITS); - status = *(volatile uint32_t *)(IRQ_STATUS_REG_CPU1); + status = OCD_READ(RM9000x2_OCD_INTP1STATUS4); if (status != 0) - *(volatile uint32_t *)(IRQ_STATUS_REG_CPU1) = IRQ_ACK_BITS; + OCD_WRITE(RM9000x2_OCD_INTP1STATUS4, IRQ_ACK_BITS); -#ifdef CONFIG_SMP - if (status == 0x2) { - /* This is an SMP IPI sent from one core to another */ - jaguar_mailbox_irq(regs); - goto done; - } -#endif - #ifdef CONFIG_HT_LEVEL_TRIGGER - /* - * Level Trigger Mode only. Send the HT EOI message back to the source. - */ - switch (status) { - case 0x1000000: - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTA; - break; - case 0x2000000: - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTB; - break; - case 0x4000000: - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTC; - break; - case 0x8000000: - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTD; - break; - case 0x0000001: - /* PLX */ - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = 0x20; - *(volatile uint32_t *)(IRQ_CLEAR_REG) = IRQ_ACK_BITS; - break; - case 0xf000000: - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTA; - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTB; - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTC; - *(volatile uint32_t *)(HYPERTRANSPORT_EOI) = HYPERTRANSPORT_INTD; - break; - } + /* + * Level Trigger Mode only. Send the HT EOI message back to the source. + */ + switch (status) { + case 0x1000000: + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA); + break; + case 0x2000000: + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB); + break; + case 0x4000000: + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC); + break; + case 0x8000000: + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD); + break; + case 0x0000001: + /* PLX */ + OCD_WRITE(RM9000x2_OCD_HTEOI, 0x20); + OCD_WRITE(IRQ_CLEAR_REG, IRQ_ACK_BITS); + break; + case 0xf000000: + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA); + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB); + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC); + OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD); + break; + } #endif /* CONFIG_HT_LEVEL_TRIGGER */ -done: - if (status != 0x2) - /* Not for SMP */ - do_IRQ(irq, regs); + do_IRQ(irq, regs); } +#ifdef CONFIG_KGDB +extern void init_second_port(void); +extern void breakpoint(void); +extern void set_debug_traps(void); +#endif + /* * Initialize the next level interrupt handler */ void __init init_IRQ(void) { - int i; - - clear_c0_status(ST0_IM | ST0_BEV); - __cli(); + clear_c0_status(ST0_IM); set_except_vector(0, titan_handle_int); init_generic_irq(); + mips_cpu_irq_init(0); + rm7k_cpu_irq_init(8); + +#ifdef CONFIG_KGDB + /* At this point, initialize the second serial port */ + init_second_port(); + printk("Start kgdb ... \n"); + set_debug_traps(); + breakpoint(); +#endif - for (i = 0; i < 13; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - irq_desc[i].handler = &rm9000_hpcdma_irq_type; - } +#ifdef CONFIG_GDB_CONSOLE + register_gdb_console(); +#endif } +#ifdef CONFIG_KGDB +/* + * The 16550 DUART has two ports, but is allocated one IRQ + * for the serial console. Hence, a generic framework for + * serial IRQ routing in place. Currently, just calls the + * do_IRQ fuction. But, going in the future, need to check + * DUART registers for channel A and B, then decide the + * appropriate action + */ +asmlinkage void yosemite_kgdb_irq(int irq, struct pt_regs *regs) +{ + do_IRQ(irq, regs); +} +#endif