s390/cio: get rid of static console subchannel
Remove the static console subchannel (and friends) and use dynamic allocation for these structures. With this change the console subchanel is treated (mostly) like any other subchannel and we can remove some special cases. Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
c135ad1caf
commit
863fc84927
@ -540,13 +540,9 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
|
|||||||
memset(sch, 0, sizeof(struct subchannel));
|
memset(sch, 0, sizeof(struct subchannel));
|
||||||
|
|
||||||
sch->schid = schid;
|
sch->schid = schid;
|
||||||
if (cio_is_console(schid)) {
|
err = cio_create_sch_lock(sch);
|
||||||
sch->lock = cio_get_console_lock();
|
if (err)
|
||||||
} else {
|
goto out;
|
||||||
err = cio_create_sch_lock(sch);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
mutex_init(&sch->reg_mutex);
|
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);
|
sch->schid.ssid, sch->schid.sch_no, sch->st);
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
if (!cio_is_console(schid))
|
kfree(sch->lock);
|
||||||
kfree(sch->lock);
|
|
||||||
sch->lock = NULL;
|
sch->lock = NULL;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -650,9 +645,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CCW_CONSOLE
|
#ifdef CONFIG_CCW_CONSOLE
|
||||||
static struct subchannel console_subchannel;
|
static struct subchannel *console_sch;
|
||||||
static struct io_subchannel_private console_priv;
|
|
||||||
static int console_subchannel_in_use;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use cio_tsch to update the subchannel status and call the interrupt handler
|
* 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
|
if (stsch_err(schid, &schib) != 0)
|
||||||
cio_test_for_console(struct subchannel_id schid, void *data)
|
|
||||||
{
|
|
||||||
if (stsch_err(schid, &console_subchannel.schib) != 0)
|
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
|
if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
|
||||||
console_subchannel.schib.pmcw.dnv &&
|
(schib.pmcw.dev == console_devno)) {
|
||||||
(console_subchannel.schib.pmcw.dev == console_devno)) {
|
|
||||||
console_irq = schid.sch_no;
|
console_irq = schid.sch_no;
|
||||||
return 1; /* found */
|
return 1; /* found */
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cio_get_console_sch_no(void)
|
||||||
static int
|
|
||||||
cio_get_console_sch_no(void)
|
|
||||||
{
|
{
|
||||||
struct subchannel_id schid;
|
struct subchannel_id schid;
|
||||||
|
struct schib schib;
|
||||||
|
|
||||||
init_subchannel_id(&schid);
|
init_subchannel_id(&schid);
|
||||||
if (console_irq != -1) {
|
if (console_irq != -1) {
|
||||||
/* VM provided us with the irq number of the console. */
|
/* VM provided us with the irq number of the console. */
|
||||||
schid.sch_no = console_irq;
|
schid.sch_no = console_irq;
|
||||||
if (stsch_err(schid, &console_subchannel.schib) != 0 ||
|
if (stsch_err(schid, &schib) != 0 ||
|
||||||
(console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
|
(schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
|
||||||
!console_subchannel.schib.pmcw.dnv)
|
|
||||||
return -1;
|
return -1;
|
||||||
console_devno = console_subchannel.schib.pmcw.dev;
|
console_devno = schib.pmcw.dev;
|
||||||
} else if (console_devno != -1) {
|
} else if (console_devno != -1) {
|
||||||
/* At least the console device number is known. */
|
/* At least the console device number is known. */
|
||||||
for_each_subchannel(cio_test_for_console, NULL);
|
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;
|
return console_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct subchannel *
|
struct subchannel *cio_probe_console(void)
|
||||||
cio_probe_console(void)
|
|
||||||
{
|
{
|
||||||
int sch_no, ret;
|
|
||||||
struct subchannel_id schid;
|
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();
|
sch_no = cio_get_console_sch_no();
|
||||||
if (sch_no == -1) {
|
if (sch_no == -1) {
|
||||||
console_subchannel_in_use = 0;
|
|
||||||
pr_warning("No CCW console was found\n");
|
pr_warning("No CCW console was found\n");
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
memset(&console_subchannel, 0, sizeof(struct subchannel));
|
|
||||||
init_subchannel_id(&schid);
|
init_subchannel_id(&schid);
|
||||||
schid.sch_no = sch_no;
|
schid.sch_no = sch_no;
|
||||||
ret = cio_validate_subchannel(&console_subchannel, schid);
|
sch = css_alloc_subchannel(schid);
|
||||||
if (ret) {
|
if (IS_ERR(sch))
|
||||||
console_subchannel_in_use = 0;
|
return sch;
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* enable console I/O-interrupt subclass
|
|
||||||
*/
|
|
||||||
isc_register(CONSOLE_ISC);
|
isc_register(CONSOLE_ISC);
|
||||||
console_subchannel.config.isc = CONSOLE_ISC;
|
sch->config.isc = CONSOLE_ISC;
|
||||||
console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel;
|
sch->config.intparm = (u32)(addr_t)sch;
|
||||||
ret = cio_commit_config(&console_subchannel);
|
ret = cio_commit_config(sch);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
isc_unregister(CONSOLE_ISC);
|
isc_unregister(CONSOLE_ISC);
|
||||||
console_subchannel_in_use = 0;
|
put_device(&sch->dev);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
return &console_subchannel;
|
console_sch = sch;
|
||||||
|
return sch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int cio_is_console(struct subchannel_id schid)
|
||||||
cio_release_console(void)
|
|
||||||
{
|
{
|
||||||
console_subchannel.config.intparm = 0;
|
if (!console_sch)
|
||||||
cio_commit_config(&console_subchannel);
|
|
||||||
isc_unregister(CONSOLE_ISC);
|
|
||||||
console_subchannel_in_use = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bah... hack to catch console special sausages. */
|
|
||||||
int
|
|
||||||
cio_is_console(struct subchannel_id schid)
|
|
||||||
{
|
|
||||||
if (!console_subchannel_in_use)
|
|
||||||
return 0;
|
return 0;
|
||||||
return schid_equal(&schid, &console_subchannel.schid);
|
return schid_equal(&schid, &console_sch->schid);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct subchannel *
|
struct subchannel *cio_get_console_subchannel(void)
|
||||||
cio_get_console_subchannel(void)
|
|
||||||
{
|
{
|
||||||
if (!console_subchannel_in_use)
|
return console_sch;
|
||||||
return NULL;
|
|
||||||
return &console_subchannel;
|
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_CCW_CONSOLE */
|
||||||
|
|
||||||
#endif
|
|
||||||
static int
|
static int
|
||||||
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
|
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
|
||||||
{
|
{
|
||||||
|
@ -128,17 +128,12 @@ void do_IRQ(struct pt_regs *);
|
|||||||
/* Use with care. */
|
/* Use with care. */
|
||||||
#ifdef CONFIG_CCW_CONSOLE
|
#ifdef CONFIG_CCW_CONSOLE
|
||||||
extern struct subchannel *cio_probe_console(void);
|
extern struct subchannel *cio_probe_console(void);
|
||||||
extern void cio_release_console(void);
|
|
||||||
extern int cio_is_console(struct subchannel_id);
|
extern int cio_is_console(struct subchannel_id);
|
||||||
extern struct subchannel *cio_get_console_subchannel(void);
|
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);
|
extern void cio_tsch(struct subchannel *sch);
|
||||||
#else
|
#else
|
||||||
#define cio_is_console(schid) 0
|
#define cio_is_console(schid) 0
|
||||||
#define cio_get_console_subchannel() NULL
|
#define cio_get_console_subchannel() NULL
|
||||||
#define cio_get_console_lock() NULL
|
|
||||||
#define cio_get_console_priv() NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,19 +139,15 @@ static void css_sch_todo(struct work_struct *work);
|
|||||||
|
|
||||||
static void css_subchannel_release(struct device *dev)
|
static void css_subchannel_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct subchannel *sch;
|
struct subchannel *sch = to_subchannel(dev);
|
||||||
|
|
||||||
sch = to_subchannel(dev);
|
sch->config.intparm = 0;
|
||||||
if (!cio_is_console(sch->schid)) {
|
cio_commit_config(sch);
|
||||||
/* Reset intparm to zeroes. */
|
kfree(sch->lock);
|
||||||
sch->config.intparm = 0;
|
kfree(sch);
|
||||||
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;
|
struct subchannel *sch;
|
||||||
int ret;
|
int ret;
|
||||||
@ -326,10 +322,9 @@ int css_probe_device(struct subchannel_id schid)
|
|||||||
return PTR_ERR(sch);
|
return PTR_ERR(sch);
|
||||||
}
|
}
|
||||||
ret = css_register_subchannel(sch);
|
ret = css_register_subchannel(sch);
|
||||||
if (ret) {
|
if (ret)
|
||||||
if (!cio_is_console(schid))
|
put_device(&sch->dev);
|
||||||
put_device(&sch->dev);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ extern void css_driver_unregister(struct css_driver *);
|
|||||||
|
|
||||||
extern void css_sch_device_unregister(struct subchannel *);
|
extern void css_sch_device_unregister(struct subchannel *);
|
||||||
extern int css_probe_device(struct subchannel_id);
|
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 struct subchannel *get_subchannel_by_schid(struct subchannel_id);
|
||||||
extern int css_init_done;
|
extern int css_init_done;
|
||||||
extern int max_ssid;
|
extern int max_ssid;
|
||||||
|
@ -1585,22 +1585,11 @@ static struct ccw_device console_cdev;
|
|||||||
static struct ccw_device_private console_private;
|
static struct ccw_device_private console_private;
|
||||||
static int console_cdev_in_use;
|
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,
|
static int ccw_device_console_enable(struct ccw_device *cdev,
|
||||||
struct subchannel *sch)
|
struct subchannel *sch)
|
||||||
{
|
{
|
||||||
struct io_subchannel_private *io_priv = cio_get_console_priv();
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Attach subchannel private data. */
|
|
||||||
memset(io_priv, 0, sizeof(*io_priv));
|
|
||||||
set_io_private(sch, io_priv);
|
|
||||||
io_subchannel_init_fields(sch);
|
io_subchannel_init_fields(sch);
|
||||||
rc = cio_commit_config(sch);
|
rc = cio_commit_config(sch);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -1633,6 +1622,7 @@ out_unlock:
|
|||||||
struct ccw_device *
|
struct ccw_device *
|
||||||
ccw_device_probe_console(void)
|
ccw_device_probe_console(void)
|
||||||
{
|
{
|
||||||
|
struct io_subchannel_private *io_priv;
|
||||||
struct subchannel *sch;
|
struct subchannel *sch;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -1648,10 +1638,20 @@ ccw_device_probe_console(void)
|
|||||||
console_cdev.private = &console_private;
|
console_cdev.private = &console_private;
|
||||||
console_private.cdev = &console_cdev;
|
console_private.cdev = &console_cdev;
|
||||||
console_private.int_class = IRQIO_CIO;
|
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);
|
ret = ccw_device_console_enable(&console_cdev, sch);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
cio_release_console();
|
|
||||||
console_cdev_in_use = 0;
|
console_cdev_in_use = 0;
|
||||||
|
set_io_private(sch, NULL);
|
||||||
|
put_device(&sch->dev);
|
||||||
|
kfree(io_priv);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
console_cdev.online = 1;
|
console_cdev.online = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user