Commit f97a56fb authored by Cornelia Huck's avatar Cornelia Huck Committed by Linus Torvalds

[PATCH] s390: introduce for_each_subchannel

for_each_subchannel() is an iterator calling a function for every possible
subchannel id until non-zero is returned.  Convert the current iterating
functions to it.
Signed-off-by: default avatarCornelia Huck <cohuck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a8237fc4
......@@ -219,6 +219,27 @@ is_blacklisted (int devno)
}
#ifdef CONFIG_PROC_FS
static int
__s390_redo_validation(struct subchannel_id schid, void *data)
{
int ret;
struct subchannel *sch;
sch = get_subchannel_by_schid(schid);
if (sch) {
/* Already known. */
put_device(&sch->dev);
return 0;
}
ret = css_probe_device(schid);
if (ret == -ENXIO)
return ret; /* We're through. */
if (ret == -ENOMEM)
/* Stop validation for now. Bad, but no need for a panic. */
return ret;
return 0;
}
/*
* Function: s390_redo_validation
* Look for no longer blacklisted devices
......@@ -226,30 +247,9 @@ is_blacklisted (int devno)
static inline void
s390_redo_validation (void)
{
struct subchannel_id schid;
CIO_TRACE_EVENT (0, "redoval");
init_subchannel_id(&schid);
do {
int ret;
struct subchannel *sch;
sch = get_subchannel_by_schid(schid);
if (sch) {
/* Already known. */
put_device(&sch->dev);
continue;
}
ret = css_probe_device(schid);
if (ret == -ENXIO)
break; /* We're through. */
if (ret == -ENOMEM)
/*
* Stop validation for now. Bad, but no need for a
* panic.
*/
break;
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
for_each_subchannel(__s390_redo_validation, NULL);
}
/*
......
This diff is collapsed.
......@@ -691,7 +691,22 @@ wait_cons_dev (void)
}
static int
cio_console_irq(void)
cio_test_for_console(struct subchannel_id schid, void *data)
{
if (stsch(schid, &console_subchannel.schib) != 0)
return -ENXIO;
if (console_subchannel.schib.pmcw.dnv &&
console_subchannel.schib.pmcw.dev ==
console_devno) {
console_irq = schid.sch_no;
return 1; /* found */
}
return 0;
}
static int
cio_get_console_sch_no(void)
{
struct subchannel_id schid;
......@@ -705,16 +720,7 @@ cio_console_irq(void)
console_devno = console_subchannel.schib.pmcw.dev;
} else if (console_devno != -1) {
/* At least the console device number is known. */
do {
if (stsch(schid, &console_subchannel.schib) != 0)
break;
if (console_subchannel.schib.pmcw.dnv &&
console_subchannel.schib.pmcw.dev ==
console_devno) {
console_irq = schid.sch_no;
break;
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
for_each_subchannel(cio_test_for_console, NULL);
if (console_irq == -1)
return -1;
} else {
......@@ -730,19 +736,19 @@ cio_console_irq(void)
struct subchannel *
cio_probe_console(void)
{
int irq, ret;
int sch_no, ret;
struct subchannel_id schid;
if (xchg(&console_subchannel_in_use, 1) != 0)
return ERR_PTR(-EBUSY);
irq = cio_console_irq();
if (irq == -1) {
sch_no = cio_get_console_sch_no();
if (sch_no == -1) {
console_subchannel_in_use = 0;
return ERR_PTR(-ENODEV);
}
memset(&console_subchannel, 0, sizeof(struct subchannel));
init_subchannel_id(&schid);
schid.sch_no = irq;
schid.sch_no = sch_no;
ret = cio_validate_subchannel(&console_subchannel, schid);
if (ret) {
console_subchannel_in_use = 0;
......@@ -830,32 +836,33 @@ __clear_subchannel_easy(struct subchannel_id schid)
}
extern void do_reipl(unsigned long devno);
static int
__shutdown_subchannel_easy(struct subchannel_id schid, void *data)
{
struct schib schib;
if (stsch(schid, &schib))
return -ENXIO;
if (!schib.pmcw.ena)
return 0;
switch(__disable_subchannel_easy(schid, &schib)) {
case 0:
case -ENODEV:
break;
default: /* -EBUSY */
if (__clear_subchannel_easy(schid))
break; /* give up... */
stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
return 0;
}
/* Clear all subchannels. */
void
clear_all_subchannels(void)
{
struct subchannel_id schid;
local_irq_disable();
init_subchannel_id(&schid);
do {
struct schib schib;
if (stsch(schid, &schib))
break; /* break out of the loop */
if (!schib.pmcw.ena)
continue;
switch(__disable_subchannel_easy(schid, &schib)) {
case 0:
case -ENODEV:
break;
default: /* -EBUSY */
if (__clear_subchannel_easy(schid))
break; /* give up... jump out of switch */
stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
for_each_subchannel(__shutdown_subchannel_easy, NULL);
}
/* Make sure all subchannels are quiet before we re-ipl an lpar. */
......
......@@ -21,7 +21,6 @@
#include "ioasm.h"
#include "chsc.h"
unsigned int highest_subchannel;
int need_rescan = 0;
int css_init_done = 0;
......@@ -32,6 +31,22 @@ struct device css_bus_device = {
.bus_id = "css0",
};
inline int
for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
{
struct subchannel_id schid;
int ret;
init_subchannel_id(&schid);
ret = -ENODEV;
do {
ret = fn(schid, data);
if (ret)
break;
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
return ret;
}
static struct subchannel *
css_alloc_subchannel(struct subchannel_id schid)
{
......@@ -280,25 +295,10 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow)
return ret;
}
static void
css_rescan_devices(void)
static int
css_rescan_devices(struct subchannel_id schid, void *data)
{
int ret;
struct subchannel_id schid;
init_subchannel_id(&schid);
do {
ret = css_evaluate_subchannel(schid, 1);
/* No more memory. It doesn't make sense to continue. No
* panic because this can happen in midflight and just
* because we can't use a new device is no reason to crash
* the system. */
if (ret == -ENOMEM)
break;
/* -ENXIO indicates that there are no more subchannels. */
if (ret == -ENXIO)
break;
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
return css_evaluate_subchannel(schid, 1);
}
struct slow_subchannel {
......@@ -316,7 +316,7 @@ css_trigger_slow_path(void)
if (need_rescan) {
need_rescan = 0;
css_rescan_devices();
for_each_subchannel(css_rescan_devices, NULL);
return;
}
......@@ -383,6 +383,43 @@ css_process_crw(int irq)
return ret;
}
static int __init
__init_channel_subsystem(struct subchannel_id schid, void *data)
{
struct subchannel *sch;
int ret;
if (cio_is_console(schid))
sch = cio_get_console_subchannel();
else {
sch = css_alloc_subchannel(schid);
if (IS_ERR(sch))
ret = PTR_ERR(sch);
else
ret = 0;
switch (ret) {
case 0:
break;
case -ENOMEM:
panic("Out of memory in init_channel_subsystem\n");
/* -ENXIO: no more subchannels. */
case -ENXIO:
return ret;
default:
return 0;
}
}
/*
* We register ALL valid subchannels in ioinfo, even those
* that have been present before init_channel_subsystem.
* These subchannels can't have been registered yet (kmalloc
* not working) so we do it now. This is true e.g. for the
* console subchannel.
*/
css_register_subchannel(sch);
return 0;
}
static void __init
css_generate_pgid(void)
{
......@@ -410,7 +447,6 @@ static int __init
init_channel_subsystem (void)
{
int ret;
struct subchannel_id schid;
if (chsc_determine_css_characteristics() == 0)
css_characteristics_avail = 1;
......@@ -426,38 +462,8 @@ init_channel_subsystem (void)
ctl_set_bit(6, 28);
init_subchannel_id(&schid);
do {
struct subchannel *sch;
if (cio_is_console(schid))
sch = cio_get_console_subchannel();
else {
sch = css_alloc_subchannel(schid);
if (IS_ERR(sch))
ret = PTR_ERR(sch);
else
ret = 0;
if (ret == -ENOMEM)
panic("Out of memory in "
"init_channel_subsystem\n");
/* -ENXIO: no more subchannels. */
if (ret == -ENXIO)
break;
if (ret)
continue;
}
/*
* We register ALL valid subchannels in ioinfo, even those
* that have been present before init_channel_subsystem.
* These subchannels can't have been registered yet (kmalloc
* not working) so we do it now. This is true e.g. for the
* console subchannel.
*/
css_register_subchannel(sch);
} while (schid.sch_no++ < __MAX_SUBCHANNEL);
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
out_bus:
bus_unregister(&css_bus_type);
out:
......
......@@ -126,6 +126,7 @@ extern struct css_driver io_subchannel_driver;
extern int css_probe_device(struct subchannel_id);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
#define __MAX_SUBCHANNEL 65535
......
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