diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/cio.c | 111 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 5 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 23 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 24 |
5 files changed, 56 insertions, 108 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 2c1d53fb2fab..ab99500604b7 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -540,13 +540,9 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) memset(sch, 0, sizeof(struct subchannel)); sch->schid = schid; - if (cio_is_console(schid)) { - sch->lock = cio_get_console_lock(); - } else { - err = cio_create_sch_lock(sch); - if (err) - goto out; - } + err = cio_create_sch_lock(sch); + if (err) + goto out; mutex_init(&sch->reg_mutex); /* @@ -580,8 +576,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) sch->schid.ssid, sch->schid.sch_no, sch->st); return 0; out: - if (!cio_is_console(schid)) - kfree(sch->lock); + kfree(sch->lock); sch->lock = NULL; return err; } @@ -650,9 +645,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) } #ifdef CONFIG_CCW_CONSOLE -static struct subchannel console_subchannel; -static struct io_subchannel_private console_priv; -static int console_subchannel_in_use; +static struct subchannel *console_sch; /* * Use cio_tsch to update the subchannel status and call the interrupt handler @@ -685,119 +678,83 @@ void cio_tsch(struct subchannel *sch) } } -void *cio_get_console_priv(void) +static int cio_test_for_console(struct subchannel_id schid, void *data) { - return &console_priv; -} + struct schib schib; -static int -cio_test_for_console(struct subchannel_id schid, void *data) -{ - if (stsch_err(schid, &console_subchannel.schib) != 0) + if (stsch_err(schid, &schib) != 0) return -ENXIO; - if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) && - console_subchannel.schib.pmcw.dnv && - (console_subchannel.schib.pmcw.dev == console_devno)) { + if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv && + (schib.pmcw.dev == console_devno)) { console_irq = schid.sch_no; return 1; /* found */ } return 0; } - -static int -cio_get_console_sch_no(void) +static int cio_get_console_sch_no(void) { struct subchannel_id schid; - + struct schib schib; + init_subchannel_id(&schid); if (console_irq != -1) { /* VM provided us with the irq number of the console. */ schid.sch_no = console_irq; - if (stsch_err(schid, &console_subchannel.schib) != 0 || - (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) || - !console_subchannel.schib.pmcw.dnv) + if (stsch_err(schid, &schib) != 0 || + (schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv) return -1; - console_devno = console_subchannel.schib.pmcw.dev; + console_devno = schib.pmcw.dev; } else if (console_devno != -1) { /* At least the console device number is known. */ for_each_subchannel(cio_test_for_console, NULL); - if (console_irq == -1) - return -1; - } else { - /* unlike in 2.4, we cannot autoprobe here, since - * the channel subsystem is not fully initialized. - * With some luck, the HWC console can take over */ - return -1; } return console_irq; } -struct subchannel * -cio_probe_console(void) +struct subchannel *cio_probe_console(void) { - int sch_no, ret; struct subchannel_id schid; + struct subchannel *sch; + int sch_no, ret; - if (xchg(&console_subchannel_in_use, 1) != 0) - return ERR_PTR(-EBUSY); sch_no = cio_get_console_sch_no(); if (sch_no == -1) { - console_subchannel_in_use = 0; pr_warning("No CCW console was found\n"); return ERR_PTR(-ENODEV); } - memset(&console_subchannel, 0, sizeof(struct subchannel)); init_subchannel_id(&schid); schid.sch_no = sch_no; - ret = cio_validate_subchannel(&console_subchannel, schid); - if (ret) { - console_subchannel_in_use = 0; - return ERR_PTR(-ENODEV); - } + sch = css_alloc_subchannel(schid); + if (IS_ERR(sch)) + return sch; - /* - * enable console I/O-interrupt subclass - */ isc_register(CONSOLE_ISC); - console_subchannel.config.isc = CONSOLE_ISC; - console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel; - ret = cio_commit_config(&console_subchannel); + sch->config.isc = CONSOLE_ISC; + sch->config.intparm = (u32)(addr_t)sch; + ret = cio_commit_config(sch); if (ret) { isc_unregister(CONSOLE_ISC); - console_subchannel_in_use = 0; + put_device(&sch->dev); return ERR_PTR(ret); } - return &console_subchannel; -} - -void -cio_release_console(void) -{ - console_subchannel.config.intparm = 0; - cio_commit_config(&console_subchannel); - isc_unregister(CONSOLE_ISC); - console_subchannel_in_use = 0; + console_sch = sch; + return sch; } -/* Bah... hack to catch console special sausages. */ -int -cio_is_console(struct subchannel_id schid) +int cio_is_console(struct subchannel_id schid) { - if (!console_subchannel_in_use) + if (!console_sch) return 0; - return schid_equal(&schid, &console_subchannel.schid); + return schid_equal(&schid, &console_sch->schid); } -struct subchannel * -cio_get_console_subchannel(void) +struct subchannel *cio_get_console_subchannel(void) { - if (!console_subchannel_in_use) - return NULL; - return &console_subchannel; + return console_sch; } +#endif /* CONFIG_CCW_CONSOLE */ -#endif static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 3b97c8bb30e5..78975471ef28 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -128,17 +128,12 @@ void do_IRQ(struct pt_regs *); /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE extern struct subchannel *cio_probe_console(void); -extern void cio_release_console(void); extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); -extern spinlock_t * cio_get_console_lock(void); -extern void *cio_get_console_priv(void); extern void cio_tsch(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL -#define cio_get_console_lock() NULL -#define cio_get_console_priv() NULL #endif #endif diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 8a1294b1cbaf..fb0e64f1845a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -139,19 +139,15 @@ static void css_sch_todo(struct work_struct *work); static void css_subchannel_release(struct device *dev) { - struct subchannel *sch; + struct subchannel *sch = to_subchannel(dev); - sch = to_subchannel(dev); - if (!cio_is_console(sch->schid)) { - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); - kfree(sch->lock); - kfree(sch); - } + sch->config.intparm = 0; + cio_commit_config(sch); + kfree(sch->lock); + kfree(sch); } -static struct subchannel *css_alloc_subchannel(struct subchannel_id schid) +struct subchannel *css_alloc_subchannel(struct subchannel_id schid) { struct subchannel *sch; int ret; @@ -326,10 +322,9 @@ int css_probe_device(struct subchannel_id schid) return PTR_ERR(sch); } ret = css_register_subchannel(sch); - if (ret) { - if (!cio_is_console(schid)) - put_device(&sch->dev); - } + if (ret) + put_device(&sch->dev); + return ret; } diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4af3dfe70ef5..6ab424d753a9 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -102,6 +102,7 @@ extern void css_driver_unregister(struct css_driver *); extern void css_sch_device_unregister(struct subchannel *); extern int css_probe_device(struct subchannel_id); +extern struct subchannel *css_alloc_subchannel(struct subchannel_id); extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; extern int max_ssid; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6ac0066d3158..25d04b7b5109 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1585,22 +1585,11 @@ static struct ccw_device console_cdev; static struct ccw_device_private console_private; static int console_cdev_in_use; -static DEFINE_SPINLOCK(ccw_console_lock); - -spinlock_t * cio_get_console_lock(void) -{ - return &ccw_console_lock; -} - static int ccw_device_console_enable(struct ccw_device *cdev, struct subchannel *sch) { - struct io_subchannel_private *io_priv = cio_get_console_priv(); int rc; - /* Attach subchannel private data. */ - memset(io_priv, 0, sizeof(*io_priv)); - set_io_private(sch, io_priv); io_subchannel_init_fields(sch); rc = cio_commit_config(sch); if (rc) @@ -1633,6 +1622,7 @@ out_unlock: struct ccw_device * ccw_device_probe_console(void) { + struct io_subchannel_private *io_priv; struct subchannel *sch; int ret; @@ -1648,10 +1638,20 @@ ccw_device_probe_console(void) console_cdev.private = &console_private; console_private.cdev = &console_cdev; console_private.int_class = IRQIO_CIO; + + io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA); + if (!io_priv) { + put_device(&sch->dev); + return ERR_PTR(-ENOMEM); + } + set_io_private(sch, io_priv); + ret = ccw_device_console_enable(&console_cdev, sch); if (ret) { - cio_release_console(); console_cdev_in_use = 0; + set_io_private(sch, NULL); + put_device(&sch->dev); + kfree(io_priv); return ERR_PTR(ret); } console_cdev.online = 1; |