xref: /kvm-unit-tests/s390x/css.c (revision d6c5a00e8cd1b71fa53649ea393b3bc6145c871d)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Channel Subsystem tests
4  *
5  * Copyright (c) 2020 IBM Corp
6  *
7  * Authors:
8  *  Pierre Morel <pmorel@linux.ibm.com>
9  */
10 
11 #include <libcflat.h>
12 #include <alloc_phys.h>
13 #include <asm/page.h>
14 #include <string.h>
15 #include <interrupt.h>
16 #include <asm/arch_def.h>
17 #include <alloc_page.h>
18 
19 #include <malloc_io.h>
20 #include <css.h>
21 #include <asm/barrier.h>
22 
23 #define DEFAULT_CU_TYPE		0x3832 /* virtio-ccw */
24 static unsigned long cu_type = DEFAULT_CU_TYPE;
25 
26 static int test_device_sid;
27 static struct senseid *senseid;
28 struct ccw1 *ccw;
29 
30 static void test_enumerate(void)
31 {
32 	test_device_sid = css_enumerate();
33 	if (test_device_sid & SCHID_ONE) {
34 		report(1, "Schid of first I/O device: 0x%08x", test_device_sid);
35 		return;
36 	}
37 	report(0, "No I/O device found");
38 }
39 
40 static void test_enable(void)
41 {
42 	int cc;
43 
44 	if (!test_device_sid) {
45 		report_skip("No device");
46 		return;
47 	}
48 
49 	cc = css_enable(test_device_sid, IO_SCH_ISC);
50 
51 	report(cc == 0, "Enable subchannel %08x", test_device_sid);
52 }
53 
54 /*
55  * test_sense
56  * Pre-requisites:
57  * - We need the test device as the first recognized
58  *   device by the enumeration.
59  */
60 static void test_sense(void)
61 {
62 	int ret;
63 	int len;
64 
65 	if (!test_device_sid) {
66 		report_skip("No device");
67 		return;
68 	}
69 
70 	ret = css_enable(test_device_sid, IO_SCH_ISC);
71 	if (ret) {
72 		report(0, "Could not enable the subchannel: %08x",
73 		       test_device_sid);
74 		return;
75 	}
76 
77 	lowcore_ptr->io_int_param = 0;
78 
79 	senseid = alloc_io_mem(sizeof(*senseid), 0);
80 	if (!senseid) {
81 		report(0, "Allocation of senseid");
82 		return;
83 	}
84 
85 	ccw = ccw_alloc(CCW_CMD_SENSE_ID, senseid, sizeof(*senseid), CCW_F_SLI);
86 	if (!ccw) {
87 		report(0, "Allocation of CCW");
88 		goto error_ccw;
89 	}
90 
91 	ret = start_ccw1_chain(test_device_sid, ccw);
92 	if (ret) {
93 		report(0, "Starting CCW chain");
94 		goto error;
95 	}
96 
97 	if (wait_and_check_io_completion(test_device_sid) < 0)
98 		goto error;
99 
100 	/* Test transfer completion */
101 	report_prefix_push("ssch transfer completion");
102 
103 	ret = css_residual_count(test_device_sid);
104 
105 	if (ret < 0) {
106 		report_info("no valid residual count");
107 	} else if (ret != 0) {
108 		len = sizeof(*senseid) - ret;
109 		if (ret && len < CSS_SENSEID_COMMON_LEN) {
110 			report(0, "transferred a too short length: %d", ret);
111 			goto error;
112 		} else if (ret && len)
113 			report_info("transferred a shorter length: %d", len);
114 	}
115 
116 	if (senseid->reserved != 0xff) {
117 		report(0, "transferred garbage: 0x%02x", senseid->reserved);
118 		goto error;
119 	}
120 
121 	report_prefix_pop();
122 
123 	report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x",
124 		    senseid->reserved, senseid->cu_type, senseid->cu_model,
125 		    senseid->dev_type, senseid->dev_model);
126 
127 	report(senseid->cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x",
128 	       (uint16_t)cu_type, senseid->cu_type);
129 
130 error:
131 	free_io_mem(ccw, sizeof(*ccw));
132 error_ccw:
133 	free_io_mem(senseid, sizeof(*senseid));
134 }
135 
136 static void css_init(void)
137 {
138 	assert(register_io_int_func(css_irq_io) == 0);
139 	lowcore_ptr->io_int_param = 0;
140 
141 	report(get_chsc_scsc(), "Store Channel Characteristics");
142 }
143 
144 static void test_schm(void)
145 {
146 	if (css_test_general_feature(CSSC_EXTENDED_MEASUREMENT_BLOCK))
147 		report_info("Extended measurement block available");
148 
149 	/* bits 59-63 of MB address must be 0  if MBU is defined */
150 	report_prefix_push("Unaligned operand");
151 	expect_pgm_int();
152 	schm((void *)0x01, SCHM_MBU);
153 	check_pgm_int_code(PGM_INT_CODE_OPERAND);
154 	report_prefix_pop();
155 
156 	/* bits 36-61 of register 1 (flags) must be 0 */
157 	report_prefix_push("Bad flags");
158 	expect_pgm_int();
159 	schm(NULL, 0xfffffffc);
160 	check_pgm_int_code(PGM_INT_CODE_OPERAND);
161 	report_prefix_pop();
162 
163 	/* SCHM is a privilege operation */
164 	report_prefix_push("Privilege");
165 	enter_pstate();
166 	expect_pgm_int();
167 	schm(NULL, SCHM_MBU);
168 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
169 	report_prefix_pop();
170 
171 	/* Normal operation */
172 	report_prefix_push("Normal operation");
173 	schm(NULL, SCHM_MBU);
174 	report(1, "SCHM call without address");
175 	report_prefix_pop();
176 }
177 
178 static struct {
179 	const char *name;
180 	void (*func)(void);
181 } tests[] = {
182 	/* The css_init test is needed to initialize the CSS Characteristics */
183 	{ "initialize CSS (chsc)", css_init },
184 	{ "enumerate (stsch)", test_enumerate },
185 	{ "enable (msch)", test_enable },
186 	{ "sense (ssch/tsch)", test_sense },
187 	{ "measurement block (schm)", test_schm },
188 	{ NULL, NULL }
189 };
190 
191 int main(int argc, char *argv[])
192 {
193 	int i;
194 
195 	report_prefix_push("Channel Subsystem");
196 	enable_io_isc(0x80 >> IO_SCH_ISC);
197 	for (i = 0; tests[i].name; i++) {
198 		report_prefix_push(tests[i].name);
199 		tests[i].func();
200 		report_prefix_pop();
201 	}
202 	report_prefix_pop();
203 
204 	return report_summary();
205 }
206