3 * John W. Linville <linville@tuxdriver.com>
5 * Copied and modified from original code by Josh Huber. Original
6 * copyright notice preserved below.
9 * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
11 * See file CREDITS for list of people who contributed to this
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 * interrupts.c - just enough support for the decrementer/timer
35 #include <asm/processor.h>
41 #define PRINTF(fmt,args...) printf (fmt ,##args)
43 #define PRINTF(fmt,args...)
47 void irq_alloc_init(void);
48 long irq_alloc(long wanted);
50 /****************************************************************************/
52 unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
55 interrupt_handler_t *handler;
60 static struct irq_action irq_handlers[NR_IRQS];
62 /****************************************************************************/
64 static __inline__ unsigned long
69 asm volatile("mfmsr %0" : "=r" (msr) :);
73 static __inline__ void
74 set_msr(unsigned long msr)
76 asm volatile("mtmsr %0" : : "r" (msr));
79 static __inline__ unsigned long
84 asm volatile("mfdec %0" : "=r" (val) :);
89 static __inline__ void
90 set_dec(unsigned long val)
92 asm volatile("mtdec %0" : : "r" (val));
97 enable_interrupts(void)
99 set_msr (get_msr() | MSR_EE);
102 /* returns flag if MSR_EE was set before */
104 disable_interrupts(void)
109 set_msr (msr & ~MSR_EE);
110 return ((msr & MSR_EE) != 0);
113 /****************************************************************************/
115 int interrupt_init (void)
117 extern void new_reset(void);
118 extern void new_reset_end(void);
120 puts("interrupt_init: setting decrementer_count\n");
122 decrementer_count = get_tbclk() / CFG_HZ;
125 puts("interrupt_init: setting actual decremter\n");
127 set_dec (get_tbclk() / CFG_HZ);
130 puts("interrupt_init: clearing external interrupt table\n");
132 /* clear external interrupt table here */
133 memset(irq_handlers, 0, sizeof(irq_handlers));
136 puts("interrupt_init: initializing interrupt controller\n");
141 puts("Copying reset trampoline\n");
143 /* WARNING: Assmues that the first megabyte is CACHEINHIBIT! */
144 memcpy((void *)0x100, new_reset, new_reset_end - new_reset);
147 PRINTF("interrupt_init: enabling interrupts (msr = %08x)\n",
150 set_msr (get_msr() | MSR_EE);
153 PRINTF("interrupt_init: done. (msr = %08x)\n", get_msr());
158 /****************************************************************************/
161 * Handle external interrupts
164 external_interrupt(struct pt_regs *regs)
166 extern int i8259_irq(void);
170 irq = i8259_irq(); /*i8259_get_irq(regs); */
171 /* printf("irq = %d, handler at %p ack=%d\n", irq, irq_handlers[irq].handler, *(volatile unsigned char *)0xFEF00000); */
172 i8259_mask_and_ack(irq);
174 if (irq_handlers[irq].handler != NULL)
175 (*irq_handlers[irq].handler)(irq_handlers[irq].arg);
177 PRINTF ("\nBogus External Interrupt IRQ %d\n", irq);
179 * turn off the bogus interrupt, otherwise it
180 * might repeat forever
185 if (unmask) i8259_unmask_irq(irq);
188 volatile ulong timestamp = 0;
191 * timer_interrupt - gets called when the decrementer overflows,
192 * with interrupts disabled.
193 * Trivial implementation - no need to be really accurate.
196 timer_interrupt(struct pt_regs *regs)
198 set_dec(decrementer_count);
202 /****************************************************************************/
211 get_timer(ulong base)
213 return (timestamp - base);
222 /****************************************************************************/
225 * Install and free a interrupt handler.
229 irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
231 if (irq < 0 || irq >= NR_IRQS) {
232 PRINTF("irq_install_handler: bad irq number %d\n", irq);
236 if (irq_handlers[irq].handler != NULL)
237 PRINTF("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
238 (ulong)handler, (ulong)irq_handlers[irq].handler);
240 irq_handlers[irq].handler = handler;
241 irq_handlers[irq].arg = arg;
243 i8259_unmask_irq(irq);
247 irq_free_handler(int irq)
249 if (irq < 0 || irq >= NR_IRQS) {
250 PRINTF("irq_free_handler: bad irq number %d\n", irq);
256 irq_handlers[irq].handler = NULL;
257 irq_handlers[irq].arg = NULL;
260 /****************************************************************************/
263 do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
265 puts("IRQ related functions are unimplemented currently.\n");