diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 61 |
1 files changed, 32 insertions, 29 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 33bff8fec7d..3db2c386546 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -114,6 +114,7 @@ cio_tpi(void) struct tpi_info *tpi_info; struct subchannel *sch; struct irb *irb; + int irq_context; tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; if (tpi (NULL) != 1) @@ -126,7 +127,9 @@ cio_tpi(void) sch = (struct subchannel *)(unsigned long)tpi_info->intparm; if (!sch) return 1; - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); irq_enter (); spin_lock(sch->lock); memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); @@ -134,7 +137,8 @@ cio_tpi(void) sch->driver->irq(sch); spin_unlock(sch->lock); irq_exit (); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); return 1; } @@ -153,7 +157,7 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) CIO_MSG_EVENT(2, "cio_start: 'not oper' status for " "subchannel 0.%x.%04x!\n", sch->schid.ssid, sch->schid.sch_no); - sprintf(dbf_text, "no%s", sch->dev.bus_id); + sprintf(dbf_text, "no%s", dev_name(&sch->dev)); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); @@ -171,9 +175,10 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ union orb *orb; CIO_TRACE_EVENT(4, "stIO"); - CIO_TRACE_EVENT(4, sch->dev.bus_id); + CIO_TRACE_EVENT(4, dev_name(&sch->dev)); orb = &to_io_private(sch)->orb; + memset(orb, 0, sizeof(union orb)); /* sch is always under 2G. */ orb->cmd.intparm = (u32)(addr_t)sch; orb->cmd.fmt = 1; @@ -208,8 +213,10 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ case 1: /* status pending */ case 2: /* busy */ return -EBUSY; - default: /* device/path not operational */ + case 3: /* device/path not operational */ return cio_start_handle_notoper(sch, lpm); + default: + return ccode; } } @@ -229,7 +236,7 @@ cio_resume (struct subchannel *sch) int ccode; CIO_TRACE_EVENT (4, "resIO"); - CIO_TRACE_EVENT (4, sch->dev.bus_id); + CIO_TRACE_EVENT(4, dev_name(&sch->dev)); ccode = rsch (sch->schid); @@ -266,7 +273,7 @@ cio_halt(struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "haltIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Halt subchannel" and process condition code @@ -301,7 +308,7 @@ cio_clear(struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "clearIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Clear subchannel" and process condition code @@ -337,7 +344,7 @@ cio_cancel (struct subchannel *sch) return -ENODEV; CIO_TRACE_EVENT (2, "cancelIO"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); @@ -401,7 +408,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) int ret; CIO_TRACE_EVENT (2, "ensch"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return -EINVAL; @@ -451,7 +458,7 @@ int cio_disable_subchannel(struct subchannel *sch) int ret; CIO_TRACE_EVENT (2, "dissch"); - CIO_TRACE_EVENT (2, sch->dev.bus_id); + CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return 0; @@ -568,8 +575,10 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) } mutex_init(&sch->reg_mutex); /* Set a name for the subchannel */ - snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, - schid.sch_no); + if (cio_is_console(schid)) + sch->dev.init_name = cio_get_console_sch_name(schid); + else + dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no); /* * The first subchannel that is not-operational (ccode==3) @@ -674,6 +683,7 @@ do_IRQ (struct pt_regs *regs) #ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; +static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; @@ -824,6 +834,12 @@ cio_get_console_subchannel(void) return &console_subchannel; } +const char *cio_get_console_sch_name(struct subchannel_id schid) +{ + snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no); + return (const char *)console_sch_name; +} + #endif static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) @@ -843,19 +859,6 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) return -EBUSY; /* uhm... */ } -/* we can't use the normal udelay here, since it enables external interrupts */ - -static void udelay_reset(unsigned long usecs) -{ - uint64_t start_cc, end_cc; - - asm volatile ("STCK %0" : "=m" (start_cc)); - do { - cpu_relax(); - asm volatile ("STCK %0" : "=m" (end_cc)); - } while (((end_cc - start_cc)/4096) < usecs); -} - static int __clear_io_subchannel_easy(struct subchannel_id schid) { @@ -871,7 +874,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid) if (schid_equal(&ti.schid, &schid)) return 0; } - udelay_reset(100); + udelay_simple(100); } return -EBUSY; } @@ -879,7 +882,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid) static void __clear_chsc_subchannel_easy(void) { /* It seems we can only wait for a bit here :/ */ - udelay_reset(100); + udelay_simple(100); } static int pgm_check_occured; @@ -889,7 +892,7 @@ static void cio_reset_pgm_check_handler(void) pgm_check_occured = 1; } -static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) +static int stsch_reset(struct subchannel_id schid, struct schib *addr) { int rc; |