1f204e0b8SIan Munsie /* 2f204e0b8SIan Munsie * Copyright 2014 IBM Corp. 3f204e0b8SIan Munsie * 4f204e0b8SIan Munsie * This program is free software; you can redistribute it and/or 5f204e0b8SIan Munsie * modify it under the terms of the GNU General Public License 6f204e0b8SIan Munsie * as published by the Free Software Foundation; either version 7f204e0b8SIan Munsie * 2 of the License, or (at your option) any later version. 8f204e0b8SIan Munsie */ 9f204e0b8SIan Munsie 10f204e0b8SIan Munsie #include <linux/kernel.h> 11f204e0b8SIan Munsie #include <linux/device.h> 12f204e0b8SIan Munsie #include <linux/sysfs.h> 13b087e619SIan Munsie #include <linux/pci_regs.h> 14f204e0b8SIan Munsie 15f204e0b8SIan Munsie #include "cxl.h" 16f204e0b8SIan Munsie 17f204e0b8SIan Munsie #define to_afu_chardev_m(d) dev_get_drvdata(d) 18f204e0b8SIan Munsie 19f204e0b8SIan Munsie /********* Adapter attributes **********************************************/ 20f204e0b8SIan Munsie 21f204e0b8SIan Munsie static ssize_t caia_version_show(struct device *device, 22f204e0b8SIan Munsie struct device_attribute *attr, 23f204e0b8SIan Munsie char *buf) 24f204e0b8SIan Munsie { 25f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 26f204e0b8SIan Munsie 27f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major, 28f204e0b8SIan Munsie adapter->caia_minor); 29f204e0b8SIan Munsie } 30f204e0b8SIan Munsie 31f204e0b8SIan Munsie static ssize_t psl_revision_show(struct device *device, 32f204e0b8SIan Munsie struct device_attribute *attr, 33f204e0b8SIan Munsie char *buf) 34f204e0b8SIan Munsie { 35f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 36f204e0b8SIan Munsie 37f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev); 38f204e0b8SIan Munsie } 39f204e0b8SIan Munsie 40f204e0b8SIan Munsie static ssize_t base_image_show(struct device *device, 41f204e0b8SIan Munsie struct device_attribute *attr, 42f204e0b8SIan Munsie char *buf) 43f204e0b8SIan Munsie { 44f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 45f204e0b8SIan Munsie 46f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image); 47f204e0b8SIan Munsie } 48f204e0b8SIan Munsie 49f204e0b8SIan Munsie static ssize_t image_loaded_show(struct device *device, 50f204e0b8SIan Munsie struct device_attribute *attr, 51f204e0b8SIan Munsie char *buf) 52f204e0b8SIan Munsie { 53f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 54f204e0b8SIan Munsie 55f204e0b8SIan Munsie if (adapter->user_image_loaded) 56f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "user\n"); 57f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "factory\n"); 58f204e0b8SIan Munsie } 59f204e0b8SIan Munsie 6062fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device, 6162fa19d4SRyan Grimm struct device_attribute *attr, 6262fa19d4SRyan Grimm const char *buf, size_t count) 6362fa19d4SRyan Grimm { 6462fa19d4SRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 6562fa19d4SRyan Grimm int rc; 6662fa19d4SRyan Grimm int val; 6762fa19d4SRyan Grimm 6862fa19d4SRyan Grimm rc = sscanf(buf, "%i", &val); 6962fa19d4SRyan Grimm if ((rc != 1) || (val != 1)) 7062fa19d4SRyan Grimm return -EINVAL; 7162fa19d4SRyan Grimm 7262fa19d4SRyan Grimm if ((rc = cxl_reset(adapter))) 7362fa19d4SRyan Grimm return rc; 7462fa19d4SRyan Grimm return count; 7562fa19d4SRyan Grimm } 7662fa19d4SRyan Grimm 7795bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device, 7895bc11bcSRyan Grimm struct device_attribute *attr, 7995bc11bcSRyan Grimm char *buf) 8095bc11bcSRyan Grimm { 8195bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 8295bc11bcSRyan Grimm 8395bc11bcSRyan Grimm if (!adapter->perst_loads_image) 8495bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "none\n"); 8595bc11bcSRyan Grimm 8695bc11bcSRyan Grimm if (adapter->perst_select_user) 8795bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "user\n"); 8895bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "factory\n"); 8995bc11bcSRyan Grimm } 9095bc11bcSRyan Grimm 9195bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device, 9295bc11bcSRyan Grimm struct device_attribute *attr, 9395bc11bcSRyan Grimm const char *buf, size_t count) 9495bc11bcSRyan Grimm { 9595bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 9695bc11bcSRyan Grimm int rc; 9795bc11bcSRyan Grimm 9895bc11bcSRyan Grimm if (!strncmp(buf, "none", 4)) 9995bc11bcSRyan Grimm adapter->perst_loads_image = false; 10095bc11bcSRyan Grimm else if (!strncmp(buf, "user", 4)) { 10195bc11bcSRyan Grimm adapter->perst_select_user = true; 10295bc11bcSRyan Grimm adapter->perst_loads_image = true; 10395bc11bcSRyan Grimm } else if (!strncmp(buf, "factory", 7)) { 10495bc11bcSRyan Grimm adapter->perst_select_user = false; 10595bc11bcSRyan Grimm adapter->perst_loads_image = true; 10695bc11bcSRyan Grimm } else 10795bc11bcSRyan Grimm return -EINVAL; 10895bc11bcSRyan Grimm 10995bc11bcSRyan Grimm if ((rc = cxl_update_image_control(adapter))) 11095bc11bcSRyan Grimm return rc; 11195bc11bcSRyan Grimm 11295bc11bcSRyan Grimm return count; 11395bc11bcSRyan Grimm } 11495bc11bcSRyan Grimm 115*13e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device, 116*13e68d8bSDaniel Axtens struct device_attribute *attr, 117*13e68d8bSDaniel Axtens char *buf) 118*13e68d8bSDaniel Axtens { 119*13e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 120*13e68d8bSDaniel Axtens 121*13e68d8bSDaniel Axtens return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image); 122*13e68d8bSDaniel Axtens } 123*13e68d8bSDaniel Axtens 124*13e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device, 125*13e68d8bSDaniel Axtens struct device_attribute *attr, 126*13e68d8bSDaniel Axtens const char *buf, size_t count) 127*13e68d8bSDaniel Axtens { 128*13e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 129*13e68d8bSDaniel Axtens int rc; 130*13e68d8bSDaniel Axtens int val; 131*13e68d8bSDaniel Axtens 132*13e68d8bSDaniel Axtens rc = sscanf(buf, "%i", &val); 133*13e68d8bSDaniel Axtens if ((rc != 1) || !(val == 1 || val == 0)) 134*13e68d8bSDaniel Axtens return -EINVAL; 135*13e68d8bSDaniel Axtens 136*13e68d8bSDaniel Axtens adapter->perst_same_image = (val == 1 ? true : false); 137*13e68d8bSDaniel Axtens return count; 138*13e68d8bSDaniel Axtens } 139*13e68d8bSDaniel Axtens 140f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = { 141f204e0b8SIan Munsie __ATTR_RO(caia_version), 142f204e0b8SIan Munsie __ATTR_RO(psl_revision), 143f204e0b8SIan Munsie __ATTR_RO(base_image), 144f204e0b8SIan Munsie __ATTR_RO(image_loaded), 14595bc11bcSRyan Grimm __ATTR_RW(load_image_on_perst), 146*13e68d8bSDaniel Axtens __ATTR_RW(perst_reloads_same_image), 14762fa19d4SRyan Grimm __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), 148f204e0b8SIan Munsie }; 149f204e0b8SIan Munsie 150f204e0b8SIan Munsie 151f204e0b8SIan Munsie /********* AFU master specific attributes **********************************/ 152f204e0b8SIan Munsie 153f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device, 154f204e0b8SIan Munsie struct device_attribute *attr, 155f204e0b8SIan Munsie char *buf) 156f204e0b8SIan Munsie { 157f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 158f204e0b8SIan Munsie 159f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 160f204e0b8SIan Munsie } 161f204e0b8SIan Munsie 162f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device, 163f204e0b8SIan Munsie struct device_attribute *attr, 164f204e0b8SIan Munsie char *buf) 165f204e0b8SIan Munsie { 166f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 167f204e0b8SIan Munsie 168f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset); 169f204e0b8SIan Munsie } 170f204e0b8SIan Munsie 171f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device, 172f204e0b8SIan Munsie struct device_attribute *attr, 173f204e0b8SIan Munsie char *buf) 174f204e0b8SIan Munsie { 175f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 176f204e0b8SIan Munsie 177f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 178f204e0b8SIan Munsie } 179f204e0b8SIan Munsie 180f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = { 181f204e0b8SIan Munsie __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 182f204e0b8SIan Munsie __ATTR_RO(pp_mmio_off), 183f204e0b8SIan Munsie __ATTR_RO(pp_mmio_len), 184f204e0b8SIan Munsie }; 185f204e0b8SIan Munsie 186f204e0b8SIan Munsie 187f204e0b8SIan Munsie /********* AFU attributes **************************************************/ 188f204e0b8SIan Munsie 189f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device, 190f204e0b8SIan Munsie struct device_attribute *attr, 191f204e0b8SIan Munsie char *buf) 192f204e0b8SIan Munsie { 193f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 194f204e0b8SIan Munsie 195f204e0b8SIan Munsie if (afu->pp_size) 196f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 197f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 198f204e0b8SIan Munsie } 199f204e0b8SIan Munsie 200f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device, 201f204e0b8SIan Munsie struct device_attribute *attr, 202f204e0b8SIan Munsie const char *buf, size_t count) 203f204e0b8SIan Munsie { 204f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 205f204e0b8SIan Munsie int rc; 206f204e0b8SIan Munsie 207f204e0b8SIan Munsie /* Not safe to reset if it is currently in use */ 208ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 209f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) { 210f204e0b8SIan Munsie rc = -EBUSY; 211f204e0b8SIan Munsie goto err; 212f204e0b8SIan Munsie } 213f204e0b8SIan Munsie 214b12994fbSMichael Neuling if ((rc = __cxl_afu_reset(afu))) 215f204e0b8SIan Munsie goto err; 216f204e0b8SIan Munsie 217f204e0b8SIan Munsie rc = count; 218f204e0b8SIan Munsie err: 219ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 220f204e0b8SIan Munsie return rc; 221f204e0b8SIan Munsie } 222f204e0b8SIan Munsie 223f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device, 224f204e0b8SIan Munsie struct device_attribute *attr, 225f204e0b8SIan Munsie char *buf) 226f204e0b8SIan Munsie { 227f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 228f204e0b8SIan Munsie 229f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 230f204e0b8SIan Munsie } 231f204e0b8SIan Munsie 232f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device, 233f204e0b8SIan Munsie struct device_attribute *attr, 234f204e0b8SIan Munsie char *buf) 235f204e0b8SIan Munsie { 236f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 237f204e0b8SIan Munsie 238f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 239f204e0b8SIan Munsie } 240f204e0b8SIan Munsie 241f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device, 242f204e0b8SIan Munsie struct device_attribute *attr, 243f204e0b8SIan Munsie const char *buf, size_t count) 244f204e0b8SIan Munsie { 245f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 246f204e0b8SIan Munsie ssize_t ret; 247f204e0b8SIan Munsie int irqs_max; 248f204e0b8SIan Munsie 249f204e0b8SIan Munsie ret = sscanf(buf, "%i", &irqs_max); 250f204e0b8SIan Munsie if (ret != 1) 251f204e0b8SIan Munsie return -EINVAL; 252f204e0b8SIan Munsie 253f204e0b8SIan Munsie if (irqs_max < afu->pp_irqs) 254f204e0b8SIan Munsie return -EINVAL; 255f204e0b8SIan Munsie 256f204e0b8SIan Munsie if (irqs_max > afu->adapter->user_irqs) 257f204e0b8SIan Munsie return -EINVAL; 258f204e0b8SIan Munsie 259f204e0b8SIan Munsie afu->irqs_max = irqs_max; 260f204e0b8SIan Munsie return count; 261f204e0b8SIan Munsie } 262f204e0b8SIan Munsie 263f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device, 264f204e0b8SIan Munsie struct device_attribute *attr, char *buf) 265f204e0b8SIan Munsie { 266f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 267f204e0b8SIan Munsie char *p = buf, *end = buf + PAGE_SIZE; 268f204e0b8SIan Munsie 269f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DEDICATED) 270f204e0b8SIan Munsie p += scnprintf(p, end - p, "dedicated_process\n"); 271f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DIRECTED) 272f204e0b8SIan Munsie p += scnprintf(p, end - p, "afu_directed\n"); 273f204e0b8SIan Munsie return (p - buf); 274f204e0b8SIan Munsie } 275f204e0b8SIan Munsie 276f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device, 277f204e0b8SIan Munsie struct device_attribute *attr, 278f204e0b8SIan Munsie char *buf) 279f204e0b8SIan Munsie { 280f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 281f204e0b8SIan Munsie 282f204e0b8SIan Munsie switch (afu->prefault_mode) { 283f204e0b8SIan Munsie case CXL_PREFAULT_WED: 284f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 285f204e0b8SIan Munsie case CXL_PREFAULT_ALL: 286f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "all\n"); 287f204e0b8SIan Munsie default: 288f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 289f204e0b8SIan Munsie } 290f204e0b8SIan Munsie } 291f204e0b8SIan Munsie 292f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device, 293f204e0b8SIan Munsie struct device_attribute *attr, 294f204e0b8SIan Munsie const char *buf, size_t count) 295f204e0b8SIan Munsie { 296f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 297f204e0b8SIan Munsie enum prefault_modes mode = -1; 298f204e0b8SIan Munsie 299f204e0b8SIan Munsie if (!strncmp(buf, "work_element_descriptor", 23)) 300f204e0b8SIan Munsie mode = CXL_PREFAULT_WED; 301f204e0b8SIan Munsie if (!strncmp(buf, "all", 3)) 302f204e0b8SIan Munsie mode = CXL_PREFAULT_ALL; 303f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 304f204e0b8SIan Munsie mode = CXL_PREFAULT_NONE; 305f204e0b8SIan Munsie 306f204e0b8SIan Munsie if (mode == -1) 307f204e0b8SIan Munsie return -EINVAL; 308f204e0b8SIan Munsie 309f204e0b8SIan Munsie afu->prefault_mode = mode; 310f204e0b8SIan Munsie return count; 311f204e0b8SIan Munsie } 312f204e0b8SIan Munsie 313f204e0b8SIan Munsie static ssize_t mode_show(struct device *device, 314f204e0b8SIan Munsie struct device_attribute *attr, 315f204e0b8SIan Munsie char *buf) 316f204e0b8SIan Munsie { 317f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 318f204e0b8SIan Munsie 319f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DEDICATED) 320f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 321f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DIRECTED) 322f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 323f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 324f204e0b8SIan Munsie } 325f204e0b8SIan Munsie 326f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr, 327f204e0b8SIan Munsie const char *buf, size_t count) 328f204e0b8SIan Munsie { 329f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 330f204e0b8SIan Munsie int old_mode, mode = -1; 331f204e0b8SIan Munsie int rc = -EBUSY; 332f204e0b8SIan Munsie 333f204e0b8SIan Munsie /* can't change this if we have a user */ 334ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 335f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) 336f204e0b8SIan Munsie goto err; 337f204e0b8SIan Munsie 338f204e0b8SIan Munsie if (!strncmp(buf, "dedicated_process", 17)) 339f204e0b8SIan Munsie mode = CXL_MODE_DEDICATED; 340f204e0b8SIan Munsie if (!strncmp(buf, "afu_directed", 12)) 341f204e0b8SIan Munsie mode = CXL_MODE_DIRECTED; 342f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 343f204e0b8SIan Munsie mode = 0; 344f204e0b8SIan Munsie 345f204e0b8SIan Munsie if (mode == -1) { 346f204e0b8SIan Munsie rc = -EINVAL; 347f204e0b8SIan Munsie goto err; 348f204e0b8SIan Munsie } 349f204e0b8SIan Munsie 350f204e0b8SIan Munsie /* 351f204e0b8SIan Munsie * cxl_afu_deactivate_mode needs to be done outside the lock, prevent 352f204e0b8SIan Munsie * other contexts coming in before we are ready: 353f204e0b8SIan Munsie */ 354f204e0b8SIan Munsie old_mode = afu->current_mode; 355f204e0b8SIan Munsie afu->current_mode = 0; 356f204e0b8SIan Munsie afu->num_procs = 0; 357f204e0b8SIan Munsie 358ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 359f204e0b8SIan Munsie 360f204e0b8SIan Munsie if ((rc = _cxl_afu_deactivate_mode(afu, old_mode))) 361f204e0b8SIan Munsie return rc; 362f204e0b8SIan Munsie if ((rc = cxl_afu_activate_mode(afu, mode))) 363f204e0b8SIan Munsie return rc; 364f204e0b8SIan Munsie 365f204e0b8SIan Munsie return count; 366f204e0b8SIan Munsie err: 367ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 368f204e0b8SIan Munsie return rc; 369f204e0b8SIan Munsie } 370f204e0b8SIan Munsie 371f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device, 372f204e0b8SIan Munsie struct device_attribute *attr, 373f204e0b8SIan Munsie char *buf) 374f204e0b8SIan Munsie { 375f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 376f204e0b8SIan Munsie } 377f204e0b8SIan Munsie 378f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device, 379f204e0b8SIan Munsie struct device_attribute *attr, 380f204e0b8SIan Munsie char *buf) 381f204e0b8SIan Munsie { 382f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 383f204e0b8SIan Munsie } 384f204e0b8SIan Munsie 385e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 386e36f6fe1SVaibhav Jain struct bin_attribute *bin_attr, char *buf, 387e36f6fe1SVaibhav Jain loff_t off, size_t count) 388e36f6fe1SVaibhav Jain { 389e36f6fe1SVaibhav Jain struct cxl_afu *afu = to_cxl_afu(container_of(kobj, 390e36f6fe1SVaibhav Jain struct device, kobj)); 391e36f6fe1SVaibhav Jain 392e36f6fe1SVaibhav Jain return cxl_afu_read_err_buffer(afu, buf, off, count); 393e36f6fe1SVaibhav Jain } 394e36f6fe1SVaibhav Jain 395f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = { 396f204e0b8SIan Munsie __ATTR_RO(mmio_size), 397f204e0b8SIan Munsie __ATTR_RO(irqs_min), 398f204e0b8SIan Munsie __ATTR_RW(irqs_max), 399f204e0b8SIan Munsie __ATTR_RO(modes_supported), 400f204e0b8SIan Munsie __ATTR_RW(mode), 401f204e0b8SIan Munsie __ATTR_RW(prefault_mode), 402f204e0b8SIan Munsie __ATTR_RO(api_version), 403f204e0b8SIan Munsie __ATTR_RO(api_version_compatible), 404f204e0b8SIan Munsie __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 405f204e0b8SIan Munsie }; 406f204e0b8SIan Munsie 407f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter) 408f204e0b8SIan Munsie { 409f204e0b8SIan Munsie int i, rc; 410f204e0b8SIan Munsie 411f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 412f204e0b8SIan Munsie if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i]))) 413f204e0b8SIan Munsie goto err; 414f204e0b8SIan Munsie } 415f204e0b8SIan Munsie return 0; 416f204e0b8SIan Munsie err: 417f204e0b8SIan Munsie for (i--; i >= 0; i--) 418f204e0b8SIan Munsie device_remove_file(&adapter->dev, &adapter_attrs[i]); 419f204e0b8SIan Munsie return rc; 420f204e0b8SIan Munsie } 421f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter) 422f204e0b8SIan Munsie { 423f204e0b8SIan Munsie int i; 424f204e0b8SIan Munsie 425f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) 426f204e0b8SIan Munsie device_remove_file(&adapter->dev, &adapter_attrs[i]); 427f204e0b8SIan Munsie } 428f204e0b8SIan Munsie 429b087e619SIan Munsie struct afu_config_record { 430b087e619SIan Munsie struct kobject kobj; 431b087e619SIan Munsie struct bin_attribute config_attr; 432b087e619SIan Munsie struct list_head list; 433b087e619SIan Munsie int cr; 434b087e619SIan Munsie u16 device; 435b087e619SIan Munsie u16 vendor; 436b087e619SIan Munsie u32 class; 437b087e619SIan Munsie }; 438b087e619SIan Munsie 439b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 440b087e619SIan Munsie 441b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj, 442b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 443b087e619SIan Munsie { 444b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 445b087e619SIan Munsie 446b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 447b087e619SIan Munsie } 448b087e619SIan Munsie 449b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj, 450b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 451b087e619SIan Munsie { 452b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 453b087e619SIan Munsie 454b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); 455b087e619SIan Munsie } 456b087e619SIan Munsie 457b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj, 458b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 459b087e619SIan Munsie { 460b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 461b087e619SIan Munsie 462b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); 463b087e619SIan Munsie } 464b087e619SIan Munsie 465b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 466b087e619SIan Munsie struct bin_attribute *bin_attr, char *buf, 467b087e619SIan Munsie loff_t off, size_t count) 468b087e619SIan Munsie { 469b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 470b087e619SIan Munsie struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj)); 471b087e619SIan Munsie 472b087e619SIan Munsie u64 i, j, val, size = afu->crs_len; 473b087e619SIan Munsie 474b087e619SIan Munsie if (off > size) 475b087e619SIan Munsie return 0; 476b087e619SIan Munsie if (off + count > size) 477b087e619SIan Munsie count = size - off; 478b087e619SIan Munsie 479b087e619SIan Munsie for (i = 0; i < count;) { 480b087e619SIan Munsie val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7); 481b087e619SIan Munsie for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 482b087e619SIan Munsie buf[i] = (val >> (j * 8)) & 0xff; 483b087e619SIan Munsie } 484b087e619SIan Munsie 485b087e619SIan Munsie return count; 486b087e619SIan Munsie } 487b087e619SIan Munsie 488b087e619SIan Munsie static struct kobj_attribute vendor_attribute = 489b087e619SIan Munsie __ATTR_RO(vendor); 490b087e619SIan Munsie static struct kobj_attribute device_attribute = 491b087e619SIan Munsie __ATTR_RO(device); 492b087e619SIan Munsie static struct kobj_attribute class_attribute = 493b087e619SIan Munsie __ATTR_RO(class); 494b087e619SIan Munsie 495b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = { 496b087e619SIan Munsie &vendor_attribute.attr, 497b087e619SIan Munsie &device_attribute.attr, 498b087e619SIan Munsie &class_attribute.attr, 499b087e619SIan Munsie NULL, 500b087e619SIan Munsie }; 501b087e619SIan Munsie 502b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj) 503b087e619SIan Munsie { 504b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 505b087e619SIan Munsie 506b087e619SIan Munsie kfree(cr); 507b087e619SIan Munsie } 508b087e619SIan Munsie 509b087e619SIan Munsie static struct kobj_type afu_config_record_type = { 510b087e619SIan Munsie .sysfs_ops = &kobj_sysfs_ops, 511b087e619SIan Munsie .release = release_afu_config_record, 512b087e619SIan Munsie .default_attrs = afu_cr_attrs, 513b087e619SIan Munsie }; 514b087e619SIan Munsie 515b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 516b087e619SIan Munsie { 517b087e619SIan Munsie struct afu_config_record *cr; 518b087e619SIan Munsie int rc; 519b087e619SIan Munsie 520b087e619SIan Munsie cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 521b087e619SIan Munsie if (!cr) 522b087e619SIan Munsie return ERR_PTR(-ENOMEM); 523b087e619SIan Munsie 524b087e619SIan Munsie cr->cr = cr_idx; 525b087e619SIan Munsie cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID); 526b087e619SIan Munsie cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID); 527b087e619SIan Munsie cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8; 528b087e619SIan Munsie 529b087e619SIan Munsie /* 530b087e619SIan Munsie * Export raw AFU PCIe like config record. For now this is read only by 531b087e619SIan Munsie * root - we can expand that later to be readable by non-root and maybe 532b087e619SIan Munsie * even writable provided we have a good use-case. Once we suport 533b087e619SIan Munsie * exposing AFUs through a virtual PHB they will get that for free from 534b087e619SIan Munsie * Linux' PCI infrastructure, but until then it's not clear that we 535b087e619SIan Munsie * need it for anything since the main use case is just identifying 536b087e619SIan Munsie * AFUs, which can be done via the vendor, device and class attributes. 537b087e619SIan Munsie */ 538b087e619SIan Munsie sysfs_bin_attr_init(&cr->config_attr); 539b087e619SIan Munsie cr->config_attr.attr.name = "config"; 540b087e619SIan Munsie cr->config_attr.attr.mode = S_IRUSR; 541b087e619SIan Munsie cr->config_attr.size = afu->crs_len; 542b087e619SIan Munsie cr->config_attr.read = afu_read_config; 543b087e619SIan Munsie 544b087e619SIan Munsie rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 545b087e619SIan Munsie &afu->dev.kobj, "cr%i", cr->cr); 546b087e619SIan Munsie if (rc) 547b087e619SIan Munsie goto err; 548b087e619SIan Munsie 549b087e619SIan Munsie rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 550b087e619SIan Munsie if (rc) 551b087e619SIan Munsie goto err1; 552b087e619SIan Munsie 553b087e619SIan Munsie rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 554b087e619SIan Munsie if (rc) 555b087e619SIan Munsie goto err2; 556b087e619SIan Munsie 557b087e619SIan Munsie return cr; 558b087e619SIan Munsie err2: 559b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 560b087e619SIan Munsie err1: 561b087e619SIan Munsie kobject_put(&cr->kobj); 562b087e619SIan Munsie return ERR_PTR(rc); 563b087e619SIan Munsie err: 564b087e619SIan Munsie kfree(cr); 565b087e619SIan Munsie return ERR_PTR(rc); 566b087e619SIan Munsie } 567b087e619SIan Munsie 568b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu) 569b087e619SIan Munsie { 570b087e619SIan Munsie struct afu_config_record *cr, *tmp; 571b087e619SIan Munsie int i; 572b087e619SIan Munsie 573e36f6fe1SVaibhav Jain /* remove the err buffer bin attribute */ 574e36f6fe1SVaibhav Jain if (afu->eb_len) 575e36f6fe1SVaibhav Jain device_remove_bin_file(&afu->dev, &afu->attr_eb); 576e36f6fe1SVaibhav Jain 577b087e619SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) 578b087e619SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 579b087e619SIan Munsie 580b087e619SIan Munsie list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 581b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 582b087e619SIan Munsie kobject_put(&cr->kobj); 583b087e619SIan Munsie } 584b087e619SIan Munsie } 585b087e619SIan Munsie 586f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu) 587f204e0b8SIan Munsie { 588b087e619SIan Munsie struct afu_config_record *cr; 589f204e0b8SIan Munsie int i, rc; 590f204e0b8SIan Munsie 591b087e619SIan Munsie INIT_LIST_HEAD(&afu->crs); 592b087e619SIan Munsie 593f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 594f204e0b8SIan Munsie if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 595f204e0b8SIan Munsie goto err; 596f204e0b8SIan Munsie } 597f204e0b8SIan Munsie 598e36f6fe1SVaibhav Jain /* conditionally create the add the binary file for error info buffer */ 599e36f6fe1SVaibhav Jain if (afu->eb_len) { 600e36f6fe1SVaibhav Jain afu->attr_eb.attr.name = "afu_err_buff"; 601e36f6fe1SVaibhav Jain afu->attr_eb.attr.mode = S_IRUGO; 602e36f6fe1SVaibhav Jain afu->attr_eb.size = afu->eb_len; 603e36f6fe1SVaibhav Jain afu->attr_eb.read = afu_eb_read; 604e36f6fe1SVaibhav Jain 605e36f6fe1SVaibhav Jain rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 606e36f6fe1SVaibhav Jain if (rc) { 607e36f6fe1SVaibhav Jain dev_err(&afu->dev, 608e36f6fe1SVaibhav Jain "Unable to create eb attr for the afu. Err(%d)\n", 609e36f6fe1SVaibhav Jain rc); 610e36f6fe1SVaibhav Jain goto err; 611e36f6fe1SVaibhav Jain } 612e36f6fe1SVaibhav Jain } 613e36f6fe1SVaibhav Jain 614b087e619SIan Munsie for (i = 0; i < afu->crs_num; i++) { 615b087e619SIan Munsie cr = cxl_sysfs_afu_new_cr(afu, i); 616b087e619SIan Munsie if (IS_ERR(cr)) { 617b087e619SIan Munsie rc = PTR_ERR(cr); 618b087e619SIan Munsie goto err1; 619b087e619SIan Munsie } 620b087e619SIan Munsie list_add(&cr->list, &afu->crs); 621b087e619SIan Munsie } 622b087e619SIan Munsie 623f204e0b8SIan Munsie return 0; 624f204e0b8SIan Munsie 625b087e619SIan Munsie err1: 626b087e619SIan Munsie cxl_sysfs_afu_remove(afu); 627b087e619SIan Munsie return rc; 628f204e0b8SIan Munsie err: 629e36f6fe1SVaibhav Jain /* reset the eb_len as we havent created the bin attr */ 630e36f6fe1SVaibhav Jain afu->eb_len = 0; 631e36f6fe1SVaibhav Jain 632f204e0b8SIan Munsie for (i--; i >= 0; i--) 633f204e0b8SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 634f204e0b8SIan Munsie return rc; 635f204e0b8SIan Munsie } 636f204e0b8SIan Munsie 637f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 638f204e0b8SIan Munsie { 639f204e0b8SIan Munsie int i, rc; 640f204e0b8SIan Munsie 641f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 642f204e0b8SIan Munsie if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 643f204e0b8SIan Munsie goto err; 644f204e0b8SIan Munsie } 645f204e0b8SIan Munsie 646f204e0b8SIan Munsie return 0; 647f204e0b8SIan Munsie 648f204e0b8SIan Munsie err: 649f204e0b8SIan Munsie for (i--; i >= 0; i--) 650f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 651f204e0b8SIan Munsie return rc; 652f204e0b8SIan Munsie } 653f204e0b8SIan Munsie 654f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 655f204e0b8SIan Munsie { 656f204e0b8SIan Munsie int i; 657f204e0b8SIan Munsie 658f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) 659f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 660f204e0b8SIan Munsie } 661