From 1e5320960510d6d6f2cbdc7ed33df9791283b7ea Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 27 Jan 2014 13:28:10 +0100 Subject: s390/cio: reorder initialization of ccw consoles Drivers for ccw consoles use ccw_device_probe_console to receive an initialized ccw device which is already enabled for interrupts. After that the device driver does the initialization of its private data. This can race with unsolicited interrupts which can happen once the device is enabled for interrupts. Split ccw_device_probe_console into ccw_device_create_console and ccw_device_enable_console and reorder the initialization of the ccw console drivers. While at it mark these functions as __init. Reviewed-by: Peter Oberparleiter Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/s390/cio') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 4283dd3cdd49..da431992fd8e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1572,11 +1572,14 @@ out: } #ifdef CONFIG_CCW_CONSOLE -static int ccw_device_console_enable(struct ccw_device *cdev, - struct subchannel *sch) +int __init ccw_device_enable_console(struct ccw_device *cdev) { + struct subchannel *sch = to_subchannel(cdev->dev.parent); int rc; + if (!cdev->drv || !cdev->handler) + return -EINVAL; + io_subchannel_init_fields(sch); rc = cio_commit_config(sch); if (rc) @@ -1609,12 +1612,11 @@ out_unlock: return rc; } -struct ccw_device *ccw_device_probe_console(struct ccw_driver *drv) +struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) { struct io_subchannel_private *io_priv; struct ccw_device *cdev; struct subchannel *sch; - int ret; sch = cio_probe_console(); if (IS_ERR(sch)) @@ -1633,17 +1635,20 @@ struct ccw_device *ccw_device_probe_console(struct ccw_driver *drv) } cdev->drv = drv; set_io_private(sch, io_priv); - ret = ccw_device_console_enable(cdev, sch); - if (ret) { - set_io_private(sch, NULL); - put_device(&sch->dev); - put_device(&cdev->dev); - kfree(io_priv); - return ERR_PTR(ret); - } return cdev; } +void __init ccw_device_destroy_console(struct ccw_device *cdev) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + struct io_subchannel_private *io_priv = to_io_private(sch); + + set_io_private(sch, NULL); + put_device(&sch->dev); + put_device(&cdev->dev); + kfree(io_priv); +} + /** * ccw_device_wait_idle() - busy wait for device to become idle * @cdev: ccw device -- cgit v1.2.3-59-g8ed1b