1/* 2 * Copyright 2001 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * 5 * Copyright (C) 2001 Ralf Baechle 6 * 7 * This file define the irq handler for MIPS CPU interrupts. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15/* 16 * Almost all MIPS CPUs define 8 interrupt sources. They are typically 17 * level triggered (i.e., cannot be cleared from CPU; must be cleared from 18 * device). The first two are software interrupts which we don't really 19 * use or support. The last one is usually cpu timer interrupt if a counter 20 * register is present. 21 * 22 * Don't even think about using this on SMP. You have been warned. 23 * 24 * This file exports one global function: 25 * mips_cpu_irq_init(u32 irq_base); 26 */ 27#include <linux/interrupt.h> 28#include <linux/types.h> 29#include <linux/kernel.h> 30 31#include <asm/mipsregs.h> 32#include <asm/system.h> 33 34static int mips_cpu_irq_base; 35 36static inline void unmask_mips_irq(unsigned int irq) 37{ 38 clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); 39 set_c0_status(0x100 << (irq - mips_cpu_irq_base)); 40} 41 42static inline void mask_mips_irq(unsigned int irq) 43{ 44 clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); 45} 46 47static inline void mips_cpu_irq_enable(unsigned int irq) 48{ 49 unsigned long flags; 50 51 local_irq_save(flags); 52 unmask_mips_irq(irq); 53 local_irq_restore(flags); 54} 55 56static void mips_cpu_irq_disable(unsigned int irq) 57{ 58 unsigned long flags; 59 60 local_irq_save(flags); 61 mask_mips_irq(irq); 62 local_irq_restore(flags); 63} 64 65static unsigned int mips_cpu_irq_startup(unsigned int irq) 66{ 67 mips_cpu_irq_enable(irq); 68 69 return 0; 70} 71 72#define mips_cpu_irq_shutdown mips_cpu_irq_disable 73 74/* 75 * While we ack the interrupt interrupts are disabled and thus we don't need 76 * to deal with concurrency issues. Same for mips_cpu_irq_end. 77 */ 78static void mips_cpu_irq_ack(unsigned int irq) 79{ 80 /* Only necessary for soft interrupts */ 81 clear_c0_cause(1 << (irq - mips_cpu_irq_base + 8)); 82 83 mask_mips_irq(irq); 84} 85 86static void mips_cpu_irq_end(unsigned int irq) 87{ 88 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 89 unmask_mips_irq(irq); 90} 91 92static hw_irq_controller mips_cpu_irq_controller = { 93 "CPU_irq", 94 mips_cpu_irq_startup, 95 mips_cpu_irq_shutdown, 96 mips_cpu_irq_enable, 97 mips_cpu_irq_disable, 98 mips_cpu_irq_ack, 99 mips_cpu_irq_end, 100 NULL /* no affinity stuff for UP */ 101}; 102 103 104void mips_cpu_irq_init(u32 irq_base) 105{ 106 u32 i; 107 108 for (i = irq_base; i < irq_base + 8; i++) { 109 irq_desc[i].status = IRQ_DISABLED; 110 irq_desc[i].action = NULL; 111 irq_desc[i].depth = 1; 112 irq_desc[i].handler = &mips_cpu_irq_controller; 113 } 114 115 mips_cpu_irq_base = irq_base; 116} 117