[S390] cio: ensure single load of irq handler pointer
[linux-2.6-block.git] / drivers / s390 / cio / cio.c
index 8a8df7552969d15ad0d2532b4cf94aef3bdf3f89..2aebb9823044765427ceb806118b921276b94dbb 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/isc.h>
 #include <asm/cpu.h>
 #include <asm/fcx.h>
+#include <asm/nmi.h>
+#include <asm/crw.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
@@ -38,7 +40,6 @@
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
-#include "../s390mach.h"
 
 debug_info_t *cio_debug_msg_id;
 debug_info_t *cio_debug_trace_id;
@@ -379,7 +380,7 @@ int cio_commit_config(struct subchannel *sch)
                if (ccode < 0) /* -EIO if msch gets a program check. */
                        return ccode;
                switch (ccode) {
-               case 0: /* successfull */
+               case 0: /* successful */
                        if (stsch(sch->schid, &schib) ||
                            !css_sch_is_valid(&schib))
                                return -ENODEV;
@@ -471,6 +472,7 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
 int cio_disable_subchannel(struct subchannel *sch)
 {
        char dbf_txt[15];
+       int retry;
        int ret;
 
        CIO_TRACE_EVENT (2, "dissch");
@@ -481,16 +483,17 @@ int cio_disable_subchannel(struct subchannel *sch)
        if (cio_update_schib(sch))
                return -ENODEV;
 
-       if (scsw_actl(&sch->schib.scsw) != 0)
-               /*
-                * the disable function must not be called while there are
-                *  requests pending for completion !
-                */
-               return -EBUSY;
-
        sch->config.ena = 0;
-       ret = cio_commit_config(sch);
 
+       for (retry = 0; retry < 3; retry++) {
+               ret = cio_commit_config(sch);
+               if (ret == -EBUSY) {
+                       struct irb irb;
+                       if (tsch(sch->schid, &irb) != 0)
+                               break;
+               } else
+                       break;
+       }
        sprintf (dbf_txt, "ret:%d", ret);
        CIO_TRACE_EVENT (2, dbf_txt);
        return ret;
@@ -632,8 +635,8 @@ do_IRQ (struct pt_regs *regs)
        struct pt_regs *old_regs;
 
        old_regs = set_irq_regs(regs);
-       irq_enter();
        s390_idle_check();
+       irq_enter();
        if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
                /* Serve timer interrupts first. */
                clock_comparator_work();