[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: Ursula Braun <braunu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
Родитель
2a2cf6b186
Коммит
e177685628
|
@ -2217,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
|
||||||
return cc;
|
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
|
static void
|
||||||
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
|
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token)
|
||||||
unsigned long token)
|
|
||||||
{
|
{
|
||||||
struct qdio_q *q;
|
struct qdio_q *q;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2227,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
|
||||||
char dbf_text[15];
|
char dbf_text[15];
|
||||||
|
|
||||||
/*check if QEBSM is disabled */
|
/*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->is_qebsm = 0;
|
||||||
irq_ptr->sch_token = 0;
|
irq_ptr->sch_token = 0;
|
||||||
irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
|
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
|
static void
|
||||||
qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
|
qdio_get_ssqd_siga(struct qdio_irq *irq_ptr)
|
||||||
{
|
{
|
||||||
int result;
|
int rc;
|
||||||
unsigned char qdioac;
|
struct qdio_chsc_ssqd *ssqd_area;
|
||||||
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;
|
|
||||||
|
|
||||||
QDIO_DBF_TEXT0(0,setup,"getssqd");
|
QDIO_DBF_TEXT0(0,setup,"getssqd");
|
||||||
qdioac = 0;
|
irq_ptr->qdioac = 0;
|
||||||
ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
|
rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area);
|
||||||
if (!ssqd_area) {
|
if (rc) {
|
||||||
QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
|
QDIO_PRINT_WARN("using all SIGAs for sch x%x.n",
|
||||||
"SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
|
irq_ptr->schid.sch_no);
|
||||||
irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
|
irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
|
||||||
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
|
CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
|
||||||
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
|
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
|
||||||
irq_ptr->is_qebsm = 0;
|
irq_ptr->is_qebsm = 0;
|
||||||
irq_ptr->sch_token = 0;
|
} else
|
||||||
irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
|
irq_ptr->qdioac = ssqd_area->qdioac1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssqd_area->request = (struct chsc_header) {
|
qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token);
|
||||||
.length = 0x0010,
|
if (rc != -ENOMEM)
|
||||||
.code = 0x0024,
|
mempool_free(ssqd_area, qdio_mempool_scssc);
|
||||||
};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
@ -3227,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data)
|
||||||
return -EIO;
|
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 this gets set once, we're running under VM and can omit SVSes */
|
||||||
if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY)
|
if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY)
|
||||||
omit_svs=1;
|
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_THININTS 0x08
|
||||||
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
|
#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 {
|
struct qdio_perf_stats {
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
atomic64_t tl_runs;
|
atomic64_t tl_runs;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче