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