]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/cio/cio.c
Merge branch 'for-2.6.26' of git://git.farnsworth.org/dale/linux-2.6-mv643xx_eth...
[linux-2.6-omap-h63xx.git] / drivers / s390 / cio / cio.c
index cd5475b82420d375e7e557027190530bd7a1a749..08a578161306e1088f4fe6786ea85b518cfd7a12 100644 (file)
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/chpid.h>
-#include "airq.h"
+#include <asm/airq.h>
+#include <asm/cpu.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "io_sch.h"
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
@@ -63,17 +65,17 @@ __setup ("cio_msg=", cio_setup);
  */
 static int __init cio_debug_init(void)
 {
-       cio_debug_msg_id = debug_register("cio_msg", 16, 4, 16 * sizeof(long));
+       cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
        if (!cio_debug_msg_id)
                goto out_unregister;
        debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
        debug_set_level(cio_debug_msg_id, 2);
-       cio_debug_trace_id = debug_register("cio_trace", 16, 4, 16);
+       cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
        if (!cio_debug_trace_id)
                goto out_unregister;
        debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
        debug_set_level(cio_debug_trace_id, 2);
-       cio_debug_crw_id = debug_register("cio_crw", 16, 4, 16 * sizeof(long));
+       cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
        if (!cio_debug_crw_id)
                goto out_unregister;
        debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
@@ -182,33 +184,35 @@ cio_start_key (struct subchannel *sch,    /* subchannel structure */
 {
        char dbf_txt[15];
        int ccode;
+       struct orb *orb;
 
-       CIO_TRACE_EVENT (4, "stIO");
-       CIO_TRACE_EVENT (4, sch->dev.bus_id);
+       CIO_TRACE_EVENT(4, "stIO");
+       CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
+       orb = &to_io_private(sch)->orb;
        /* sch is always under 2G. */
-       sch->orb.intparm = (__u32)(unsigned long)sch;
-       sch->orb.fmt = 1;
+       orb->intparm = (u32)(addr_t)sch;
+       orb->fmt = 1;
 
-       sch->orb.pfch = sch->options.prefetch == 0;
-       sch->orb.spnd = sch->options.suspend;
-       sch->orb.ssic = sch->options.suspend && sch->options.inter;
-       sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+       orb->pfch = sch->options.prefetch == 0;
+       orb->spnd = sch->options.suspend;
+       orb->ssic = sch->options.suspend && sch->options.inter;
+       orb->lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
        /*
         * for 64 bit we always support 64 bit IDAWs with 4k page size only
         */
-       sch->orb.c64 = 1;
-       sch->orb.i2k = 0;
+       orb->c64 = 1;
+       orb->i2k = 0;
 #endif
-       sch->orb.key = key >> 4;
+       orb->key = key >> 4;
        /* issue "Start Subchannel" */
-       sch->orb.cpa = (__u32) __pa (cpa);
-       ccode = ssch (sch->schid, &sch->orb);
+       orb->cpa = (__u32) __pa(cpa);
+       ccode = ssch(sch->schid, orb);
 
        /* process condition code */
-       sprintf (dbf_txt, "ccode:%d", ccode);
-       CIO_TRACE_EVENT (4, dbf_txt);
+       sprintf(dbf_txt, "ccode:%d", ccode);
+       CIO_TRACE_EVENT(4, dbf_txt);
 
        switch (ccode) {
        case 0:
@@ -403,8 +407,7 @@ cio_modify (struct subchannel *sch)
 /*
  * Enable subchannel.
  */
-int
-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
 {
        char dbf_txt[15];
        int ccode;
@@ -422,8 +425,8 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
 
        for (retry = 5, ret = 0; retry > 0; retry--) {
                sch->schib.pmcw.ena = 1;
-               sch->schib.pmcw.isc = isc;
-               sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+               sch->schib.pmcw.isc = sch->isc;
+               sch->schib.pmcw.intparm = intparm;
                ret = cio_modify(sch);
                if (ret == -ENODEV)
                        break;
@@ -574,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        }
 
        /* Initialization for io subchannels. */
-       if (!sch->schib.pmcw.dnv) {
-               /* io subchannel but device number is invalid. */
+       if (!css_sch_is_valid(&sch->schib)) {
                err = -ENODEV;
                goto out;
        }
+
        /* Devno is valid. */
        if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
                /*
@@ -596,6 +599,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        else
                sch->opm = chp_get_sch_opm(sch);
        sch->lpm = sch->schib.pmcw.pam & sch->opm;
+       sch->isc = 3;
 
        CIO_DEBUG(KERN_INFO, 0,
                  "Detected device %04x on subchannel 0.%x.%04X"
@@ -606,13 +610,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
 
        /*
         * We now have to initially ...
-        *  ... set "interruption subclass"
         *  ... enable "concurrent sense"
         *  ... enable "multipath mode" if more than one
         *        CHPID is available. This is done regardless
         *        whether multiple paths are available for us.
         */
-       sch->schib.pmcw.isc = 3;        /* could be smth. else */
        sch->schib.pmcw.csense = 1;     /* concurrent sense */
        sch->schib.pmcw.ena = 0;
        if ((sch->lpm & (sch->lpm - 1)) != 0)
@@ -646,13 +648,10 @@ do_IRQ (struct pt_regs *regs)
 
        old_regs = set_irq_regs(regs);
        irq_enter();
-       asm volatile ("mc 0,0");
-       if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
-               /**
-                * Make sure that the i/o interrupt did not "overtake"
-                * the last HZ timer interrupt.
-                */
-               account_ticks(S390_lowcore.int_clock);
+       s390_idle_check();
+       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
+               /* Serve timer interrupts first. */
+               clock_comparator_work();
        /*
         * Get interrupt information from lowcore
         */
@@ -669,10 +668,14 @@ do_IRQ (struct pt_regs *regs)
                        continue;
                }
                sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
-               if (sch)
-                       spin_lock(sch->lock);
+               if (!sch) {
+                       /* Clear pending interrupt condition. */
+                       tsch(tpi_info->schid, irb);
+                       continue;
+               }
+               spin_lock(sch->lock);
                /* Store interrupt response block to lowcore. */
-               if (tsch (tpi_info->schid, irb) == 0 && sch) {
+               if (tsch(tpi_info->schid, irb) == 0) {
                        /* Keep subchannel information word up to date. */
                        memcpy (&sch->schib.scsw, &irb->scsw,
                                sizeof (irb->scsw));
@@ -680,8 +683,7 @@ do_IRQ (struct pt_regs *regs)
                        if (sch->driver && sch->driver->irq)
                                sch->driver->irq(sch);
                }
-               if (sch)
-                       spin_unlock(sch->lock);
+               spin_unlock(sch->lock);
                /*
                 * Are more interrupts pending?
                 * If so, the tpi instruction will update the lowcore
@@ -696,13 +698,20 @@ do_IRQ (struct pt_regs *regs)
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+void *cio_get_console_priv(void)
+{
+       return &console_priv;
+}
+
 /*
  * busy wait for the next interrupt on the console
  */
-void
-wait_cons_dev (void)
+void wait_cons_dev(void)
+       __releases(console_subchannel.lock)
+       __acquires(console_subchannel.lock)
 {
        unsigned long cr6      __attribute__ ((aligned (8)));
        unsigned long save_cr6 __attribute__ ((aligned (8)));
@@ -736,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
 {
        if (stsch_err(schid, &console_subchannel.schib) != 0)
                return -ENXIO;
-       if (console_subchannel.schib.pmcw.dnv &&
-           console_subchannel.schib.pmcw.dev ==
-           console_devno) {
+       if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
+           console_subchannel.schib.pmcw.dnv &&
+           (console_subchannel.schib.pmcw.dev == console_devno)) {
                console_irq = schid.sch_no;
                return 1; /* found */
        }
@@ -756,6 +765,7 @@ cio_get_console_sch_no(void)
                /* VM provided us with the irq number of the console. */
                schid.sch_no = console_irq;
                if (stsch(schid, &console_subchannel.schib) != 0 ||
+                   (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
                    !console_subchannel.schib.pmcw.dnv)
                        return -1;
                console_devno = console_subchannel.schib.pmcw.dev;
@@ -800,9 +810,10 @@ cio_probe_console(void)
         * enable console I/O-interrupt subclass 7
         */
        ctl_set_bit(6, 24);
+       console_subchannel.isc = 7;
        console_subchannel.schib.pmcw.isc = 7;
        console_subchannel.schib.pmcw.intparm =
-               (__u32)(unsigned long)&console_subchannel;
+               (u32)(addr_t)&console_subchannel;
        ret = cio_modify(&console_subchannel);
        if (ret) {
                console_subchannel_in_use = 0;
@@ -1020,7 +1031,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
 
        if (stsch_reset(schid, &schib))
                return -ENXIO;
-       if (schib.pmcw.dnv &&
+       if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
            (schib.pmcw.dev == match_id->devid.devno) &&
            (schid.ssid == match_id->devid.ssid)) {
                match_id->schid = schid;
@@ -1066,6 +1077,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
                return -ENODEV;
        if (stsch(schid, &schib))
                return -ENODEV;
+       if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
+               return -ENODEV;
        if (!schib.pmcw.dnv)
                return -ENODEV;
        iplinfo->devno = schib.pmcw.dev;