diff options
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r-- | drivers/s390/cio/device.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c6767f5a58b2..2e1e9086e916 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -19,6 +19,7 @@ #include <linux/list.h> #include <linux/device.h> #include <linux/workqueue.h> +#include <linux/delay.h> #include <linux/timer.h> #include <linux/kernel_stat.h> @@ -1612,13 +1613,15 @@ static int ccw_device_console_enable(struct ccw_device *cdev, /* Now wait for the async. recognition to come to an end. */ spin_lock_irq(cdev->ccwlock); while (!dev_fsm_final_state(cdev)) - wait_cons_dev(); + ccw_device_wait_idle(cdev); + rc = -EIO; if (cdev->private->state != DEV_STATE_OFFLINE) goto out_unlock; ccw_device_online(cdev); while (!dev_fsm_final_state(cdev)) - wait_cons_dev(); + ccw_device_wait_idle(cdev); + if (cdev->private->state != DEV_STATE_ONLINE) goto out_unlock; rc = 0; @@ -1655,6 +1658,26 @@ ccw_device_probe_console(void) return &console_cdev; } +/** + * ccw_device_wait_idle() - busy wait for device to become idle + * @cdev: ccw device + * + * Poll until activity control is zero, that is, no function or data + * transfer is pending/active. + * Called with device lock being held. + */ +void ccw_device_wait_idle(struct ccw_device *cdev) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + + while (1) { + cio_tsch(sch); + if (sch->schib.scsw.cmd.actl == 0) + break; + udelay_simple(100); + } +} + static int ccw_device_pm_restore(struct device *dev); int ccw_device_force_console(void) |