forked from luck/tmp_suning_uos_patched
s390/css: reduce stsch calls
Both css_evaluate_new_subchannel and cio_validate_subchannel used stsch and css_sch_is_valid to check for a valid device. Reduce stsch calls during subchannel evaluation by re-using schib data. Also the type/devno valid information is only checked once. Signed-off-by: Sebastian Ott <sebott@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
05b217f4c5
commit
d4f5d79e97
|
@ -526,64 +526,6 @@ int cio_disable_subchannel(struct subchannel *sch)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
|
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
|
||||||
|
|
||||||
/**
|
|
||||||
* cio_validate_subchannel - basic validation of subchannel
|
|
||||||
* @schid: subchannel id
|
|
||||||
* @schib: subchannel information block to be filled out
|
|
||||||
*
|
|
||||||
* Check if subchannel is valid and should be used.
|
|
||||||
* Return codes:
|
|
||||||
* 0 on success
|
|
||||||
* -ENXIO for non-defined subchannels
|
|
||||||
* -ENODEV for invalid subchannels or blacklisted devices
|
|
||||||
* -EIO for subchannels in an invalid subchannel set
|
|
||||||
*/
|
|
||||||
int cio_validate_subchannel(struct subchannel_id schid, struct schib *schib)
|
|
||||||
{
|
|
||||||
char dbf_txt[15];
|
|
||||||
int ccode;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
sprintf(dbf_txt, "valsch%x", schid.sch_no);
|
|
||||||
CIO_TRACE_EVENT(4, dbf_txt);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The first subchannel that is not-operational (ccode==3)
|
|
||||||
* indicates that there aren't any more devices available.
|
|
||||||
* If stsch gets an exception, it means the current subchannel set
|
|
||||||
* is not valid.
|
|
||||||
*/
|
|
||||||
ccode = stsch(schid, schib);
|
|
||||||
if (ccode) {
|
|
||||||
err = (ccode == 3) ? -ENXIO : ccode;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (schib->pmcw.st) {
|
|
||||||
case SUBCHANNEL_TYPE_IO:
|
|
||||||
case SUBCHANNEL_TYPE_MSG:
|
|
||||||
if (!css_sch_is_valid(schib))
|
|
||||||
err = -ENODEV;
|
|
||||||
else if (is_blacklisted(schid.ssid, schib->pmcw.dev)) {
|
|
||||||
CIO_MSG_EVENT(6, "Blacklisted device detected "
|
|
||||||
"at devno %04X, subchannel set %x\n",
|
|
||||||
schib->pmcw.dev, schid.ssid);
|
|
||||||
err = -ENODEV;
|
|
||||||
} else
|
|
||||||
err = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
|
|
||||||
schid.ssid, schid.sch_no, schib->pmcw.st);
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do_cio_interrupt() handles all normal I/O device IRQ's
|
* do_cio_interrupt() handles all normal I/O device IRQ's
|
||||||
*/
|
*/
|
||||||
|
@ -707,6 +649,7 @@ struct subchannel *cio_probe_console(void)
|
||||||
{
|
{
|
||||||
struct subchannel_id schid;
|
struct subchannel_id schid;
|
||||||
struct subchannel *sch;
|
struct subchannel *sch;
|
||||||
|
struct schib schib;
|
||||||
int sch_no, ret;
|
int sch_no, ret;
|
||||||
|
|
||||||
sch_no = cio_get_console_sch_no();
|
sch_no = cio_get_console_sch_no();
|
||||||
|
@ -716,7 +659,11 @@ struct subchannel *cio_probe_console(void)
|
||||||
}
|
}
|
||||||
init_subchannel_id(&schid);
|
init_subchannel_id(&schid);
|
||||||
schid.sch_no = sch_no;
|
schid.sch_no = sch_no;
|
||||||
sch = css_alloc_subchannel(schid);
|
ret = stsch(schid, &schib);
|
||||||
|
if (ret)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
sch = css_alloc_subchannel(schid, &schib);
|
||||||
if (IS_ERR(sch))
|
if (IS_ERR(sch))
|
||||||
return sch;
|
return sch;
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,6 @@ DECLARE_PER_CPU(struct irb, cio_irb);
|
||||||
|
|
||||||
#define to_subchannel(n) container_of(n, struct subchannel, dev)
|
#define to_subchannel(n) container_of(n, struct subchannel, dev)
|
||||||
|
|
||||||
extern int cio_validate_subchannel(struct subchannel_id, struct schib *);
|
|
||||||
extern int cio_enable_subchannel(struct subchannel *, u32);
|
extern int cio_enable_subchannel(struct subchannel *, u32);
|
||||||
extern int cio_disable_subchannel (struct subchannel *);
|
extern int cio_disable_subchannel (struct subchannel *);
|
||||||
extern int cio_cancel (struct subchannel *);
|
extern int cio_cancel (struct subchannel *);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "cio.h"
|
#include "cio.h"
|
||||||
|
#include "blacklist.h"
|
||||||
#include "cio_debug.h"
|
#include "cio_debug.h"
|
||||||
#include "ioasm.h"
|
#include "ioasm.h"
|
||||||
#include "chsc.h"
|
#include "chsc.h"
|
||||||
|
@ -168,13 +169,43 @@ static void css_subchannel_release(struct device *dev)
|
||||||
kfree(sch);
|
kfree(sch);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
|
static int css_validate_subchannel(struct subchannel_id schid,
|
||||||
|
struct schib *schib)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
switch (schib->pmcw.st) {
|
||||||
|
case SUBCHANNEL_TYPE_IO:
|
||||||
|
case SUBCHANNEL_TYPE_MSG:
|
||||||
|
if (!css_sch_is_valid(schib))
|
||||||
|
err = -ENODEV;
|
||||||
|
else if (is_blacklisted(schid.ssid, schib->pmcw.dev)) {
|
||||||
|
CIO_MSG_EVENT(6, "Blacklisted device detected "
|
||||||
|
"at devno %04X, subchannel set %x\n",
|
||||||
|
schib->pmcw.dev, schid.ssid);
|
||||||
|
err = -ENODEV;
|
||||||
|
} else
|
||||||
|
err = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
|
||||||
|
schid.ssid, schid.sch_no, schib->pmcw.st);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct subchannel *css_alloc_subchannel(struct subchannel_id schid,
|
||||||
|
struct schib *schib)
|
||||||
{
|
{
|
||||||
struct subchannel *sch;
|
struct subchannel *sch;
|
||||||
struct schib schib;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = cio_validate_subchannel(schid, &schib);
|
ret = css_validate_subchannel(schid, schib);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
@ -183,8 +214,8 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
sch->schid = schid;
|
sch->schid = schid;
|
||||||
sch->schib = schib;
|
sch->schib = *schib;
|
||||||
sch->st = schib.pmcw.st;
|
sch->st = schib->pmcw.st;
|
||||||
|
|
||||||
ret = css_sch_create_locks(sch);
|
ret = css_sch_create_locks(sch);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -386,12 +417,12 @@ int css_register_subchannel(struct subchannel *sch)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int css_probe_device(struct subchannel_id schid)
|
static int css_probe_device(struct subchannel_id schid, struct schib *schib)
|
||||||
{
|
{
|
||||||
struct subchannel *sch;
|
struct subchannel *sch;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sch = css_alloc_subchannel(schid);
|
sch = css_alloc_subchannel(schid, schib);
|
||||||
if (IS_ERR(sch))
|
if (IS_ERR(sch))
|
||||||
return PTR_ERR(sch);
|
return PTR_ERR(sch);
|
||||||
|
|
||||||
|
@ -440,23 +471,23 @@ EXPORT_SYMBOL_GPL(css_sch_is_valid);
|
||||||
static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
|
static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
|
||||||
{
|
{
|
||||||
struct schib schib;
|
struct schib schib;
|
||||||
|
int ccode;
|
||||||
|
|
||||||
if (!slow) {
|
if (!slow) {
|
||||||
/* Will be done on the slow path. */
|
/* Will be done on the slow path. */
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (stsch(schid, &schib)) {
|
/*
|
||||||
/* Subchannel is not provided. */
|
* The first subchannel that is not-operational (ccode==3)
|
||||||
return -ENXIO;
|
* indicates that there aren't any more devices available.
|
||||||
}
|
* If stsch gets an exception, it means the current subchannel set
|
||||||
if (!css_sch_is_valid(&schib)) {
|
* is not valid.
|
||||||
/* Unusable - ignore. */
|
*/
|
||||||
return 0;
|
ccode = stsch(schid, &schib);
|
||||||
}
|
if (ccode)
|
||||||
CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid,
|
return (ccode == 3) ? -ENXIO : ccode;
|
||||||
schid.sch_no);
|
|
||||||
|
|
||||||
return css_probe_device(schid);
|
return css_probe_device(schid, &schib);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
|
static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
|
||||||
|
|
|
@ -103,7 +103,8 @@ 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_register_subchannel(struct subchannel *);
|
extern int css_register_subchannel(struct subchannel *);
|
||||||
extern struct subchannel *css_alloc_subchannel(struct subchannel_id);
|
extern struct subchannel *css_alloc_subchannel(struct subchannel_id,
|
||||||
|
struct schib *schib);
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user