1 /* 2 * Copyright 2014 IBM Corp. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/device.h> 12 #include <linux/sysfs.h> 13 14 #include "cxl.h" 15 16 #define to_afu_chardev_m(d) dev_get_drvdata(d) 17 18 /********* Adapter attributes **********************************************/ 19 20 static ssize_t caia_version_show(struct device *device, 21 struct device_attribute *attr, 22 char *buf) 23 { 24 struct cxl *adapter = to_cxl_adapter(device); 25 26 return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major, 27 adapter->caia_minor); 28 } 29 30 static ssize_t psl_revision_show(struct device *device, 31 struct device_attribute *attr, 32 char *buf) 33 { 34 struct cxl *adapter = to_cxl_adapter(device); 35 36 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev); 37 } 38 39 static ssize_t base_image_show(struct device *device, 40 struct device_attribute *attr, 41 char *buf) 42 { 43 struct cxl *adapter = to_cxl_adapter(device); 44 45 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image); 46 } 47 48 static ssize_t image_loaded_show(struct device *device, 49 struct device_attribute *attr, 50 char *buf) 51 { 52 struct cxl *adapter = to_cxl_adapter(device); 53 54 if (adapter->user_image_loaded) 55 return scnprintf(buf, PAGE_SIZE, "user\n"); 56 return scnprintf(buf, PAGE_SIZE, "factory\n"); 57 } 58 59 static struct device_attribute adapter_attrs[] = { 60 __ATTR_RO(caia_version), 61 __ATTR_RO(psl_revision), 62 __ATTR_RO(base_image), 63 __ATTR_RO(image_loaded), 64 }; 65 66 67 /********* AFU master specific attributes **********************************/ 68 69 static ssize_t mmio_size_show_master(struct device *device, 70 struct device_attribute *attr, 71 char *buf) 72 { 73 struct cxl_afu *afu = to_afu_chardev_m(device); 74 75 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 76 } 77 78 static ssize_t pp_mmio_off_show(struct device *device, 79 struct device_attribute *attr, 80 char *buf) 81 { 82 struct cxl_afu *afu = to_afu_chardev_m(device); 83 84 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset); 85 } 86 87 static ssize_t pp_mmio_len_show(struct device *device, 88 struct device_attribute *attr, 89 char *buf) 90 { 91 struct cxl_afu *afu = to_afu_chardev_m(device); 92 93 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 94 } 95 96 static struct device_attribute afu_master_attrs[] = { 97 __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 98 __ATTR_RO(pp_mmio_off), 99 __ATTR_RO(pp_mmio_len), 100 }; 101 102 103 /********* AFU attributes **************************************************/ 104 105 static ssize_t mmio_size_show(struct device *device, 106 struct device_attribute *attr, 107 char *buf) 108 { 109 struct cxl_afu *afu = to_cxl_afu(device); 110 111 if (afu->pp_size) 112 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 113 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 114 } 115 116 static ssize_t reset_store_afu(struct device *device, 117 struct device_attribute *attr, 118 const char *buf, size_t count) 119 { 120 struct cxl_afu *afu = to_cxl_afu(device); 121 int rc; 122 123 /* Not safe to reset if it is currently in use */ 124 mutex_lock(&afu->contexts_lock); 125 if (!idr_is_empty(&afu->contexts_idr)) { 126 rc = -EBUSY; 127 goto err; 128 } 129 130 if ((rc = cxl_afu_reset(afu))) 131 goto err; 132 133 rc = count; 134 err: 135 mutex_unlock(&afu->contexts_lock); 136 return rc; 137 } 138 139 static ssize_t irqs_min_show(struct device *device, 140 struct device_attribute *attr, 141 char *buf) 142 { 143 struct cxl_afu *afu = to_cxl_afu(device); 144 145 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 146 } 147 148 static ssize_t irqs_max_show(struct device *device, 149 struct device_attribute *attr, 150 char *buf) 151 { 152 struct cxl_afu *afu = to_cxl_afu(device); 153 154 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 155 } 156 157 static ssize_t irqs_max_store(struct device *device, 158 struct device_attribute *attr, 159 const char *buf, size_t count) 160 { 161 struct cxl_afu *afu = to_cxl_afu(device); 162 ssize_t ret; 163 int irqs_max; 164 165 ret = sscanf(buf, "%i", &irqs_max); 166 if (ret != 1) 167 return -EINVAL; 168 169 if (irqs_max < afu->pp_irqs) 170 return -EINVAL; 171 172 if (irqs_max > afu->adapter->user_irqs) 173 return -EINVAL; 174 175 afu->irqs_max = irqs_max; 176 return count; 177 } 178 179 static ssize_t modes_supported_show(struct device *device, 180 struct device_attribute *attr, char *buf) 181 { 182 struct cxl_afu *afu = to_cxl_afu(device); 183 char *p = buf, *end = buf + PAGE_SIZE; 184 185 if (afu->modes_supported & CXL_MODE_DEDICATED) 186 p += scnprintf(p, end - p, "dedicated_process\n"); 187 if (afu->modes_supported & CXL_MODE_DIRECTED) 188 p += scnprintf(p, end - p, "afu_directed\n"); 189 return (p - buf); 190 } 191 192 static ssize_t prefault_mode_show(struct device *device, 193 struct device_attribute *attr, 194 char *buf) 195 { 196 struct cxl_afu *afu = to_cxl_afu(device); 197 198 switch (afu->prefault_mode) { 199 case CXL_PREFAULT_WED: 200 return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 201 case CXL_PREFAULT_ALL: 202 return scnprintf(buf, PAGE_SIZE, "all\n"); 203 default: 204 return scnprintf(buf, PAGE_SIZE, "none\n"); 205 } 206 } 207 208 static ssize_t prefault_mode_store(struct device *device, 209 struct device_attribute *attr, 210 const char *buf, size_t count) 211 { 212 struct cxl_afu *afu = to_cxl_afu(device); 213 enum prefault_modes mode = -1; 214 215 if (!strncmp(buf, "work_element_descriptor", 23)) 216 mode = CXL_PREFAULT_WED; 217 if (!strncmp(buf, "all", 3)) 218 mode = CXL_PREFAULT_ALL; 219 if (!strncmp(buf, "none", 4)) 220 mode = CXL_PREFAULT_NONE; 221 222 if (mode == -1) 223 return -EINVAL; 224 225 afu->prefault_mode = mode; 226 return count; 227 } 228 229 static ssize_t mode_show(struct device *device, 230 struct device_attribute *attr, 231 char *buf) 232 { 233 struct cxl_afu *afu = to_cxl_afu(device); 234 235 if (afu->current_mode == CXL_MODE_DEDICATED) 236 return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 237 if (afu->current_mode == CXL_MODE_DIRECTED) 238 return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 239 return scnprintf(buf, PAGE_SIZE, "none\n"); 240 } 241 242 static ssize_t mode_store(struct device *device, struct device_attribute *attr, 243 const char *buf, size_t count) 244 { 245 struct cxl_afu *afu = to_cxl_afu(device); 246 int old_mode, mode = -1; 247 int rc = -EBUSY; 248 249 /* can't change this if we have a user */ 250 mutex_lock(&afu->contexts_lock); 251 if (!idr_is_empty(&afu->contexts_idr)) 252 goto err; 253 254 if (!strncmp(buf, "dedicated_process", 17)) 255 mode = CXL_MODE_DEDICATED; 256 if (!strncmp(buf, "afu_directed", 12)) 257 mode = CXL_MODE_DIRECTED; 258 if (!strncmp(buf, "none", 4)) 259 mode = 0; 260 261 if (mode == -1) { 262 rc = -EINVAL; 263 goto err; 264 } 265 266 /* 267 * cxl_afu_deactivate_mode needs to be done outside the lock, prevent 268 * other contexts coming in before we are ready: 269 */ 270 old_mode = afu->current_mode; 271 afu->current_mode = 0; 272 afu->num_procs = 0; 273 274 mutex_unlock(&afu->contexts_lock); 275 276 if ((rc = _cxl_afu_deactivate_mode(afu, old_mode))) 277 return rc; 278 if ((rc = cxl_afu_activate_mode(afu, mode))) 279 return rc; 280 281 return count; 282 err: 283 mutex_unlock(&afu->contexts_lock); 284 return rc; 285 } 286 287 static ssize_t api_version_show(struct device *device, 288 struct device_attribute *attr, 289 char *buf) 290 { 291 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 292 } 293 294 static ssize_t api_version_compatible_show(struct device *device, 295 struct device_attribute *attr, 296 char *buf) 297 { 298 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 299 } 300 301 static struct device_attribute afu_attrs[] = { 302 __ATTR_RO(mmio_size), 303 __ATTR_RO(irqs_min), 304 __ATTR_RW(irqs_max), 305 __ATTR_RO(modes_supported), 306 __ATTR_RW(mode), 307 __ATTR_RW(prefault_mode), 308 __ATTR_RO(api_version), 309 __ATTR_RO(api_version_compatible), 310 __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 311 }; 312 313 314 315 int cxl_sysfs_adapter_add(struct cxl *adapter) 316 { 317 int i, rc; 318 319 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 320 if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i]))) 321 goto err; 322 } 323 return 0; 324 err: 325 for (i--; i >= 0; i--) 326 device_remove_file(&adapter->dev, &adapter_attrs[i]); 327 return rc; 328 } 329 void cxl_sysfs_adapter_remove(struct cxl *adapter) 330 { 331 int i; 332 333 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) 334 device_remove_file(&adapter->dev, &adapter_attrs[i]); 335 } 336 337 int cxl_sysfs_afu_add(struct cxl_afu *afu) 338 { 339 int i, rc; 340 341 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 342 if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 343 goto err; 344 } 345 346 return 0; 347 348 err: 349 for (i--; i >= 0; i--) 350 device_remove_file(&afu->dev, &afu_attrs[i]); 351 return rc; 352 } 353 354 void cxl_sysfs_afu_remove(struct cxl_afu *afu) 355 { 356 int i; 357 358 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) 359 device_remove_file(&afu->dev, &afu_attrs[i]); 360 } 361 362 int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 363 { 364 int i, rc; 365 366 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 367 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 368 goto err; 369 } 370 371 return 0; 372 373 err: 374 for (i--; i >= 0; i--) 375 device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 376 return rc; 377 } 378 379 void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 380 { 381 int i; 382 383 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) 384 device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 385 } 386