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 char alignment_test_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 31 32 static void test_enumerate(void) 33 { 34 test_device_sid = css_enumerate(); 35 if (test_device_sid & SCHID_ONE) { 36 report_pass("Schid of first I/O device: 0x%08x", test_device_sid); 37 return; 38 } 39 report_fail("No I/O device found"); 40 } 41 42 static void test_enable(void) 43 { 44 int cc; 45 46 if (!test_device_sid) { 47 report_skip("No device"); 48 return; 49 } 50 51 cc = css_enable(test_device_sid, IO_SCH_ISC); 52 53 report(cc == 0, "Enable subchannel %08x", test_device_sid); 54 } 55 56 /* 57 * test_sense 58 * Pre-requisites: 59 * - We need the test device as the first recognized 60 * device by the enumeration. 61 */ 62 static void test_sense(void) 63 { 64 int ret; 65 int len; 66 67 if (!test_device_sid) { 68 report_skip("No device"); 69 return; 70 } 71 72 ret = css_enable(test_device_sid, IO_SCH_ISC); 73 if (ret) { 74 report_fail("Could not enable the subchannel: %08x", 75 test_device_sid); 76 return; 77 } 78 79 lowcore_ptr->io_int_param = 0; 80 81 senseid = alloc_io_mem(sizeof(*senseid), 0); 82 if (!senseid) { 83 report_fail("Allocation of senseid"); 84 return; 85 } 86 87 ccw = ccw_alloc(CCW_CMD_SENSE_ID, senseid, sizeof(*senseid), CCW_F_SLI); 88 if (!ccw) { 89 report_fail("Allocation of CCW"); 90 goto error_ccw; 91 } 92 93 ret = start_ccw1_chain(test_device_sid, ccw); 94 if (ret) { 95 report_fail("Starting CCW chain"); 96 goto error; 97 } 98 99 if (wait_and_check_io_completion(test_device_sid) < 0) 100 goto error; 101 102 /* Test transfer completion */ 103 report_prefix_push("ssch transfer completion"); 104 105 ret = css_residual_count(test_device_sid); 106 107 if (ret < 0) { 108 report_info("no valid residual count"); 109 } else if (ret != 0) { 110 len = sizeof(*senseid) - ret; 111 if (ret && len < CSS_SENSEID_COMMON_LEN) { 112 report_fail("transferred a too short length: %d", ret); 113 goto error; 114 } else if (ret && len) 115 report_info("transferred a shorter length: %d", len); 116 } 117 118 if (senseid->reserved != 0xff) { 119 report_fail("transferred garbage: 0x%02x", senseid->reserved); 120 goto error; 121 } 122 123 report_prefix_pop(); 124 125 report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x", 126 senseid->reserved, senseid->cu_type, senseid->cu_model, 127 senseid->dev_type, senseid->dev_model); 128 129 report(senseid->cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x", 130 (uint16_t)cu_type, senseid->cu_type); 131 132 error: 133 free_io_mem(ccw, sizeof(*ccw)); 134 error_ccw: 135 free_io_mem(senseid, sizeof(*senseid)); 136 } 137 138 static void sense_id(void) 139 { 140 assert(!start_ccw1_chain(test_device_sid, ccw)); 141 142 assert(wait_and_check_io_completion(test_device_sid) >= 0); 143 } 144 145 static void css_init(void) 146 { 147 assert(register_io_int_func(css_irq_io) == 0); 148 lowcore_ptr->io_int_param = 0; 149 150 report(get_chsc_scsc(), "Store Channel Characteristics"); 151 } 152 153 static void test_schm(void) 154 { 155 if (css_test_general_feature(CSSC_EXTENDED_MEASUREMENT_BLOCK)) 156 report_info("Extended measurement block available"); 157 158 /* bits 59-63 of MB address must be 0 if MBU is defined */ 159 report_prefix_push("Unaligned operand"); 160 expect_pgm_int(); 161 schm((void *)0x01, SCHM_MBU); 162 check_pgm_int_code(PGM_INT_CODE_OPERAND); 163 report_prefix_pop(); 164 165 /* bits 36-61 of register 1 (flags) must be 0 */ 166 report_prefix_push("Bad flags"); 167 expect_pgm_int(); 168 schm(NULL, 0xfffffffc); 169 check_pgm_int_code(PGM_INT_CODE_OPERAND); 170 report_prefix_pop(); 171 172 /* SCHM is a privilege operation */ 173 report_prefix_push("Privilege"); 174 enter_pstate(); 175 expect_pgm_int(); 176 schm(NULL, SCHM_MBU); 177 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 178 report_prefix_pop(); 179 180 /* Normal operation */ 181 report_prefix_push("Normal operation"); 182 schm(NULL, SCHM_MBU); 183 report_pass("SCHM call without address"); 184 report_prefix_pop(); 185 } 186 187 #define SCHM_UPDATE_CNT 10 188 static bool start_measuring(uint64_t mbo, uint16_t mbi, bool fmt1) 189 { 190 int i; 191 192 senseid = alloc_io_mem(sizeof(*senseid), 0); 193 assert(senseid); 194 195 ccw = ccw_alloc(CCW_CMD_SENSE_ID, senseid, sizeof(*senseid), CCW_F_SLI); 196 assert(ccw); 197 198 if (!css_enable_mb(test_device_sid, mbo, mbi, PMCW_MBUE, fmt1)) { 199 report_abort("Enabling measurement block failed"); 200 return false; 201 } 202 203 for (i = 0; i < SCHM_UPDATE_CNT; i++) 204 sense_id(); 205 206 free_io_mem(ccw, sizeof(*ccw)); 207 free_io_mem(senseid, sizeof(*senseid)); 208 209 return true; 210 } 211 212 /* 213 * test_schm_fmt0: 214 * With measurement block format 0 a memory space is shared 215 * by all subchannels, each subchannel can provide an index 216 * for the measurement block facility to store the measurements. 217 */ 218 static void test_schm_fmt0(void) 219 { 220 struct measurement_block_format0 *mb0; 221 int shared_mb_size = 2 * sizeof(struct measurement_block_format0); 222 223 if (!test_device_sid) { 224 report_skip("No device"); 225 return; 226 } 227 228 /* Allocate zeroed Measurement block */ 229 mb0 = alloc_io_mem(shared_mb_size, 0); 230 if (!mb0) { 231 report_abort("measurement_block_format0 allocation failed"); 232 return; 233 } 234 235 schm(NULL, 0); /* Stop any previous measurement */ 236 schm(mb0, SCHM_MBU); 237 238 /* Expect success */ 239 report_prefix_push("Valid MB address and index 0"); 240 report(start_measuring(0, 0, false) && 241 mb0->ssch_rsch_count == SCHM_UPDATE_CNT, 242 "SSCH measured %d", mb0->ssch_rsch_count); 243 report_prefix_pop(); 244 245 /* Clear the measurement block for the next test */ 246 memset(mb0, 0, shared_mb_size); 247 248 /* Expect success */ 249 report_prefix_push("Valid MB address and index 1"); 250 if (start_measuring(0, 1, false)) 251 report(mb0[1].ssch_rsch_count == SCHM_UPDATE_CNT, 252 "SSCH measured %d", mb0[1].ssch_rsch_count); 253 report_prefix_pop(); 254 255 /* Stop the measurement */ 256 css_disable_mb(test_device_sid); 257 schm(NULL, 0); 258 259 free_io_mem(mb0, shared_mb_size); 260 } 261 262 static void msch_with_wrong_fmt1_mbo(unsigned int schid, uint64_t mb) 263 { 264 struct pmcw *pmcw = &schib.pmcw; 265 int cc; 266 267 /* Read the SCHIB for this subchannel */ 268 cc = stsch(schid, &schib); 269 if (cc) { 270 report_fail("stsch: sch %08x failed with cc=%d", schid, cc); 271 return; 272 } 273 274 /* Update the SCHIB to enable the measurement block */ 275 pmcw->flags |= PMCW_MBUE; 276 pmcw->flags2 |= PMCW_MBF1; 277 schib.mbo = mb; 278 279 /* Tell the CSS we want to modify the subchannel */ 280 expect_pgm_int(); 281 cc = msch(schid, &schib); 282 check_pgm_int_code(PGM_INT_CODE_OPERAND); 283 } 284 285 /* 286 * test_schm_fmt1: 287 * With measurement block format 1 the measurement block is 288 * dedicated to a subchannel. 289 */ 290 static void test_schm_fmt1(void) 291 { 292 struct measurement_block_format1 *mb1; 293 294 if (!test_device_sid) { 295 report_skip("No device"); 296 return; 297 } 298 299 if (!css_test_general_feature(CSSC_EXTENDED_MEASUREMENT_BLOCK)) { 300 report_skip("Extended measurement block not available"); 301 return; 302 } 303 304 /* Allocate zeroed Measurement block */ 305 mb1 = alloc_io_mem(sizeof(struct measurement_block_format1), 0); 306 if (!mb1) { 307 report_abort("measurement_block_format1 allocation failed"); 308 return; 309 } 310 311 schm(NULL, 0); /* Stop any previous measurement */ 312 schm(0, SCHM_MBU); 313 314 /* Expect error for non aligned MB */ 315 report_prefix_push("Unaligned MB origin"); 316 msch_with_wrong_fmt1_mbo(test_device_sid, (uint64_t)mb1 + 1); 317 report_prefix_pop(); 318 319 /* Clear the measurement block for the next test */ 320 memset(mb1, 0, sizeof(*mb1)); 321 322 /* Expect success */ 323 report_prefix_push("Valid MB origin"); 324 if (start_measuring((u64)mb1, 0, true)) 325 report(mb1->ssch_rsch_count == SCHM_UPDATE_CNT, 326 "SSCH measured %d", mb1->ssch_rsch_count); 327 report_prefix_pop(); 328 329 /* Stop the measurement */ 330 css_disable_mb(test_device_sid); 331 schm(NULL, 0); 332 333 free_io_mem(mb1, sizeof(struct measurement_block_format1)); 334 } 335 336 static void test_msch(void) 337 { 338 int invalid_pmcw_flags[] = {0, 1, 6, 7}; 339 struct schib test_schib; 340 uint16_t old_pmcw_flags; 341 const int align_to = 4; 342 int invalid_flag; 343 int cc; 344 345 if (!test_device_sid) { 346 report_skip("No device"); 347 return; 348 } 349 350 cc = stsch(test_device_sid, &schib); 351 if (cc) { 352 report_fail("stsch: sch %08x failed with cc=%d", test_device_sid, cc); 353 return; 354 } 355 356 report_prefix_push("Unaligned"); 357 for (int i = 1; i < align_to; i *= 2) { 358 report_prefix_pushf("%d", i); 359 360 expect_pgm_int(); 361 msch(test_device_sid, (struct schib *)(alignment_test_page + i)); 362 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 363 364 report_prefix_pop(); 365 } 366 report_prefix_pop(); 367 368 report_prefix_push("Invalid SCHIB"); 369 old_pmcw_flags = schib.pmcw.flags; 370 for (int i = 0; i < ARRAY_SIZE(invalid_pmcw_flags); i++) { 371 invalid_flag = invalid_pmcw_flags[i]; 372 373 report_prefix_pushf("PMCW flag bit %d set", invalid_flag); 374 375 schib.pmcw.flags = old_pmcw_flags | BIT(15 - invalid_flag); 376 expect_pgm_int(); 377 msch(test_device_sid, &schib); 378 check_pgm_int_code(PGM_INT_CODE_OPERAND); 379 380 cc = stsch(test_device_sid, &test_schib); 381 report(!cc, "STSCH succeeded"); 382 report(!(test_schib.pmcw.flags & BIT(15 - invalid_flag)), "Clear on STSCH"); 383 384 report_prefix_pop(); 385 } 386 report_prefix_pop(); 387 388 schib.pmcw.flags = old_pmcw_flags; 389 } 390 391 static struct { 392 const char *name; 393 void (*func)(void); 394 } tests[] = { 395 /* The css_init test is needed to initialize the CSS Characteristics */ 396 { "initialize CSS (chsc)", css_init }, 397 { "enumerate (stsch)", test_enumerate }, 398 { "enable (msch)", test_enable }, 399 { "sense (ssch/tsch)", test_sense }, 400 { "measurement block (schm)", test_schm }, 401 { "measurement block format0", test_schm_fmt0 }, 402 { "measurement block format1", test_schm_fmt1 }, 403 { "msch", test_msch }, 404 { NULL, NULL } 405 }; 406 407 int main(int argc, char *argv[]) 408 { 409 int i; 410 411 report_prefix_push("Channel Subsystem"); 412 enable_io_isc(0x80 >> IO_SCH_ISC); 413 for (i = 0; tests[i].name; i++) { 414 report_prefix_push(tests[i].name); 415 tests[i].func(); 416 report_prefix_pop(); 417 } 418 report_prefix_pop(); 419 420 return report_summary(); 421 } 422