Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+86 −92
Original line number Diff line number Diff line
@@ -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);
	qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token);
	if (rc != -ENOMEM)
		mempool_free(ssqd_area, qdio_mempool_scssc);
	irq_ptr->qdioac = qdioac;
}

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;
+28 −0
Original line number Diff line number Diff line
@@ -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;