X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fs390%2Fcio%2Fcio.c;h=b3a56dc5f68a2fd5144dad6d7bd6abef50369fd0;hb=572543d8b410c9734b530e811139120e36371ebd;hp=7835a714a405c90018dc8fa2aea49f415c829851;hpb=40b20c257a13c5a526ac540bc5e43d0fdf29792a;p=powerpc.git diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 7835a714a4..b3a56dc5f6 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -2,8 +2,7 @@ * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls * - * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation + * Copyright (C) IBM Corp. 1999,2006 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -123,7 +122,7 @@ cio_get_options (struct subchannel *sch) * Use tpi to get a pending interrupt, call the interrupt handler and * return a pointer to the subchannel structure. */ -static inline int +static int cio_tpi(void) { struct tpi_info *tpi_info; @@ -153,7 +152,7 @@ cio_tpi(void) return 1; } -static inline int +static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { char dbf_text[15]; @@ -586,7 +585,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) * This device must not be known to Linux. So we simply * say that there is no device and return ENODEV. */ - CIO_MSG_EVENT(0, "Blacklisted device detected " + CIO_MSG_EVENT(4, "Blacklisted device detected " "at devno %04X, subchannel set %x\n", sch->schib.pmcw.dev, sch->schid.ssid); err = -ENODEV; @@ -647,7 +646,7 @@ do_IRQ (struct pt_regs *regs) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); /* * Get interrupt information from lowcore */ @@ -833,7 +832,7 @@ cio_get_console_subchannel(void) } #endif -static inline int +static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { int retry, cc; @@ -851,7 +850,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) return -EBUSY; /* uhm... */ } -static inline int +/* 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_subchannel_easy(struct subchannel_id schid) { int retry; @@ -866,16 +878,41 @@ __clear_subchannel_easy(struct subchannel_id schid) if (schid_equal(&ti.schid, &schid)) return 0; } - udelay(100); + udelay_reset(100); } return -EBUSY; } +static int pgm_check_occured; + +static void cio_reset_pgm_check_handler(void) +{ + pgm_check_occured = 1; +} + +static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) +{ + int rc; + + pgm_check_occured = 0; + s390_base_pgm_handler_fn = cio_reset_pgm_check_handler; + rc = stsch(schid, addr); + s390_base_pgm_handler_fn = NULL; + + /* The program check handler could have changed pgm_check_occured. */ + barrier(); + + if (pgm_check_occured) + return -EIO; + else + return rc; +} + static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) { struct schib schib; - if (stsch_err(schid, &schib)) + if (stsch_reset(schid, &schib)) return -ENXIO; if (!schib.pmcw.ena) return 0; @@ -920,7 +957,7 @@ static void css_reset(void) /* Reset subchannels. */ for_each_subchannel(__shutdown_subchannel_easy, NULL); /* Reset channel paths. */ - s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; + s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler; /* Enable channel report machine checks. */ __ctl_set_bit(14, 28); /* Temporarily reenable machine checks. */ @@ -945,7 +982,7 @@ static void css_reset(void) local_mcck_disable(); /* Disable channel report machine checks. */ __ctl_clear_bit(14, 28); - s390_reset_mcck_handler = NULL; + s390_base_mcck_handler_fn = NULL; } static struct reset_call css_reset_call = { @@ -972,7 +1009,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data) struct schib schib; struct sch_match_id *match_id = data; - if (stsch_err(schid, &schib)) + if (stsch_reset(schid, &schib)) return -ENXIO; if (schib.pmcw.dnv && (schib.pmcw.dev == match_id->devid.devno) &&