[PATCH] uml: add and use generic hw_controller_type->release
authorPaolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Wed, 22 Jun 2005 00:16:19 +0000 (17:16 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 22 Jun 2005 02:07:32 +0000 (19:07 -0700)
With Chris Wedgwood <cw@f00f.org>

Currently UML must explicitly call the UML-specific
free_irq_by_irq_and_dev() for each free_irq call it's done.

This is needed because ->shutdown and/or ->disable are only called when the
last "action" for that irq is removed.

Instead, for UML shared IRQs (UML IRQs are very often, if not always,
shared), for each dev_id some setup is done, which must be cleared on the
release of that fd.  For instance, for each open console a new instance
(i.e.  new dev_id) of the same IRQ is requested().

Exactly, a fd is stored in an array (pollfds), which is after read by a
host thread and passed to poll().  Each event registered by poll() triggers
an interrupt.  So, for each free_irq() we must remove the corresponding
host fd from the table, which we do via this -release() method.

In this patch we add an appropriate hook for this, and remove all uses of
it by pointing the hook to the said procedure; this is safe to do since the
said procedure.

Also some cosmetic improvements are included.

This is heavily based on some work by Chris Wedgwood, which however didn't
get the patch merged for something I'd call a "misunderstanding" (the need
for this patch wasn't cleanly explained, thus adding the generic hook was
felt as undesirable).

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
CC: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/um/drivers/line.c
arch/um/drivers/net_kern.c
arch/um/drivers/port_kern.c
arch/um/drivers/xterm_kern.c
arch/um/kernel/irq.c
arch/um/kernel/irq_user.c
include/linux/irq.h
kernel/irq/manage.c

index 025d3be8aca4ae522e40b6aaa2a8623834805243..562f864254ba43bc009e86be6e529865542b803e 100644 (file)
@@ -406,14 +406,12 @@ void line_disable(struct tty_struct *tty, int current_irq)
        if(line->driver->read_irq == current_irq)
                free_irq_later(line->driver->read_irq, tty);
        else {
-               free_irq_by_irq_and_dev(line->driver->read_irq, tty);
                free_irq(line->driver->read_irq, tty);
        }
 
        if(line->driver->write_irq == current_irq)
                free_irq_later(line->driver->write_irq, tty);
        else {
-               free_irq_by_irq_and_dev(line->driver->write_irq, tty);
                free_irq(line->driver->write_irq, tty);
        }
 
index 4eeaf88c1e97ba3bac425ff55b5cc904b4ee6d29..5388a7428691a2c4c12791b0e5370cd0b31685ba 100644 (file)
@@ -146,7 +146,6 @@ static int uml_net_close(struct net_device *dev)
        netif_stop_queue(dev);
        spin_lock(&lp->lock);
 
-       free_irq_by_irq_and_dev(dev->irq, dev);
        free_irq(dev->irq, dev);
        if(lp->close != NULL)
                (*lp->close)(lp->fd, &lp->user);
index b5ee07472f79bb266822383c4c57c14a21481f7b..c41efd207fcc23b33cf35b09edd94d1c841893c8 100644 (file)
@@ -257,7 +257,6 @@ int port_wait(void *data)
                 * connection.  Then we loop here throwing out failed 
                 * connections until a good one is found.
                 */
-               free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
                free_irq(TELNETD_IRQ, conn);
 
                if(conn->fd >= 0) break;
index a4fdf3584ad2c455e6165de1f88e5cc9a75ce62b..d269a80f4b0c665b70ef6f32422a53474efcb7af 100644 (file)
@@ -69,7 +69,6 @@ int xterm_fd(int socket, int *pid_out)
         * isn't set) this will hang... */
        wait_for_completion(&data->ready);
 
-       free_irq_by_irq_and_dev(XTERM_IRQ, data);
        free_irq(XTERM_IRQ, data);
 
        ret = data->new_fd;
index d44fb52825479fb8c00f67360c547c37473e1877..9f18061ef4c98d16915f7f040709340ed6740ad2 100644 (file)
@@ -124,14 +124,16 @@ void irq_unlock(unsigned long flags)
        spin_unlock_irqrestore(&irq_spinlock, flags);
 }
 
-/*  presently hw_interrupt_type must define (startup || enable) &&
- *  disable && end */
+/* hw_interrupt_type must define (startup || enable) &&
+ * (shutdown || disable) && end */
 static void dummy(unsigned int irq)
 {
 }
 
-static struct hw_interrupt_type SIGIO_irq_type = {
+/* This is used for everything else than the timer. */
+static struct hw_interrupt_type normal_irq_type = {
        .typename = "SIGIO",
+       .release = free_irq_by_irq_and_dev,
        .disable = dummy,
        .enable = dummy,
        .ack = dummy,
@@ -140,6 +142,7 @@ static struct hw_interrupt_type SIGIO_irq_type = {
 
 static struct hw_interrupt_type SIGVTALRM_irq_type = {
        .typename = "SIGVTALRM",
+       .release = free_irq_by_irq_and_dev,
        .shutdown = dummy, /* never called */
        .disable = dummy,
        .enable = dummy,
@@ -160,7 +163,7 @@ void __init init_IRQ(void)
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = NULL;
                irq_desc[i].depth = 1;
-               irq_desc[i].handler = &SIGIO_irq_type;
+               irq_desc[i].handler = &normal_irq_type;
                enable_irq(i);
        }
 }
index b3074cbaa479ac3de6c42242006d8e5c1f33cb42..c3ccaf24f3e0722cc4e3cc1a9ab8458fd8f41fdf 100644 (file)
@@ -85,8 +85,6 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
                                next = irq_fd->next;
                                if(irq_fd->freed){
                                        free_irq(irq_fd->irq, irq_fd->id);
-                                       free_irq_by_irq_and_dev(irq_fd->irq,
-                                                               irq_fd->id);
                                }
                        }
                }
index c3ff4d1016675fb8d8309b03e090f603bd1ee69e..b68ad80e2464d020c50554ac362bfdcd1dbf50bc 100644 (file)
@@ -47,6 +47,7 @@ struct hw_interrupt_type {
        void (*ack)(unsigned int irq);
        void (*end)(unsigned int irq);
        void (*set_affinity)(unsigned int irq, cpumask_t dest);
+       void (*release)(unsigned int irq, void *dev_id);
 };
 
 typedef struct hw_interrupt_type  hw_irq_controller;
index 5202e4c4a5b606e2408dafd1e48904548bc44e83..5fde8177eedf8c331eae4bc245bee449f63d6d7c 100644 (file)
@@ -255,6 +255,10 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Found it - now remove it from the list of entries */
                        *pp = action->next;
+
+                       if (desc->handler->release)
+                               desc->handler->release(irq, dev_id);
+
                        if (!desc->action) {
                                desc->status |= IRQ_DISABLED;
                                if (desc->handler->shutdown)