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 60e009a7e8SFrederic Barrat static ssize_t psl_timebase_synced_show(struct device *device, 61e009a7e8SFrederic Barrat struct device_attribute *attr, 62e009a7e8SFrederic Barrat char *buf) 63e009a7e8SFrederic Barrat { 64e009a7e8SFrederic Barrat struct cxl *adapter = to_cxl_adapter(device); 65e009a7e8SFrederic Barrat 66e009a7e8SFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced); 67e009a7e8SFrederic Barrat } 68e009a7e8SFrederic Barrat 6962fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device, 7062fa19d4SRyan Grimm struct device_attribute *attr, 7162fa19d4SRyan Grimm const char *buf, size_t count) 7262fa19d4SRyan Grimm { 7362fa19d4SRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 7462fa19d4SRyan Grimm int rc; 7562fa19d4SRyan Grimm int val; 7662fa19d4SRyan Grimm 7762fa19d4SRyan Grimm rc = sscanf(buf, "%i", &val); 78*70b565bbSVaibhav Jain if ((rc != 1) || (val != 1 && val != -1)) 7962fa19d4SRyan Grimm return -EINVAL; 8062fa19d4SRyan Grimm 81*70b565bbSVaibhav Jain /* 82*70b565bbSVaibhav Jain * See if we can lock the context mapping that's only allowed 83*70b565bbSVaibhav Jain * when there are no contexts attached to the adapter. Once 84*70b565bbSVaibhav Jain * taken this will also prevent any context from getting activated. 85*70b565bbSVaibhav Jain */ 86*70b565bbSVaibhav Jain if (val == 1) { 87*70b565bbSVaibhav Jain rc = cxl_adapter_context_lock(adapter); 88*70b565bbSVaibhav Jain if (rc) 89*70b565bbSVaibhav Jain goto out; 90*70b565bbSVaibhav Jain 91*70b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 92*70b565bbSVaibhav Jain /* In case reset failed release context lock */ 93*70b565bbSVaibhav Jain if (rc) 94*70b565bbSVaibhav Jain cxl_adapter_context_unlock(adapter); 95*70b565bbSVaibhav Jain 96*70b565bbSVaibhav Jain } else if (val == -1) { 97*70b565bbSVaibhav Jain /* Perform a forced adapter reset */ 98*70b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 99*70b565bbSVaibhav Jain } 100*70b565bbSVaibhav Jain 101*70b565bbSVaibhav Jain out: 102*70b565bbSVaibhav Jain return rc ? rc : count; 10362fa19d4SRyan Grimm } 10462fa19d4SRyan Grimm 10595bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device, 10695bc11bcSRyan Grimm struct device_attribute *attr, 10795bc11bcSRyan Grimm char *buf) 10895bc11bcSRyan Grimm { 10995bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 11095bc11bcSRyan Grimm 11195bc11bcSRyan Grimm if (!adapter->perst_loads_image) 11295bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "none\n"); 11395bc11bcSRyan Grimm 11495bc11bcSRyan Grimm if (adapter->perst_select_user) 11595bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "user\n"); 11695bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "factory\n"); 11795bc11bcSRyan Grimm } 11895bc11bcSRyan Grimm 11995bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device, 12095bc11bcSRyan Grimm struct device_attribute *attr, 12195bc11bcSRyan Grimm const char *buf, size_t count) 12295bc11bcSRyan Grimm { 12395bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 12495bc11bcSRyan Grimm int rc; 12595bc11bcSRyan Grimm 12695bc11bcSRyan Grimm if (!strncmp(buf, "none", 4)) 12795bc11bcSRyan Grimm adapter->perst_loads_image = false; 12895bc11bcSRyan Grimm else if (!strncmp(buf, "user", 4)) { 12995bc11bcSRyan Grimm adapter->perst_select_user = true; 13095bc11bcSRyan Grimm adapter->perst_loads_image = true; 13195bc11bcSRyan Grimm } else if (!strncmp(buf, "factory", 7)) { 13295bc11bcSRyan Grimm adapter->perst_select_user = false; 13395bc11bcSRyan Grimm adapter->perst_loads_image = true; 13495bc11bcSRyan Grimm } else 13595bc11bcSRyan Grimm return -EINVAL; 13695bc11bcSRyan Grimm 13795bc11bcSRyan Grimm if ((rc = cxl_update_image_control(adapter))) 13895bc11bcSRyan Grimm return rc; 13995bc11bcSRyan Grimm 14095bc11bcSRyan Grimm return count; 14195bc11bcSRyan Grimm } 14295bc11bcSRyan Grimm 14313e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device, 14413e68d8bSDaniel Axtens struct device_attribute *attr, 14513e68d8bSDaniel Axtens char *buf) 14613e68d8bSDaniel Axtens { 14713e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 14813e68d8bSDaniel Axtens 14913e68d8bSDaniel Axtens return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image); 15013e68d8bSDaniel Axtens } 15113e68d8bSDaniel Axtens 15213e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device, 15313e68d8bSDaniel Axtens struct device_attribute *attr, 15413e68d8bSDaniel Axtens const char *buf, size_t count) 15513e68d8bSDaniel Axtens { 15613e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 15713e68d8bSDaniel Axtens int rc; 15813e68d8bSDaniel Axtens int val; 15913e68d8bSDaniel Axtens 16013e68d8bSDaniel Axtens rc = sscanf(buf, "%i", &val); 16113e68d8bSDaniel Axtens if ((rc != 1) || !(val == 1 || val == 0)) 16213e68d8bSDaniel Axtens return -EINVAL; 16313e68d8bSDaniel Axtens 16413e68d8bSDaniel Axtens adapter->perst_same_image = (val == 1 ? true : false); 16513e68d8bSDaniel Axtens return count; 16613e68d8bSDaniel Axtens } 16713e68d8bSDaniel Axtens 168f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = { 169f204e0b8SIan Munsie __ATTR_RO(caia_version), 170f204e0b8SIan Munsie __ATTR_RO(psl_revision), 171f204e0b8SIan Munsie __ATTR_RO(base_image), 172f204e0b8SIan Munsie __ATTR_RO(image_loaded), 173e009a7e8SFrederic Barrat __ATTR_RO(psl_timebase_synced), 17495bc11bcSRyan Grimm __ATTR_RW(load_image_on_perst), 17513e68d8bSDaniel Axtens __ATTR_RW(perst_reloads_same_image), 17662fa19d4SRyan Grimm __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), 177f204e0b8SIan Munsie }; 178f204e0b8SIan Munsie 179f204e0b8SIan Munsie 180f204e0b8SIan Munsie /********* AFU master specific attributes **********************************/ 181f204e0b8SIan Munsie 182f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device, 183f204e0b8SIan Munsie struct device_attribute *attr, 184f204e0b8SIan Munsie char *buf) 185f204e0b8SIan Munsie { 186f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 187f204e0b8SIan Munsie 188f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 189f204e0b8SIan Munsie } 190f204e0b8SIan Munsie 191f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device, 192f204e0b8SIan Munsie struct device_attribute *attr, 193f204e0b8SIan Munsie char *buf) 194f204e0b8SIan Munsie { 195f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 196f204e0b8SIan Munsie 197cbffa3a5SChristophe Lombard return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset); 198f204e0b8SIan Munsie } 199f204e0b8SIan Munsie 200f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device, 201f204e0b8SIan Munsie struct device_attribute *attr, 202f204e0b8SIan Munsie char *buf) 203f204e0b8SIan Munsie { 204f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 205f204e0b8SIan Munsie 206f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 207f204e0b8SIan Munsie } 208f204e0b8SIan Munsie 209f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = { 210f204e0b8SIan Munsie __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 211f204e0b8SIan Munsie __ATTR_RO(pp_mmio_off), 212f204e0b8SIan Munsie __ATTR_RO(pp_mmio_len), 213f204e0b8SIan Munsie }; 214f204e0b8SIan Munsie 215f204e0b8SIan Munsie 216f204e0b8SIan Munsie /********* AFU attributes **************************************************/ 217f204e0b8SIan Munsie 218f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device, 219f204e0b8SIan Munsie struct device_attribute *attr, 220f204e0b8SIan Munsie char *buf) 221f204e0b8SIan Munsie { 222f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 223f204e0b8SIan Munsie 224f204e0b8SIan Munsie if (afu->pp_size) 225f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 226f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 227f204e0b8SIan Munsie } 228f204e0b8SIan Munsie 229f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device, 230f204e0b8SIan Munsie struct device_attribute *attr, 231f204e0b8SIan Munsie const char *buf, size_t count) 232f204e0b8SIan Munsie { 233f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 234f204e0b8SIan Munsie int rc; 235f204e0b8SIan Munsie 236f204e0b8SIan Munsie /* Not safe to reset if it is currently in use */ 237ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 238f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) { 239f204e0b8SIan Munsie rc = -EBUSY; 240f204e0b8SIan Munsie goto err; 241f204e0b8SIan Munsie } 242f204e0b8SIan Munsie 2435be587b1SFrederic Barrat if ((rc = cxl_ops->afu_reset(afu))) 244f204e0b8SIan Munsie goto err; 245f204e0b8SIan Munsie 246f204e0b8SIan Munsie rc = count; 247f204e0b8SIan Munsie err: 248ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 249f204e0b8SIan Munsie return rc; 250f204e0b8SIan Munsie } 251f204e0b8SIan Munsie 252f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device, 253f204e0b8SIan Munsie struct device_attribute *attr, 254f204e0b8SIan Munsie char *buf) 255f204e0b8SIan Munsie { 256f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 257f204e0b8SIan Munsie 258f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 259f204e0b8SIan Munsie } 260f204e0b8SIan Munsie 261f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device, 262f204e0b8SIan Munsie struct device_attribute *attr, 263f204e0b8SIan Munsie char *buf) 264f204e0b8SIan Munsie { 265f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 266f204e0b8SIan Munsie 267f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 268f204e0b8SIan Munsie } 269f204e0b8SIan Munsie 270f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device, 271f204e0b8SIan Munsie struct device_attribute *attr, 272f204e0b8SIan Munsie const char *buf, size_t count) 273f204e0b8SIan Munsie { 274f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 275f204e0b8SIan Munsie ssize_t ret; 276f204e0b8SIan Munsie int irqs_max; 277f204e0b8SIan Munsie 278f204e0b8SIan Munsie ret = sscanf(buf, "%i", &irqs_max); 279f204e0b8SIan Munsie if (ret != 1) 280f204e0b8SIan Munsie return -EINVAL; 281f204e0b8SIan Munsie 282f204e0b8SIan Munsie if (irqs_max < afu->pp_irqs) 283f204e0b8SIan Munsie return -EINVAL; 284f204e0b8SIan Munsie 2854752876cSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 286f204e0b8SIan Munsie if (irqs_max > afu->adapter->user_irqs) 287f204e0b8SIan Munsie return -EINVAL; 2884752876cSChristophe Lombard } else { 2894752876cSChristophe Lombard /* pHyp sets a per-AFU limit */ 2904752876cSChristophe Lombard if (irqs_max > afu->guest->max_ints) 2914752876cSChristophe Lombard return -EINVAL; 2924752876cSChristophe Lombard } 293f204e0b8SIan Munsie 294f204e0b8SIan Munsie afu->irqs_max = irqs_max; 295f204e0b8SIan Munsie return count; 296f204e0b8SIan Munsie } 297f204e0b8SIan Munsie 298f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device, 299f204e0b8SIan Munsie struct device_attribute *attr, char *buf) 300f204e0b8SIan Munsie { 301f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 302f204e0b8SIan Munsie char *p = buf, *end = buf + PAGE_SIZE; 303f204e0b8SIan Munsie 304f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DEDICATED) 305f204e0b8SIan Munsie p += scnprintf(p, end - p, "dedicated_process\n"); 306f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DIRECTED) 307f204e0b8SIan Munsie p += scnprintf(p, end - p, "afu_directed\n"); 308f204e0b8SIan Munsie return (p - buf); 309f204e0b8SIan Munsie } 310f204e0b8SIan Munsie 311f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device, 312f204e0b8SIan Munsie struct device_attribute *attr, 313f204e0b8SIan Munsie char *buf) 314f204e0b8SIan Munsie { 315f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 316f204e0b8SIan Munsie 317f204e0b8SIan Munsie switch (afu->prefault_mode) { 318f204e0b8SIan Munsie case CXL_PREFAULT_WED: 319f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 320f204e0b8SIan Munsie case CXL_PREFAULT_ALL: 321f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "all\n"); 322f204e0b8SIan Munsie default: 323f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 324f204e0b8SIan Munsie } 325f204e0b8SIan Munsie } 326f204e0b8SIan Munsie 327f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device, 328f204e0b8SIan Munsie struct device_attribute *attr, 329f204e0b8SIan Munsie const char *buf, size_t count) 330f204e0b8SIan Munsie { 331f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 332f204e0b8SIan Munsie enum prefault_modes mode = -1; 333f204e0b8SIan Munsie 334f204e0b8SIan Munsie if (!strncmp(buf, "work_element_descriptor", 23)) 335f204e0b8SIan Munsie mode = CXL_PREFAULT_WED; 336f204e0b8SIan Munsie if (!strncmp(buf, "all", 3)) 337f204e0b8SIan Munsie mode = CXL_PREFAULT_ALL; 338f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 339f204e0b8SIan Munsie mode = CXL_PREFAULT_NONE; 340f204e0b8SIan Munsie 341f204e0b8SIan Munsie if (mode == -1) 342f204e0b8SIan Munsie return -EINVAL; 343f204e0b8SIan Munsie 344f204e0b8SIan Munsie afu->prefault_mode = mode; 345f204e0b8SIan Munsie return count; 346f204e0b8SIan Munsie } 347f204e0b8SIan Munsie 348f204e0b8SIan Munsie static ssize_t mode_show(struct device *device, 349f204e0b8SIan Munsie struct device_attribute *attr, 350f204e0b8SIan Munsie char *buf) 351f204e0b8SIan Munsie { 352f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 353f204e0b8SIan Munsie 354f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DEDICATED) 355f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 356f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DIRECTED) 357f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 358f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 359f204e0b8SIan Munsie } 360f204e0b8SIan Munsie 361f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr, 362f204e0b8SIan Munsie const char *buf, size_t count) 363f204e0b8SIan Munsie { 364f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 365f204e0b8SIan Munsie int old_mode, mode = -1; 366f204e0b8SIan Munsie int rc = -EBUSY; 367f204e0b8SIan Munsie 368f204e0b8SIan Munsie /* can't change this if we have a user */ 369ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 370f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) 371f204e0b8SIan Munsie goto err; 372f204e0b8SIan Munsie 373f204e0b8SIan Munsie if (!strncmp(buf, "dedicated_process", 17)) 374f204e0b8SIan Munsie mode = CXL_MODE_DEDICATED; 375f204e0b8SIan Munsie if (!strncmp(buf, "afu_directed", 12)) 376f204e0b8SIan Munsie mode = CXL_MODE_DIRECTED; 377f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 378f204e0b8SIan Munsie mode = 0; 379f204e0b8SIan Munsie 380f204e0b8SIan Munsie if (mode == -1) { 381f204e0b8SIan Munsie rc = -EINVAL; 382f204e0b8SIan Munsie goto err; 383f204e0b8SIan Munsie } 384f204e0b8SIan Munsie 385f204e0b8SIan Munsie /* 3865be587b1SFrederic Barrat * afu_deactivate_mode needs to be done outside the lock, prevent 387f204e0b8SIan Munsie * other contexts coming in before we are ready: 388f204e0b8SIan Munsie */ 389f204e0b8SIan Munsie old_mode = afu->current_mode; 390f204e0b8SIan Munsie afu->current_mode = 0; 391f204e0b8SIan Munsie afu->num_procs = 0; 392f204e0b8SIan Munsie 393ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 394f204e0b8SIan Munsie 3955be587b1SFrederic Barrat if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) 396f204e0b8SIan Munsie return rc; 3975be587b1SFrederic Barrat if ((rc = cxl_ops->afu_activate_mode(afu, mode))) 398f204e0b8SIan Munsie return rc; 399f204e0b8SIan Munsie 400f204e0b8SIan Munsie return count; 401f204e0b8SIan Munsie err: 402ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 403f204e0b8SIan Munsie return rc; 404f204e0b8SIan Munsie } 405f204e0b8SIan Munsie 406f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device, 407f204e0b8SIan Munsie struct device_attribute *attr, 408f204e0b8SIan Munsie char *buf) 409f204e0b8SIan Munsie { 410f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 411f204e0b8SIan Munsie } 412f204e0b8SIan Munsie 413f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device, 414f204e0b8SIan Munsie struct device_attribute *attr, 415f204e0b8SIan Munsie char *buf) 416f204e0b8SIan Munsie { 417f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 418f204e0b8SIan Munsie } 419f204e0b8SIan Munsie 420e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 421e36f6fe1SVaibhav Jain struct bin_attribute *bin_attr, char *buf, 422e36f6fe1SVaibhav Jain loff_t off, size_t count) 423e36f6fe1SVaibhav Jain { 42485016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj)); 425e36f6fe1SVaibhav Jain 4265be587b1SFrederic Barrat return cxl_ops->afu_read_err_buffer(afu, buf, off, count); 427e36f6fe1SVaibhav Jain } 428e36f6fe1SVaibhav Jain 429f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = { 430f204e0b8SIan Munsie __ATTR_RO(mmio_size), 431f204e0b8SIan Munsie __ATTR_RO(irqs_min), 432f204e0b8SIan Munsie __ATTR_RW(irqs_max), 433f204e0b8SIan Munsie __ATTR_RO(modes_supported), 434f204e0b8SIan Munsie __ATTR_RW(mode), 435f204e0b8SIan Munsie __ATTR_RW(prefault_mode), 436f204e0b8SIan Munsie __ATTR_RO(api_version), 437f204e0b8SIan Munsie __ATTR_RO(api_version_compatible), 438f204e0b8SIan Munsie __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 439f204e0b8SIan Munsie }; 440f204e0b8SIan Munsie 441f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter) 442f204e0b8SIan Munsie { 4434752876cSChristophe Lombard struct device_attribute *dev_attr; 444f204e0b8SIan Munsie int i, rc; 445f204e0b8SIan Munsie 446f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4474752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4484752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4494752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) { 4504752876cSChristophe Lombard if ((rc = device_create_file(&adapter->dev, dev_attr))) 451f204e0b8SIan Munsie goto err; 452f204e0b8SIan Munsie } 4534752876cSChristophe Lombard } 454f204e0b8SIan Munsie return 0; 455f204e0b8SIan Munsie err: 4564752876cSChristophe Lombard for (i--; i >= 0; i--) { 4574752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4584752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4594752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4604752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4614752876cSChristophe Lombard } 462f204e0b8SIan Munsie return rc; 463f204e0b8SIan Munsie } 4644752876cSChristophe Lombard 465f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter) 466f204e0b8SIan Munsie { 4674752876cSChristophe Lombard struct device_attribute *dev_attr; 468f204e0b8SIan Munsie int i; 469f204e0b8SIan Munsie 4704752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4714752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4724752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4734752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4744752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4754752876cSChristophe Lombard } 476f204e0b8SIan Munsie } 477f204e0b8SIan Munsie 478b087e619SIan Munsie struct afu_config_record { 479b087e619SIan Munsie struct kobject kobj; 480b087e619SIan Munsie struct bin_attribute config_attr; 481b087e619SIan Munsie struct list_head list; 482b087e619SIan Munsie int cr; 483b087e619SIan Munsie u16 device; 484b087e619SIan Munsie u16 vendor; 485b087e619SIan Munsie u32 class; 486b087e619SIan Munsie }; 487b087e619SIan Munsie 488b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 489b087e619SIan Munsie 490b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj, 491b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 492b087e619SIan Munsie { 493b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 494b087e619SIan Munsie 495b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 496b087e619SIan Munsie } 497b087e619SIan Munsie 498b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj, 499b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 500b087e619SIan Munsie { 501b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 502b087e619SIan Munsie 503b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); 504b087e619SIan Munsie } 505b087e619SIan Munsie 506b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj, 507b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 508b087e619SIan Munsie { 509b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 510b087e619SIan Munsie 511b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); 512b087e619SIan Munsie } 513b087e619SIan Munsie 514b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 515b087e619SIan Munsie struct bin_attribute *bin_attr, char *buf, 516b087e619SIan Munsie loff_t off, size_t count) 517b087e619SIan Munsie { 518b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 51985016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent)); 520b087e619SIan Munsie 5215be587b1SFrederic Barrat u64 i, j, val, rc; 522b087e619SIan Munsie 523b087e619SIan Munsie for (i = 0; i < count;) { 5245be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); 5255be587b1SFrederic Barrat if (rc) 5265be587b1SFrederic Barrat val = ~0ULL; 527b087e619SIan Munsie for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 528b087e619SIan Munsie buf[i] = (val >> (j * 8)) & 0xff; 529b087e619SIan Munsie } 530b087e619SIan Munsie 531b087e619SIan Munsie return count; 532b087e619SIan Munsie } 533b087e619SIan Munsie 534b087e619SIan Munsie static struct kobj_attribute vendor_attribute = 535b087e619SIan Munsie __ATTR_RO(vendor); 536b087e619SIan Munsie static struct kobj_attribute device_attribute = 537b087e619SIan Munsie __ATTR_RO(device); 538b087e619SIan Munsie static struct kobj_attribute class_attribute = 539b087e619SIan Munsie __ATTR_RO(class); 540b087e619SIan Munsie 541b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = { 542b087e619SIan Munsie &vendor_attribute.attr, 543b087e619SIan Munsie &device_attribute.attr, 544b087e619SIan Munsie &class_attribute.attr, 545b087e619SIan Munsie NULL, 546b087e619SIan Munsie }; 547b087e619SIan Munsie 548b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj) 549b087e619SIan Munsie { 550b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 551b087e619SIan Munsie 552b087e619SIan Munsie kfree(cr); 553b087e619SIan Munsie } 554b087e619SIan Munsie 555b087e619SIan Munsie static struct kobj_type afu_config_record_type = { 556b087e619SIan Munsie .sysfs_ops = &kobj_sysfs_ops, 557b087e619SIan Munsie .release = release_afu_config_record, 558b087e619SIan Munsie .default_attrs = afu_cr_attrs, 559b087e619SIan Munsie }; 560b087e619SIan Munsie 561b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 562b087e619SIan Munsie { 563b087e619SIan Munsie struct afu_config_record *cr; 564b087e619SIan Munsie int rc; 565b087e619SIan Munsie 566b087e619SIan Munsie cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 567b087e619SIan Munsie if (!cr) 568b087e619SIan Munsie return ERR_PTR(-ENOMEM); 569b087e619SIan Munsie 570b087e619SIan Munsie cr->cr = cr_idx; 5715be587b1SFrederic Barrat 5725be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); 5735be587b1SFrederic Barrat if (rc) 5745be587b1SFrederic Barrat goto err; 5755be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); 5765be587b1SFrederic Barrat if (rc) 5775be587b1SFrederic Barrat goto err; 5785be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); 5795be587b1SFrederic Barrat if (rc) 5805be587b1SFrederic Barrat goto err; 5815be587b1SFrederic Barrat cr->class >>= 8; 582b087e619SIan Munsie 583b087e619SIan Munsie /* 584b087e619SIan Munsie * Export raw AFU PCIe like config record. For now this is read only by 585b087e619SIan Munsie * root - we can expand that later to be readable by non-root and maybe 5864752876cSChristophe Lombard * even writable provided we have a good use-case. Once we support 587b087e619SIan Munsie * exposing AFUs through a virtual PHB they will get that for free from 588b087e619SIan Munsie * Linux' PCI infrastructure, but until then it's not clear that we 589b087e619SIan Munsie * need it for anything since the main use case is just identifying 590b087e619SIan Munsie * AFUs, which can be done via the vendor, device and class attributes. 591b087e619SIan Munsie */ 592b087e619SIan Munsie sysfs_bin_attr_init(&cr->config_attr); 593b087e619SIan Munsie cr->config_attr.attr.name = "config"; 594b087e619SIan Munsie cr->config_attr.attr.mode = S_IRUSR; 595b087e619SIan Munsie cr->config_attr.size = afu->crs_len; 596b087e619SIan Munsie cr->config_attr.read = afu_read_config; 597b087e619SIan Munsie 598b087e619SIan Munsie rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 599b087e619SIan Munsie &afu->dev.kobj, "cr%i", cr->cr); 600b087e619SIan Munsie if (rc) 601b087e619SIan Munsie goto err; 602b087e619SIan Munsie 603b087e619SIan Munsie rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 604b087e619SIan Munsie if (rc) 605b087e619SIan Munsie goto err1; 606b087e619SIan Munsie 607b087e619SIan Munsie rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 608b087e619SIan Munsie if (rc) 609b087e619SIan Munsie goto err2; 610b087e619SIan Munsie 611b087e619SIan Munsie return cr; 612b087e619SIan Munsie err2: 613b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 614b087e619SIan Munsie err1: 615b087e619SIan Munsie kobject_put(&cr->kobj); 616b087e619SIan Munsie return ERR_PTR(rc); 617b087e619SIan Munsie err: 618b087e619SIan Munsie kfree(cr); 619b087e619SIan Munsie return ERR_PTR(rc); 620b087e619SIan Munsie } 621b087e619SIan Munsie 622b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu) 623b087e619SIan Munsie { 6244752876cSChristophe Lombard struct device_attribute *dev_attr; 625b087e619SIan Munsie struct afu_config_record *cr, *tmp; 626b087e619SIan Munsie int i; 627b087e619SIan Munsie 628e36f6fe1SVaibhav Jain /* remove the err buffer bin attribute */ 629e36f6fe1SVaibhav Jain if (afu->eb_len) 630e36f6fe1SVaibhav Jain device_remove_bin_file(&afu->dev, &afu->attr_eb); 631e36f6fe1SVaibhav Jain 6324752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6334752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6344752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6354752876cSChristophe Lombard CXL_AFU_ATTRS)) 636b087e619SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 6374752876cSChristophe Lombard } 638b087e619SIan Munsie 639b087e619SIan Munsie list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 640b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 641b087e619SIan Munsie kobject_put(&cr->kobj); 642b087e619SIan Munsie } 643b087e619SIan Munsie } 644b087e619SIan Munsie 645f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu) 646f204e0b8SIan Munsie { 6474752876cSChristophe Lombard struct device_attribute *dev_attr; 648b087e619SIan Munsie struct afu_config_record *cr; 649f204e0b8SIan Munsie int i, rc; 650f204e0b8SIan Munsie 651b087e619SIan Munsie INIT_LIST_HEAD(&afu->crs); 652b087e619SIan Munsie 653f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6544752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6554752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6564752876cSChristophe Lombard CXL_AFU_ATTRS)) { 657f204e0b8SIan Munsie if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 658f204e0b8SIan Munsie goto err; 659f204e0b8SIan Munsie } 6604752876cSChristophe Lombard } 661f204e0b8SIan Munsie 662e36f6fe1SVaibhav Jain /* conditionally create the add the binary file for error info buffer */ 663e36f6fe1SVaibhav Jain if (afu->eb_len) { 664d6eb71a6SVaibhav Jain sysfs_attr_init(&afu->attr_eb.attr); 665d6eb71a6SVaibhav Jain 666e36f6fe1SVaibhav Jain afu->attr_eb.attr.name = "afu_err_buff"; 667e36f6fe1SVaibhav Jain afu->attr_eb.attr.mode = S_IRUGO; 668e36f6fe1SVaibhav Jain afu->attr_eb.size = afu->eb_len; 669e36f6fe1SVaibhav Jain afu->attr_eb.read = afu_eb_read; 670e36f6fe1SVaibhav Jain 671e36f6fe1SVaibhav Jain rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 672e36f6fe1SVaibhav Jain if (rc) { 673e36f6fe1SVaibhav Jain dev_err(&afu->dev, 674e36f6fe1SVaibhav Jain "Unable to create eb attr for the afu. Err(%d)\n", 675e36f6fe1SVaibhav Jain rc); 676e36f6fe1SVaibhav Jain goto err; 677e36f6fe1SVaibhav Jain } 678e36f6fe1SVaibhav Jain } 679e36f6fe1SVaibhav Jain 680b087e619SIan Munsie for (i = 0; i < afu->crs_num; i++) { 681b087e619SIan Munsie cr = cxl_sysfs_afu_new_cr(afu, i); 682b087e619SIan Munsie if (IS_ERR(cr)) { 683b087e619SIan Munsie rc = PTR_ERR(cr); 684b087e619SIan Munsie goto err1; 685b087e619SIan Munsie } 686b087e619SIan Munsie list_add(&cr->list, &afu->crs); 687b087e619SIan Munsie } 688b087e619SIan Munsie 689f204e0b8SIan Munsie return 0; 690f204e0b8SIan Munsie 691b087e619SIan Munsie err1: 692b087e619SIan Munsie cxl_sysfs_afu_remove(afu); 693b087e619SIan Munsie return rc; 694f204e0b8SIan Munsie err: 695e36f6fe1SVaibhav Jain /* reset the eb_len as we havent created the bin attr */ 696e36f6fe1SVaibhav Jain afu->eb_len = 0; 697e36f6fe1SVaibhav Jain 6984752876cSChristophe Lombard for (i--; i >= 0; i--) { 6994752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 7004752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7014752876cSChristophe Lombard CXL_AFU_ATTRS)) 702f204e0b8SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 7034752876cSChristophe Lombard } 704f204e0b8SIan Munsie return rc; 705f204e0b8SIan Munsie } 706f204e0b8SIan Munsie 707f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 708f204e0b8SIan Munsie { 7094752876cSChristophe Lombard struct device_attribute *dev_attr; 710f204e0b8SIan Munsie int i, rc; 711f204e0b8SIan Munsie 712f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7134752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7144752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7154752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) { 716f204e0b8SIan Munsie if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 717f204e0b8SIan Munsie goto err; 718f204e0b8SIan Munsie } 7194752876cSChristophe Lombard } 720f204e0b8SIan Munsie 721f204e0b8SIan Munsie return 0; 722f204e0b8SIan Munsie 723f204e0b8SIan Munsie err: 7244752876cSChristophe Lombard for (i--; i >= 0; i--) { 7254752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7264752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7274752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 728f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 7294752876cSChristophe Lombard } 730f204e0b8SIan Munsie return rc; 731f204e0b8SIan Munsie } 732f204e0b8SIan Munsie 733f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 734f204e0b8SIan Munsie { 7354752876cSChristophe Lombard struct device_attribute *dev_attr; 736f204e0b8SIan Munsie int i; 737f204e0b8SIan Munsie 7384752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7394752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7404752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7414752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 742f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 743f204e0b8SIan Munsie } 7444752876cSChristophe Lombard } 745