Commit 1e532096 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky

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: default avatarPeter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 2253e8d7
...@@ -219,7 +219,9 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *); ...@@ -219,7 +219,9 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define to_ccwdev(n) container_of(n, struct ccw_device, dev) #define to_ccwdev(n) container_of(n, struct ccw_device, dev)
#define to_ccwdrv(n) container_of(n, struct ccw_driver, driver) #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
extern struct ccw_device *ccw_device_probe_console(struct ccw_driver *); extern struct ccw_device *ccw_device_create_console(struct ccw_driver *);
extern void ccw_device_destroy_console(struct ccw_device *);
extern int ccw_device_enable_console(struct ccw_device *);
extern void ccw_device_wait_idle(struct ccw_device *); extern void ccw_device_wait_idle(struct ccw_device *);
extern int ccw_device_force_console(struct ccw_device *); extern int ccw_device_force_console(struct ccw_device *);
......
...@@ -922,7 +922,7 @@ static int __init con3215_init(void) ...@@ -922,7 +922,7 @@ static int __init con3215_init(void)
raw3215_freelist = req; raw3215_freelist = req;
} }
cdev = ccw_device_probe_console(&raw3215_ccw_driver); cdev = ccw_device_create_console(&raw3215_ccw_driver);
if (IS_ERR(cdev)) if (IS_ERR(cdev))
return -ENODEV; return -ENODEV;
...@@ -932,6 +932,12 @@ static int __init con3215_init(void) ...@@ -932,6 +932,12 @@ static int __init con3215_init(void)
cdev->handler = raw3215_irq; cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED; raw->flags |= RAW3215_FIXED;
if (ccw_device_enable_console(cdev)) {
ccw_device_destroy_console(cdev);
raw3215_free_info(raw);
raw3215[0] = NULL;
return -ENODEV;
}
/* Request the console irq */ /* Request the console irq */
if (raw3215_startup(raw) != 0) { if (raw3215_startup(raw) != 0) {
......
...@@ -790,7 +790,7 @@ struct raw3270 __init *raw3270_setup_console(void) ...@@ -790,7 +790,7 @@ struct raw3270 __init *raw3270_setup_console(void)
char *ascebc; char *ascebc;
int rc; int rc;
cdev = ccw_device_probe_console(&raw3270_ccw_driver); cdev = ccw_device_create_console(&raw3270_ccw_driver);
if (IS_ERR(cdev)) if (IS_ERR(cdev))
return ERR_CAST(cdev); return ERR_CAST(cdev);
...@@ -800,6 +800,13 @@ struct raw3270 __init *raw3270_setup_console(void) ...@@ -800,6 +800,13 @@ struct raw3270 __init *raw3270_setup_console(void)
if (rc) if (rc)
return ERR_PTR(rc); return ERR_PTR(rc);
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags); set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
rc = ccw_device_enable_console(cdev);
if (rc) {
ccw_device_destroy_console(cdev);
return ERR_PTR(rc);
}
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
do { do {
__raw3270_reset_device(rp); __raw3270_reset_device(rp);
......
...@@ -1572,11 +1572,14 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) ...@@ -1572,11 +1572,14 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
} }
#ifdef CONFIG_CCW_CONSOLE #ifdef CONFIG_CCW_CONSOLE
static int ccw_device_console_enable(struct ccw_device *cdev, int __init ccw_device_enable_console(struct ccw_device *cdev)
struct subchannel *sch)
{ {
struct subchannel *sch = to_subchannel(cdev->dev.parent);
int rc; int rc;
if (!cdev->drv || !cdev->handler)
return -EINVAL;
io_subchannel_init_fields(sch); io_subchannel_init_fields(sch);
rc = cio_commit_config(sch); rc = cio_commit_config(sch);
if (rc) if (rc)
...@@ -1609,12 +1612,11 @@ static int ccw_device_console_enable(struct ccw_device *cdev, ...@@ -1609,12 +1612,11 @@ static int ccw_device_console_enable(struct ccw_device *cdev,
return rc; 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 io_subchannel_private *io_priv;
struct ccw_device *cdev; struct ccw_device *cdev;
struct subchannel *sch; struct subchannel *sch;
int ret;
sch = cio_probe_console(); sch = cio_probe_console();
if (IS_ERR(sch)) if (IS_ERR(sch))
...@@ -1633,15 +1635,18 @@ struct ccw_device *ccw_device_probe_console(struct ccw_driver *drv) ...@@ -1633,15 +1635,18 @@ struct ccw_device *ccw_device_probe_console(struct ccw_driver *drv)
} }
cdev->drv = drv; cdev->drv = drv;
set_io_private(sch, io_priv); set_io_private(sch, io_priv);
ret = ccw_device_console_enable(cdev, sch); return cdev;
if (ret) { }
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); set_io_private(sch, NULL);
put_device(&sch->dev); put_device(&sch->dev);
put_device(&cdev->dev); put_device(&cdev->dev);
kfree(io_priv); kfree(io_priv);
return ERR_PTR(ret);
}
return cdev;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment