blob: bbf94bf2921ed144a6d70990152c1264b8361b33 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
6 */
7
8#include "linux/config.h"
9#include "linux/kernel.h"
10#include "linux/module.h"
11#include "linux/smp.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "linux/kernel_stat.h"
13#include "linux/interrupt.h"
14#include "linux/random.h"
15#include "linux/slab.h"
16#include "linux/file.h"
17#include "linux/proc_fs.h"
18#include "linux/init.h"
19#include "linux/seq_file.h"
20#include "linux/profile.h"
21#include "linux/hardirq.h"
22#include "asm/irq.h"
23#include "asm/hw_irq.h"
24#include "asm/atomic.h"
25#include "asm/signal.h"
26#include "asm/system.h"
27#include "asm/errno.h"
28#include "asm/uaccess.h"
29#include "user_util.h"
30#include "kern_util.h"
31#include "irq_user.h"
32#include "irq_kern.h"
Jeff Dike75e55842005-09-03 15:57:45 -070033#include "os.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35/*
36 * Generic, controller-independent functions:
37 */
38
39int show_interrupts(struct seq_file *p, void *v)
40{
41 int i = *(loff_t *) v, j;
42 struct irqaction * action;
43 unsigned long flags;
44
45 if (i == 0) {
46 seq_printf(p, " ");
47 for_each_online_cpu(j)
48 seq_printf(p, "CPU%d ",j);
49 seq_putc(p, '\n');
50 }
51
52 if (i < NR_IRQS) {
53 spin_lock_irqsave(&irq_desc[i].lock, flags);
54 action = irq_desc[i].action;
55 if (!action)
56 goto skip;
57 seq_printf(p, "%3d: ",i);
58#ifndef CONFIG_SMP
59 seq_printf(p, "%10u ", kstat_irqs(i));
60#else
61 for_each_online_cpu(j)
62 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
63#endif
64 seq_printf(p, " %14s", irq_desc[i].handler->typename);
65 seq_printf(p, " %s", action->name);
66
67 for (action=action->next; action; action = action->next)
68 seq_printf(p, ", %s", action->name);
69
70 seq_putc(p, '\n');
71skip:
72 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
73 } else if (i == NR_IRQS) {
74 seq_putc(p, '\n');
75 }
76
77 return 0;
78}
79
80/*
81 * do_IRQ handles all normal device IRQ's (the special
82 * SMP cross-CPU interrupts have their own specific
83 * handlers).
84 */
85unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
86{
87 irq_enter();
88 __do_IRQ(irq, (struct pt_regs *) regs);
89 irq_exit();
90 return 1;
91}
92
93int um_request_irq(unsigned int irq, int fd, int type,
94 irqreturn_t (*handler)(int, void *, struct pt_regs *),
95 unsigned long irqflags, const char * devname,
96 void *dev_id)
97{
98 int err;
99
100 err = request_irq(irq, handler, irqflags, devname, dev_id);
101 if(err)
102 return(err);
103
104 if(fd != -1)
105 err = activate_fd(irq, fd, type, dev_id);
106 return(err);
107}
108EXPORT_SYMBOL(um_request_irq);
109EXPORT_SYMBOL(reactivate_fd);
110
111static DEFINE_SPINLOCK(irq_spinlock);
112
113unsigned long irq_lock(void)
114{
115 unsigned long flags;
116
117 spin_lock_irqsave(&irq_spinlock, flags);
118 return(flags);
119}
120
121void irq_unlock(unsigned long flags)
122{
123 spin_unlock_irqrestore(&irq_spinlock, flags);
124}
125
Paolo 'Blaisorblade' Giarrussodbce7062005-06-21 17:16:19 -0700126/* hw_interrupt_type must define (startup || enable) &&
127 * (shutdown || disable) && end */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128static void dummy(unsigned int irq)
129{
130}
131
Paolo 'Blaisorblade' Giarrussodbce7062005-06-21 17:16:19 -0700132/* This is used for everything else than the timer. */
133static struct hw_interrupt_type normal_irq_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 .typename = "SIGIO",
Paolo 'Blaisorblade' Giarrussodbce7062005-06-21 17:16:19 -0700135 .release = free_irq_by_irq_and_dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 .disable = dummy,
137 .enable = dummy,
138 .ack = dummy,
139 .end = dummy
140};
141
142static struct hw_interrupt_type SIGVTALRM_irq_type = {
143 .typename = "SIGVTALRM",
Paolo 'Blaisorblade' Giarrussodbce7062005-06-21 17:16:19 -0700144 .release = free_irq_by_irq_and_dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 .shutdown = dummy, /* never called */
146 .disable = dummy,
147 .enable = dummy,
148 .ack = dummy,
149 .end = dummy
150};
151
152void __init init_IRQ(void)
153{
154 int i;
155
156 irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
157 irq_desc[TIMER_IRQ].action = NULL;
158 irq_desc[TIMER_IRQ].depth = 1;
159 irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
160 enable_irq(TIMER_IRQ);
161 for(i=1;i<NR_IRQS;i++){
162 irq_desc[i].status = IRQ_DISABLED;
163 irq_desc[i].action = NULL;
164 irq_desc[i].depth = 1;
Paolo 'Blaisorblade' Giarrussodbce7062005-06-21 17:16:19 -0700165 irq_desc[i].handler = &normal_irq_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 enable_irq(i);
167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
Jeff Dike75e55842005-09-03 15:57:45 -0700170int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
171 struct pt_regs *))
172{
173 int fds[2], err;
174
175 err = os_pipe(fds, 1, 1);
176 if(err){
177 printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
178 goto out;
179 }
180
181 err = um_request_irq(irq, fds[0], IRQ_READ, handler,
182 SA_INTERRUPT | SA_SAMPLE_RANDOM, name,
183 (void *) (long) fds[0]);
184 if(err){
185 printk("init_aio_irq - : um_request_irq failed, err = %d\n",
186 err);
187 goto out_close;
188 }
189
190 err = fds[1];
191 goto out;
192
193 out_close:
194 os_close_file(fds[0]);
195 os_close_file(fds[1]);
196 out:
197 return(err);
198}