Commit e1776856 authored by Ursula Braun's avatar Ursula Braun Committed by Heiko Carstens

[S390] qdio (new feature): enhancing info-retrieval from QDIO-adapters

Next generation of OSA adapters allows retrieval of further self-describing
infos. This is the preparational infrastructure patch for further exploitation
in the qeth driver.
Signed-off-by: default avatarUrsula Braun <braunu@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent 2a2cf6b1
......@@ -2217,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
return cc;
}
static int
qdio_get_ssqd_information(struct subchannel_id *schid,
struct qdio_chsc_ssqd **ssqd_area)
{
int result;
QDIO_DBF_TEXT0(0, setup, "getssqd");
*ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!ssqd_area) {
QDIO_PRINT_WARN("Could not get memory for chsc on sch x%x.\n",
schid->sch_no);
return -ENOMEM;
}
(*ssqd_area)->request = (struct chsc_header) {
.length = 0x0010,
.code = 0x0024,
};
(*ssqd_area)->first_sch = schid->sch_no;
(*ssqd_area)->last_sch = schid->sch_no;
(*ssqd_area)->ssid = schid->ssid;
result = chsc(*ssqd_area);
if (result) {
QDIO_PRINT_WARN("CHSC returned cc %i on sch 0.%x.%x.\n",
result, schid->ssid, schid->sch_no);
goto out;
}
if ((*ssqd_area)->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {
QDIO_PRINT_WARN("CHSC response is 0x%x on sch 0.%x.%x.\n",
(*ssqd_area)->response.code,
schid->ssid, schid->sch_no);
goto out;
}
if (!((*ssqd_area)->flags & CHSC_FLAG_QDIO_CAPABILITY) ||
!((*ssqd_area)->flags & CHSC_FLAG_VALIDITY) ||
((*ssqd_area)->sch != schid->sch_no)) {
QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \
"using all SIGAs.\n",
schid->ssid, schid->sch_no);
goto out;
}
return 0;
out:
return -EINVAL;
}
int
qdio_get_ssqd_pct(struct ccw_device *cdev)
{
struct qdio_chsc_ssqd *ssqd_area;
struct subchannel_id schid;
char dbf_text[15];
int rc;
int pct = 0;
QDIO_DBF_TEXT0(0, setup, "getpct");
schid = ccw_device_get_subchannel_id(cdev);
rc = qdio_get_ssqd_information(&schid, &ssqd_area);
if (!rc)
pct = (int)ssqd_area->pct;
if (rc != -ENOMEM)
mempool_free(ssqd_area, qdio_mempool_scssc);
sprintf(dbf_text, "pct: %d", pct);
QDIO_DBF_TEXT2(0, setup, dbf_text);
return pct;
}
EXPORT_SYMBOL(qdio_get_ssqd_pct);
static void
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
unsigned long token)
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token)
{
struct qdio_q *q;
int i;
......@@ -2227,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
char dbf_text[15];
/*check if QEBSM is disabled */
if (!(irq_ptr->is_qebsm) || !(qdioac & 0x01)) {
if (!(irq_ptr->is_qebsm) || !(irq_ptr->qdioac & 0x01)) {
irq_ptr->is_qebsm = 0;
irq_ptr->sch_token = 0;
irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
......@@ -2256,102 +2325,27 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
}
static void
qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
qdio_get_ssqd_siga(struct qdio_irq *irq_ptr)
{
int result;
unsigned char qdioac;
struct {
struct chsc_header request;
u16 reserved1:10;
u16 ssid:2;
u16 fmt:4;
u16 first_sch;
u16 reserved2;
u16 last_sch;
u32 reserved3;
struct chsc_header response;
u32 reserved4;
u8 flags;
u8 reserved5;
u16 sch;
u8 qfmt;
u8 parm;
u8 qdioac1;
u8 sch_class;
u8 reserved7;
u8 icnt;
u8 reserved8;
u8 ocnt;
u8 reserved9;
u8 mbccnt;
u16 qdioac2;
u64 sch_token;
} *ssqd_area;
int rc;
struct qdio_chsc_ssqd *ssqd_area;
QDIO_DBF_TEXT0(0,setup,"getssqd");
qdioac = 0;
ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!ssqd_area) {
QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
"SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
irq_ptr->qdioac = 0;
rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area);
if (rc) {
QDIO_PRINT_WARN("using all SIGAs for sch x%x.n",
irq_ptr->schid.sch_no);
irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
irq_ptr->sch_token = 0;
irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
return;
}
ssqd_area->request = (struct chsc_header) {
.length = 0x0010,
.code = 0x0024,
};
ssqd_area->first_sch = irq_ptr->schid.sch_no;
ssqd_area->last_sch = irq_ptr->schid.sch_no;
ssqd_area->ssid = irq_ptr->schid.ssid;
result = chsc(ssqd_area);
if (result) {
QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
"SIGAs for sch 0.%x.%x.\n", result,
irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
goto out;
}
} else
irq_ptr->qdioac = ssqd_area->qdioac1;
if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {
QDIO_PRINT_WARN("response upon checking SIGA needs " \
"is 0x%x. Using all SIGAs for sch 0.%x.%x.\n",
ssqd_area->response.code,
irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
goto out;
}
if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) ||
!(ssqd_area->flags & CHSC_FLAG_VALIDITY) ||
(ssqd_area->sch != irq_ptr->schid.sch_no)) {
QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \
"using all SIGAs.\n",
irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */
irq_ptr->is_qebsm = 0;
goto out;
}
qdioac = ssqd_area->qdioac1;
out:
qdio_check_subchannel_qebsm(irq_ptr, qdioac,
ssqd_area->sch_token);
mempool_free(ssqd_area, qdio_mempool_scssc);
irq_ptr->qdioac = qdioac;
qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token);
if (rc != -ENOMEM)
mempool_free(ssqd_area, qdio_mempool_scssc);
}
static unsigned int
......@@ -3227,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data)
return -EIO;
}
qdio_get_ssqd_information(irq_ptr);
qdio_get_ssqd_siga(irq_ptr);
/* if this gets set once, we're running under VM and can omit SVSes */
if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY)
omit_svs=1;
......
......@@ -406,6 +406,34 @@ do_clear_global_summary(void)
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
struct qdio_chsc_ssqd {
struct chsc_header request;
u16 reserved1:10;
u16 ssid:2;
u16 fmt:4;
u16 first_sch;
u16 reserved2;
u16 last_sch;
u32 reserved3;
struct chsc_header response;
u32 reserved4;
u8 flags;
u8 reserved5;
u16 sch;
u8 qfmt;
u8 parm;
u8 qdioac1;
u8 sch_class;
u8 pct;
u8 icnt;
u8 reserved7;
u8 ocnt;
u8 reserved8;
u8 mbccnt;
u16 qdioac2;
u64 sch_token;
};
struct qdio_perf_stats {
#ifdef CONFIG_64BIT
atomic64_t tl_runs;
......
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