xref: /kvm-unit-tests/lib/s390x/css_lib.c (revision d3d7fa5a1bf32986bf703d91a1b87683e3b3fd46)
16c9f99dfSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
23227b5a6SPierre Morel /*
33227b5a6SPierre Morel  * Channel Subsystem tests library
43227b5a6SPierre Morel  *
53227b5a6SPierre Morel  * Copyright (c) 2020 IBM Corp
63227b5a6SPierre Morel  *
73227b5a6SPierre Morel  * Authors:
83227b5a6SPierre Morel  *  Pierre Morel <pmorel@linux.ibm.com>
93227b5a6SPierre Morel  */
103227b5a6SPierre Morel #include <libcflat.h>
113227b5a6SPierre Morel #include <alloc_phys.h>
123227b5a6SPierre Morel #include <asm/page.h>
133227b5a6SPierre Morel #include <string.h>
143227b5a6SPierre Morel #include <interrupt.h>
153227b5a6SPierre Morel #include <asm/arch_def.h>
16551e6622SPierre Morel #include <asm/time.h>
178cb729e4SPierre Morel #include <asm/arch_def.h>
187fbcef02SPierre Morel #include <alloc_page.h>
19a6e5e596SPierre Morel #include <malloc_io.h>
203227b5a6SPierre Morel #include <css.h>
213227b5a6SPierre Morel 
223227b5a6SPierre Morel static struct schib schib;
237fbcef02SPierre Morel struct chsc_scsc *chsc_scsc;
247fbcef02SPierre Morel 
257fbcef02SPierre Morel static const char * const chsc_rsp_description[] = {
267fbcef02SPierre Morel 	"CHSC unknown error",
277fbcef02SPierre Morel 	"Command executed",
287fbcef02SPierre Morel 	"Invalid command",
297fbcef02SPierre Morel 	"Request-block error",
307fbcef02SPierre Morel 	"Command not installed",
317fbcef02SPierre Morel 	"Data not available",
327fbcef02SPierre Morel 	"Absolute address of channel-subsystem communication block exceeds 2G - 1.",
337fbcef02SPierre Morel 	"Invalid command format",
347fbcef02SPierre Morel 	"Invalid channel-subsystem identification (CSSID)",
357fbcef02SPierre Morel 	"The command-request block specified an invalid format for the command response block.",
367fbcef02SPierre Morel 	"Invalid subchannel-set identification (SSID)",
377fbcef02SPierre Morel 	"A busy condition precludes execution.",
387fbcef02SPierre Morel };
397fbcef02SPierre Morel 
407fbcef02SPierre Morel static bool check_response(void *p)
417fbcef02SPierre Morel {
427fbcef02SPierre Morel 	struct chsc_header *h = p;
437fbcef02SPierre Morel 
447fbcef02SPierre Morel 	if (h->code == CHSC_RSP_OK)
457fbcef02SPierre Morel 		return true;
467fbcef02SPierre Morel 
477fbcef02SPierre Morel 	if (h->code > CHSC_RSP_MAX)
487fbcef02SPierre Morel 		h->code = 0;
497fbcef02SPierre Morel 
507fbcef02SPierre Morel 	report_abort("Response code %04x: %s", h->code,
517fbcef02SPierre Morel 		      chsc_rsp_description[h->code]);
527fbcef02SPierre Morel 	return false;
537fbcef02SPierre Morel }
547fbcef02SPierre Morel 
557fbcef02SPierre Morel bool chsc(void *p, uint16_t code, uint16_t len)
567fbcef02SPierre Morel {
577fbcef02SPierre Morel 	struct chsc_header *h = p;
587fbcef02SPierre Morel 
597fbcef02SPierre Morel 	h->code = code;
607fbcef02SPierre Morel 	h->len = len;
617fbcef02SPierre Morel 
627fbcef02SPierre Morel 	switch (_chsc(p)) {
637fbcef02SPierre Morel 	case 3:
647fbcef02SPierre Morel 		report_abort("Subchannel invalid or not enabled.");
657fbcef02SPierre Morel 		break;
667fbcef02SPierre Morel 	case 2:
677fbcef02SPierre Morel 		report_abort("CHSC subchannel busy.");
687fbcef02SPierre Morel 		break;
697fbcef02SPierre Morel 	case 1:
707fbcef02SPierre Morel 		report_abort("Subchannel invalid or not enabled.");
717fbcef02SPierre Morel 		break;
727fbcef02SPierre Morel 	case 0:
737fbcef02SPierre Morel 		return check_response(p + len);
747fbcef02SPierre Morel 	}
757fbcef02SPierre Morel 	return false;
767fbcef02SPierre Morel }
777fbcef02SPierre Morel 
787fbcef02SPierre Morel bool get_chsc_scsc(void)
797fbcef02SPierre Morel {
807fbcef02SPierre Morel 	int i, n;
817fbcef02SPierre Morel 	char buffer[510];
827fbcef02SPierre Morel 	char *p;
837fbcef02SPierre Morel 
847fbcef02SPierre Morel 	if (chsc_scsc) /* chsc_scsc already initialized */
857fbcef02SPierre Morel 		return true;
867fbcef02SPierre Morel 
877fbcef02SPierre Morel 	chsc_scsc = alloc_page();
887fbcef02SPierre Morel 	if (!chsc_scsc) {
897fbcef02SPierre Morel 		report_abort("could not allocate chsc_scsc page!");
907fbcef02SPierre Morel 		return false;
917fbcef02SPierre Morel 	}
927fbcef02SPierre Morel 
937fbcef02SPierre Morel 	if (!chsc(chsc_scsc, CHSC_SCSC, CHSC_SCSC_LEN))
947fbcef02SPierre Morel 		return false;
957fbcef02SPierre Morel 
967fbcef02SPierre Morel 	for (i = 0, p = buffer; i < CSS_GENERAL_FEAT_BITLEN; i++) {
977fbcef02SPierre Morel 		if (css_test_general_feature(i)) {
987fbcef02SPierre Morel 			n = snprintf(p, sizeof(buffer), "%d,", i);
997fbcef02SPierre Morel 			p += n;
1007fbcef02SPierre Morel 		}
1017fbcef02SPierre Morel 	}
1027fbcef02SPierre Morel 	report_info("General features: %s", buffer);
1037fbcef02SPierre Morel 
1047fbcef02SPierre Morel 	for (i = 0, p = buffer; i < CSS_CHSC_FEAT_BITLEN; i++) {
1057fbcef02SPierre Morel 		if (css_test_chsc_feature(i)) {
1067fbcef02SPierre Morel 			n = snprintf(p, sizeof(buffer), "%d,", i);
1077fbcef02SPierre Morel 			p += n;
1087fbcef02SPierre Morel 		}
1097fbcef02SPierre Morel 	}
1107fbcef02SPierre Morel 	report_info("CHSC features: %s", buffer);
1117fbcef02SPierre Morel 
1127fbcef02SPierre Morel 	return true;
1137fbcef02SPierre Morel }
1143227b5a6SPierre Morel 
1153227b5a6SPierre Morel /*
1163227b5a6SPierre Morel  * css_enumerate:
1173227b5a6SPierre Morel  * On success return the first subchannel ID found.
1183227b5a6SPierre Morel  * On error return an invalid subchannel ID containing cc
1193227b5a6SPierre Morel  */
1203227b5a6SPierre Morel int css_enumerate(void)
1213227b5a6SPierre Morel {
1223227b5a6SPierre Morel 	struct pmcw *pmcw = &schib.pmcw;
1233227b5a6SPierre Morel 	int scn_found = 0;
1243227b5a6SPierre Morel 	int dev_found = 0;
1253227b5a6SPierre Morel 	int schid = 0;
1263227b5a6SPierre Morel 	int cc;
1273227b5a6SPierre Morel 	int scn;
1283227b5a6SPierre Morel 
1293227b5a6SPierre Morel 	for (scn = 0; scn < 0xffff; scn++) {
1303227b5a6SPierre Morel 		cc = stsch(scn | SCHID_ONE, &schib);
1313227b5a6SPierre Morel 		switch (cc) {
1323227b5a6SPierre Morel 		case 0:		/* 0 means SCHIB stored */
1333227b5a6SPierre Morel 			break;
1343227b5a6SPierre Morel 		case 3:		/* 3 means no more channels */
1353227b5a6SPierre Morel 			goto out;
1363227b5a6SPierre Morel 		default:	/* 1 or 2 should never happen for STSCH */
1373227b5a6SPierre Morel 			report_abort("Unexpected error %d on subchannel %08x",
1383227b5a6SPierre Morel 				     cc, scn | SCHID_ONE);
1393227b5a6SPierre Morel 			return cc;
1403227b5a6SPierre Morel 		}
1413227b5a6SPierre Morel 
1423227b5a6SPierre Morel 		/* We currently only support type 0, a.k.a. I/O channels */
1433227b5a6SPierre Morel 		if (PMCW_CHANNEL_TYPE(pmcw) != 0)
1443227b5a6SPierre Morel 			continue;
1453227b5a6SPierre Morel 
1463227b5a6SPierre Morel 		/* We ignore I/O channels without valid devices */
1473227b5a6SPierre Morel 		scn_found++;
1483227b5a6SPierre Morel 		if (!(pmcw->flags & PMCW_DNV))
1493227b5a6SPierre Morel 			continue;
1503227b5a6SPierre Morel 
1513227b5a6SPierre Morel 		/* We keep track of the first device as our test device */
1523227b5a6SPierre Morel 		if (!schid)
1533227b5a6SPierre Morel 			schid = scn | SCHID_ONE;
1543227b5a6SPierre Morel 		report_info("Found subchannel %08x", scn | SCHID_ONE);
1553227b5a6SPierre Morel 		dev_found++;
1563227b5a6SPierre Morel 	}
1573227b5a6SPierre Morel 
1583227b5a6SPierre Morel out:
1593227b5a6SPierre Morel 	report_info("Tested subchannels: %d, I/O subchannels: %d, I/O devices: %d",
1603227b5a6SPierre Morel 		    scn, scn_found, dev_found);
1613227b5a6SPierre Morel 	return schid;
1623227b5a6SPierre Morel }
163551e6622SPierre Morel 
164551e6622SPierre Morel /*
165*d3d7fa5aSPierre Morel  * css_enabled: report if the subchannel is enabled
166*d3d7fa5aSPierre Morel  * @schid: Subchannel Identifier
167*d3d7fa5aSPierre Morel  * Return value:
168*d3d7fa5aSPierre Morel  *   true if the subchannel is enabled
169*d3d7fa5aSPierre Morel  *   false otherwise
170*d3d7fa5aSPierre Morel  */
171*d3d7fa5aSPierre Morel bool css_enabled(int schid)
172*d3d7fa5aSPierre Morel {
173*d3d7fa5aSPierre Morel 	struct pmcw *pmcw = &schib.pmcw;
174*d3d7fa5aSPierre Morel 	int cc;
175*d3d7fa5aSPierre Morel 
176*d3d7fa5aSPierre Morel 	cc = stsch(schid, &schib);
177*d3d7fa5aSPierre Morel 	if (cc) {
178*d3d7fa5aSPierre Morel 		report_info("stsch: updating sch %08x failed with cc=%d",
179*d3d7fa5aSPierre Morel 			    schid, cc);
180*d3d7fa5aSPierre Morel 		return false;
181*d3d7fa5aSPierre Morel 	}
182*d3d7fa5aSPierre Morel 
183*d3d7fa5aSPierre Morel 	if (!(pmcw->flags & PMCW_ENABLE)) {
184*d3d7fa5aSPierre Morel 		report_info("stsch: sch %08x not enabled", schid);
185*d3d7fa5aSPierre Morel 		return false;
186*d3d7fa5aSPierre Morel 	}
187*d3d7fa5aSPierre Morel 	return true;
188*d3d7fa5aSPierre Morel }
189*d3d7fa5aSPierre Morel /*
190551e6622SPierre Morel  * css_enable: enable the subchannel with the specified ISC
191551e6622SPierre Morel  * @schid: Subchannel Identifier
192551e6622SPierre Morel  * @isc  : number of the interruption subclass to use
193551e6622SPierre Morel  * Return value:
194551e6622SPierre Morel  *   On success: 0
195551e6622SPierre Morel  *   On error the CC of the faulty instruction
196551e6622SPierre Morel  *      or -1 if the retry count is exceeded.
197551e6622SPierre Morel  */
198551e6622SPierre Morel int css_enable(int schid, int isc)
199551e6622SPierre Morel {
200551e6622SPierre Morel 	struct pmcw *pmcw = &schib.pmcw;
201551e6622SPierre Morel 	int retry_count = 0;
202551e6622SPierre Morel 	uint16_t flags;
203551e6622SPierre Morel 	int cc;
204551e6622SPierre Morel 
205551e6622SPierre Morel 	/* Read the SCHIB for this subchannel */
206551e6622SPierre Morel 	cc = stsch(schid, &schib);
207551e6622SPierre Morel 	if (cc) {
208551e6622SPierre Morel 		report_info("stsch: sch %08x failed with cc=%d", schid, cc);
209551e6622SPierre Morel 		return cc;
210551e6622SPierre Morel 	}
211551e6622SPierre Morel 
212551e6622SPierre Morel 	flags = PMCW_ENABLE | (isc << PMCW_ISC_SHIFT);
213551e6622SPierre Morel 	if ((pmcw->flags & (PMCW_ISC_MASK | PMCW_ENABLE)) == flags) {
214551e6622SPierre Morel 		report_info("stsch: sch %08x already enabled", schid);
215551e6622SPierre Morel 		return 0;
216551e6622SPierre Morel 	}
217551e6622SPierre Morel 
218551e6622SPierre Morel retry:
219551e6622SPierre Morel 	/* Update the SCHIB to enable the channel and set the ISC */
220551e6622SPierre Morel 	pmcw->flags &= ~PMCW_ISC_MASK;
221551e6622SPierre Morel 	pmcw->flags |= flags;
222551e6622SPierre Morel 
223551e6622SPierre Morel 	/* Tell the CSS we want to modify the subchannel */
224551e6622SPierre Morel 	cc = msch(schid, &schib);
225551e6622SPierre Morel 	if (cc) {
226551e6622SPierre Morel 		/*
227551e6622SPierre Morel 		 * If the subchannel is status pending or
228551e6622SPierre Morel 		 * if a function is in progress,
229551e6622SPierre Morel 		 * we consider both cases as errors.
230551e6622SPierre Morel 		 */
231551e6622SPierre Morel 		report_info("msch: sch %08x failed with cc=%d", schid, cc);
232551e6622SPierre Morel 		return cc;
233551e6622SPierre Morel 	}
234551e6622SPierre Morel 
235551e6622SPierre Morel 	/*
236551e6622SPierre Morel 	 * Read the SCHIB again to verify the enablement
237551e6622SPierre Morel 	 */
238*d3d7fa5aSPierre Morel 	if (css_enabled(schid))
239551e6622SPierre Morel 		return 0;
240551e6622SPierre Morel 
241551e6622SPierre Morel 	if (retry_count++ < MAX_ENABLE_RETRIES) {
242551e6622SPierre Morel 		mdelay(10); /* the hardware was not ready, give it some time */
243551e6622SPierre Morel 		goto retry;
244551e6622SPierre Morel 	}
245551e6622SPierre Morel 
246551e6622SPierre Morel 	report_info("msch: modifying sch %08x failed after %d retries. pmcw flags: %04x",
247551e6622SPierre Morel 		    schid, retry_count, pmcw->flags);
248551e6622SPierre Morel 	return -1;
249551e6622SPierre Morel }
2508cb729e4SPierre Morel 
2518cb729e4SPierre Morel static struct irb irb;
2528cb729e4SPierre Morel 
2538cb729e4SPierre Morel void css_irq_io(void)
2548cb729e4SPierre Morel {
2558cb729e4SPierre Morel 	int ret = 0;
2568cb729e4SPierre Morel 	char *flags;
2578cb729e4SPierre Morel 	int sid;
2588cb729e4SPierre Morel 
2598cb729e4SPierre Morel 	report_prefix_push("Interrupt");
2608cb729e4SPierre Morel 	sid = lowcore_ptr->subsys_id_word;
2618cb729e4SPierre Morel 	/* Lowlevel set the SID as interrupt parameter. */
2628cb729e4SPierre Morel 	if (lowcore_ptr->io_int_param != sid) {
2638cb729e4SPierre Morel 		report(0,
2648cb729e4SPierre Morel 		       "io_int_param: %x differs from subsys_id_word: %x",
2658cb729e4SPierre Morel 		       lowcore_ptr->io_int_param, sid);
2668cb729e4SPierre Morel 		goto pop;
2678cb729e4SPierre Morel 	}
2688cb729e4SPierre Morel 	report_prefix_pop();
2698cb729e4SPierre Morel 
2708cb729e4SPierre Morel 	report_prefix_push("tsch");
2718cb729e4SPierre Morel 	ret = tsch(sid, &irb);
2728cb729e4SPierre Morel 	switch (ret) {
2738cb729e4SPierre Morel 	case 1:
2748cb729e4SPierre Morel 		dump_irb(&irb);
2758cb729e4SPierre Morel 		flags = dump_scsw_flags(irb.scsw.ctrl);
2768cb729e4SPierre Morel 		report(0,
2778cb729e4SPierre Morel 		       "I/O interrupt, but tsch returns CC 1 for subchannel %08x. SCSW flags: %s",
2788cb729e4SPierre Morel 		       sid, flags);
2798cb729e4SPierre Morel 		break;
2808cb729e4SPierre Morel 	case 2:
2818cb729e4SPierre Morel 		report(0, "tsch returns unexpected CC 2");
2828cb729e4SPierre Morel 		break;
2838cb729e4SPierre Morel 	case 3:
2848cb729e4SPierre Morel 		report(0, "tsch reporting sch %08x as not operational", sid);
2858cb729e4SPierre Morel 		break;
2868cb729e4SPierre Morel 	case 0:
2878cb729e4SPierre Morel 		/* Stay humble on success */
2888cb729e4SPierre Morel 		break;
2898cb729e4SPierre Morel 	}
2908cb729e4SPierre Morel pop:
2918cb729e4SPierre Morel 	report_prefix_pop();
2928cb729e4SPierre Morel 	lowcore_ptr->io_old_psw.mask &= ~PSW_MASK_WAIT;
2938cb729e4SPierre Morel }
2948cb729e4SPierre Morel 
2958cb729e4SPierre Morel int start_ccw1_chain(unsigned int sid, struct ccw1 *ccw)
2968cb729e4SPierre Morel {
2978cb729e4SPierre Morel 	struct orb orb = {
2988cb729e4SPierre Morel 		.intparm = sid,
2998cb729e4SPierre Morel 		.ctrl = ORB_CTRL_ISIC|ORB_CTRL_FMT|ORB_LPM_DFLT,
3008cb729e4SPierre Morel 		.cpa = (unsigned int) (unsigned long)ccw,
3018cb729e4SPierre Morel 	};
3028cb729e4SPierre Morel 
3038cb729e4SPierre Morel 	return ssch(sid, &orb);
3048cb729e4SPierre Morel }
3058cb729e4SPierre Morel 
306a6e5e596SPierre Morel struct ccw1 *ccw_alloc(int code, void *data, int count, unsigned char flags)
3078cb729e4SPierre Morel {
308a6e5e596SPierre Morel 	struct ccw1 *ccw;
3098cb729e4SPierre Morel 
310a6e5e596SPierre Morel 	ccw = alloc_io_mem(sizeof(*ccw), 0);
311a6e5e596SPierre Morel 	if (!ccw)
312a6e5e596SPierre Morel 		return NULL;
313a6e5e596SPierre Morel 
3148cb729e4SPierre Morel 	ccw->code = code;
3158cb729e4SPierre Morel 	ccw->flags = flags;
3168cb729e4SPierre Morel 	ccw->count = count;
3178cb729e4SPierre Morel 	ccw->data_address = (int)(unsigned long)data;
3188cb729e4SPierre Morel 
319a6e5e596SPierre Morel 	return ccw;
3208cb729e4SPierre Morel }
3218cb729e4SPierre Morel 
3228cb729e4SPierre Morel /* wait_and_check_io_completion:
3238cb729e4SPierre Morel  * @schid: the subchannel ID
3248cb729e4SPierre Morel  *
3258cb729e4SPierre Morel  * Makes the most common check to validate a successful I/O
3268cb729e4SPierre Morel  * completion.
3278cb729e4SPierre Morel  * Only report failures.
3288cb729e4SPierre Morel  */
3298cb729e4SPierre Morel int wait_and_check_io_completion(int schid)
3308cb729e4SPierre Morel {
3318cb729e4SPierre Morel 	int ret = 0;
3328cb729e4SPierre Morel 
3338cb729e4SPierre Morel 	wait_for_interrupt(PSW_MASK_IO);
3348cb729e4SPierre Morel 
3358cb729e4SPierre Morel 	report_prefix_push("check I/O completion");
3368cb729e4SPierre Morel 
3378cb729e4SPierre Morel 	if (lowcore_ptr->io_int_param != schid) {
3388cb729e4SPierre Morel 		report(0, "interrupt parameter: expected %08x got %08x",
3398cb729e4SPierre Morel 		       schid, lowcore_ptr->io_int_param);
3408cb729e4SPierre Morel 		ret = -1;
3418cb729e4SPierre Morel 		goto end;
3428cb729e4SPierre Morel 	}
3438cb729e4SPierre Morel 
3448cb729e4SPierre Morel 	/* Verify that device status is valid */
3458cb729e4SPierre Morel 	if (!(irb.scsw.ctrl & SCSW_SC_PENDING)) {
3468cb729e4SPierre Morel 		report(0, "No status pending after interrupt. Subch Ctrl: %08x",
3478cb729e4SPierre Morel 		       irb.scsw.ctrl);
3488cb729e4SPierre Morel 		ret = -1;
3498cb729e4SPierre Morel 		goto end;
3508cb729e4SPierre Morel 	}
3518cb729e4SPierre Morel 
3528cb729e4SPierre Morel 	if (!(irb.scsw.ctrl & (SCSW_SC_SECONDARY | SCSW_SC_PRIMARY))) {
3538cb729e4SPierre Morel 		report(0, "Primary or secondary status missing. Subch Ctrl: %08x",
3548cb729e4SPierre Morel 		       irb.scsw.ctrl);
3558cb729e4SPierre Morel 		ret = -1;
3568cb729e4SPierre Morel 		goto end;
3578cb729e4SPierre Morel 	}
3588cb729e4SPierre Morel 
3598cb729e4SPierre Morel 	if (!(irb.scsw.dev_stat & (SCSW_DEVS_DEV_END | SCSW_DEVS_SCH_END))) {
3608cb729e4SPierre Morel 		report(0, "No device end or sch end. Dev. status: %02x",
3618cb729e4SPierre Morel 		       irb.scsw.dev_stat);
3628cb729e4SPierre Morel 		ret = -1;
3638cb729e4SPierre Morel 		goto end;
3648cb729e4SPierre Morel 	}
3658cb729e4SPierre Morel 
3668cb729e4SPierre Morel 	if (irb.scsw.sch_stat & ~SCSW_SCHS_IL) {
3678cb729e4SPierre Morel 		report_info("Unexpected Subch. status %02x", irb.scsw.sch_stat);
3688cb729e4SPierre Morel 		ret = -1;
3698cb729e4SPierre Morel 		goto end;
3708cb729e4SPierre Morel 	}
3718cb729e4SPierre Morel 
3728cb729e4SPierre Morel end:
3738cb729e4SPierre Morel 	report_prefix_pop();
3748cb729e4SPierre Morel 	return ret;
3758cb729e4SPierre Morel }
3768cb729e4SPierre Morel 
3778cb729e4SPierre Morel /*
3788cb729e4SPierre Morel  * css_residual_count
3798cb729e4SPierre Morel  * Return the residual count, if it is valid.
3808cb729e4SPierre Morel  *
3818cb729e4SPierre Morel  * Return value:
3828cb729e4SPierre Morel  * Success: the residual count
3838cb729e4SPierre Morel  * Not meaningful: -1 (-1 can not be a valid count)
3848cb729e4SPierre Morel  */
3858cb729e4SPierre Morel int css_residual_count(unsigned int schid)
3868cb729e4SPierre Morel {
3878cb729e4SPierre Morel 
3888cb729e4SPierre Morel 	if (!(irb.scsw.ctrl & (SCSW_SC_PENDING | SCSW_SC_PRIMARY)))
3898cb729e4SPierre Morel 		return -1;
3908cb729e4SPierre Morel 
3918cb729e4SPierre Morel 	if (irb.scsw.dev_stat)
3928cb729e4SPierre Morel 		if (irb.scsw.sch_stat & ~(SCSW_SCHS_PCI | SCSW_SCHS_IL))
3938cb729e4SPierre Morel 			return -1;
3948cb729e4SPierre Morel 
3958cb729e4SPierre Morel 	return irb.scsw.count;
3968cb729e4SPierre Morel }
3978cb729e4SPierre Morel 
3988cb729e4SPierre Morel /*
3998cb729e4SPierre Morel  * enable_io_isc: setup ISC in Control Register 6
4008cb729e4SPierre Morel  * @isc: The interruption Sub Class as a bitfield
4018cb729e4SPierre Morel  */
4028cb729e4SPierre Morel void enable_io_isc(uint8_t isc)
4038cb729e4SPierre Morel {
4048cb729e4SPierre Morel 	uint64_t value;
4058cb729e4SPierre Morel 
4068cb729e4SPierre Morel 	value = (uint64_t)isc << 24;
4078cb729e4SPierre Morel 	lctlg(6, value);
4088cb729e4SPierre Morel }
409