patch-2.3.14 linux/arch/m68k/amiga/amiints.c
Next file: linux/arch/m68k/amiga/cia.c
Previous file: linux/arch/m68k/Makefile
Back to the patch index
Back to the overall index
- Lines: 226
- Date:
Sun Aug 15 11:47:29 1999
- Orig file:
v2.3.13/linux/arch/m68k/amiga/amiints.c
- Orig date:
Thu Jan 7 08:41:55 1999
diff -u --recursive --new-file v2.3.13/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
@@ -19,6 +19,20 @@
* called again.
* The whole interrupt handling for CIAs is moved to cia.c
* /Roman Zippel
+ *
+ * 07/08/99: rewamp of the interrupt handling - we now have two types of
+ * interrupts, normal and fast handlers, fast handlers being
+ * marked with SA_INTERRUPT and runs with all other interrupts
+ * disabled. Normal interrupts disable their own source but
+ * run with all other interrupt sources enabled.
+ * PORTS and EXTER interrupts are always shared even if the
+ * drivers do not explicitly mark this when calling
+ * request_irq which they really should do.
+ * This is similar to the way interrupts are handled on all
+ * other architectures and makes a ton of sense besides
+ * having the advantage of making it easier to share
+ * drivers.
+ * /Jes
*/
#include <linux/types.h>
@@ -70,7 +84,7 @@
* the amiga IRQ handling routines.
*/
-__initfunc(void amiga_init_IRQ(void))
+void __init amiga_init_IRQ(void)
{
int i;
@@ -81,7 +95,7 @@
} else {
ami_irq_list[i] = new_irq_node();
ami_irq_list[i]->handler = ami_badint;
- ami_irq_list[i]->flags = IRQ_FLG_STD;
+ ami_irq_list[i]->flags = 0;
ami_irq_list[i]->dev_id = NULL;
ami_irq_list[i]->devname = NULL;
ami_irq_list[i]->next = NULL;
@@ -117,19 +131,18 @@
cur = *list;
- if (node->flags & IRQ_FLG_FAST) {
- node->flags &= ~IRQ_FLG_SLOW;
- while (cur && cur->flags & IRQ_FLG_FAST) {
- list = &cur->next;
- cur = cur->next;
- }
- } else if (node->flags & IRQ_FLG_SLOW) {
- while (cur) {
+ if (node->flags & SA_INTERRUPT) {
+ if (node->flags & SA_SHIRQ)
+ return;
+ /*
+ * There should never be more than one
+ */
+ while (cur && cur->flags & SA_INTERRUPT) {
list = &cur->next;
cur = cur->next;
}
} else {
- while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+ while (cur) {
list = &cur->next;
cur = cur->next;
}
@@ -168,13 +181,15 @@
* If the addition was successful, it returns 0.
*/
-int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int amiga_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *devname, void *dev_id)
{
irq_node_t *node;
if (irq >= AMI_IRQS) {
- printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
+ printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
+ irq, devname);
return -ENXIO;
}
@@ -190,6 +205,11 @@
return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
handler, flags, devname, dev_id);
+ /*
+ * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
+ * we could add a check here for the SA_SHIRQ flag but all drivers
+ * should be aware of sharing anyway.
+ */
if (ami_servers[irq]) {
if (!(node = new_irq_node()))
return -ENOMEM;
@@ -200,18 +220,6 @@
node->next = NULL;
amiga_insert_irq(&ami_irq_list[irq], node);
} else {
- if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) {
- if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) {
- printk("%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, ami_irq_list[irq]->devname);
- return -EBUSY;
- }
- if (!(flags & IRQ_FLG_REPLACE)) {
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, ami_irq_list[irq]->devname);
- return -EBUSY;
- }
- }
ami_irq_list[irq]->handler = handler;
ami_irq_list[irq]->flags = flags;
ami_irq_list[irq]->dev_id = dev_id;
@@ -255,7 +263,7 @@
printk("%s: removing probably wrong IRQ %d from %s\n",
__FUNCTION__, irq, ami_irq_list[irq]->devname);
ami_irq_list[irq]->handler = ami_badint;
- ami_irq_list[irq]->flags = IRQ_FLG_STD;
+ ami_irq_list[irq]->flags = 0;
ami_irq_list[irq]->dev_id = NULL;
ami_irq_list[irq]->devname = NULL;
custom.intena = ami_intena_vals[irq];
@@ -345,37 +353,58 @@
void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
{
irq_node_t *node, *slow_nodes;
- unsigned short flags;
+ unsigned short flags, intena;
kstat.irqs[0][SYS_IRQS + irq]++;
if (server->count++)
server->reentrance = 1;
- /* serve first fast and normal handlers */
- for (node = ami_irq_list[irq];
- node && (!(node->flags & IRQ_FLG_SLOW));
- node = node->next)
- node->handler(irq, node->dev_id, fp);
- custom.intreq = ami_intena_vals[irq];
+
+ intena = ami_intena_vals[irq];
+ custom.intreq = intena;
+
+ /* serve first fast handlers - there can only be one of these */
+ node = ami_irq_list[irq];
+
+ /*
+ * Timer interrupts show up like this
+ */
if (!node) {
server->count--;
return;
}
+
+ if (node && (node->flags & SA_INTERRUPT)) {
+ save_flags(flags);
+ cli();
+ node->handler(irq, node->dev_id, fp);
+ restore_flags(flags);
+
+ server->count--;
+ return;
+ }
+
+ /*
+ * Disable the interrupt source in question and reenable all
+ * other interrupts. No interrupt handler should ever touch
+ * the intena flags directly!
+ */
+ custom.intena = intena;
save_flags(flags);
- restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
- /* if slow handlers exists, serve them now */
+ sti();
+
slow_nodes = node;
for (;;) {
for (; node; node = node->next)
node->handler(irq, node->dev_id, fp);
- /* if reentrance occurred, serve slow handlers again */
- custom.intena = ami_intena_vals[irq];
+
if (!server->reentrance) {
server->count--;
- custom.intena = IF_SETCLR | ami_intena_vals[irq];
+ restore_flags(flags);
+ custom.intena = IF_SETCLR | intena;
return;
}
+
server->reentrance = 0;
- custom.intena = IF_SETCLR | ami_intena_vals[irq];
node = slow_nodes;
}
}
@@ -493,24 +522,13 @@
for (i = 0; i < AMI_STD_IRQS; i++) {
if (!(node = ami_irq_list[i]))
continue;
- if (node->flags & IRQ_FLG_STD)
- continue;
len += sprintf(buf+len, "ami %2d: %10u ", i,
kstat.irqs[0][SYS_IRQS + i]);
do {
- if (ami_servers[i]) {
- if (node->flags & IRQ_FLG_FAST)
- len += sprintf(buf+len, "F ");
- else if (node->flags & IRQ_FLG_SLOW)
- len += sprintf(buf+len, "S ");
- else
- len += sprintf(buf+len, " ");
- } else {
- if (node->flags & IRQ_FLG_LOCK)
- len += sprintf(buf+len, "L ");
- else
- len += sprintf(buf+len, " ");
- }
+ if (node->flags & SA_INTERRUPT)
+ len += sprintf(buf+len, "F ");
+ else
+ len += sprintf(buf+len, " ");
len += sprintf(buf+len, "%s\n", node->devname);
if ((node = node->next))
len += sprintf(buf+len, " ");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)