|
@@ -656,51 +656,34 @@ static struct io_subchannel_private console_priv;
|
|
|
static int console_subchannel_in_use;
|
|
|
|
|
|
/*
|
|
|
- * Use cio_tpi to get a pending interrupt and call the interrupt handler.
|
|
|
- * Return non-zero if an interrupt was processed, zero otherwise.
|
|
|
+ * Use cio_tsch to update the subchannel status and call the interrupt handler
|
|
|
+ * if status had been pending. Called with the console_subchannel lock.
|
|
|
*/
|
|
|
-static int cio_tpi(void)
|
|
|
+static void cio_tsch(struct subchannel *sch)
|
|
|
{
|
|
|
- struct tpi_info *tpi_info;
|
|
|
- struct subchannel *sch;
|
|
|
struct irb *irb;
|
|
|
int irq_context;
|
|
|
|
|
|
- tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
|
|
|
- if (tpi(NULL) != 1)
|
|
|
- return 0;
|
|
|
- kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
|
|
|
- if (tpi_info->adapter_IO) {
|
|
|
- do_adapter_IO(tpi_info->isc);
|
|
|
- return 1;
|
|
|
- }
|
|
|
irb = (struct irb *)&S390_lowcore.irb;
|
|
|
/* Store interrupt response block to lowcore. */
|
|
|
- if (tsch(tpi_info->schid, irb) != 0) {
|
|
|
+ if (tsch(sch->schid, irb) != 0)
|
|
|
/* Not status pending or not operational. */
|
|
|
- kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
|
|
|
- return 1;
|
|
|
- }
|
|
|
- sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
|
|
|
- if (!sch) {
|
|
|
- kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
|
|
|
- return 1;
|
|
|
- }
|
|
|
+ return;
|
|
|
+ memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
|
|
|
+ /* Call interrupt handler with updated status. */
|
|
|
irq_context = in_interrupt();
|
|
|
- if (!irq_context)
|
|
|
+ if (!irq_context) {
|
|
|
local_bh_disable();
|
|
|
- irq_enter();
|
|
|
- spin_lock(sch->lock);
|
|
|
- memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
|
|
|
+ irq_enter();
|
|
|
+ }
|
|
|
if (sch->driver && sch->driver->irq)
|
|
|
sch->driver->irq(sch);
|
|
|
else
|
|
|
kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
|
|
|
- spin_unlock(sch->lock);
|
|
|
- irq_exit();
|
|
|
- if (!irq_context)
|
|
|
+ if (!irq_context) {
|
|
|
+ irq_exit();
|
|
|
_local_bh_enable();
|
|
|
- return 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void *cio_get_console_priv(void)
|
|
@@ -712,34 +695,16 @@ void *cio_get_console_priv(void)
|
|
|
* busy wait for the next interrupt on the console
|
|
|
*/
|
|
|
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)));
|
|
|
-
|
|
|
- /*
|
|
|
- * before entering the spinlock we may already have
|
|
|
- * processed the interrupt on a different CPU...
|
|
|
- */
|
|
|
if (!console_subchannel_in_use)
|
|
|
return;
|
|
|
|
|
|
- /* disable all but the console isc */
|
|
|
- __ctl_store (save_cr6, 6, 6);
|
|
|
- cr6 = 1UL << (31 - CONSOLE_ISC);
|
|
|
- __ctl_load (cr6, 6, 6);
|
|
|
-
|
|
|
- do {
|
|
|
- spin_unlock(console_subchannel.lock);
|
|
|
- if (!cio_tpi())
|
|
|
- cpu_relax();
|
|
|
- spin_lock(console_subchannel.lock);
|
|
|
- } while (console_subchannel.schib.scsw.cmd.actl != 0);
|
|
|
- /*
|
|
|
- * restore previous isc value
|
|
|
- */
|
|
|
- __ctl_load (save_cr6, 6, 6);
|
|
|
+ while (1) {
|
|
|
+ cio_tsch(&console_subchannel);
|
|
|
+ if (console_subchannel.schib.scsw.cmd.actl == 0)
|
|
|
+ break;
|
|
|
+ udelay_simple(100);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int
|