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); 65c2be663dSChristophe Lombard u64 psl_tb, delta; 66e009a7e8SFrederic Barrat 67c2be663dSChristophe Lombard /* Recompute the status only in native mode */ 68c2be663dSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 69c2be663dSChristophe Lombard psl_tb = adapter->native->sl_ops->timebase_read(adapter); 70c2be663dSChristophe Lombard delta = abs(mftb() - psl_tb); 71c2be663dSChristophe Lombard 72c2be663dSChristophe Lombard /* CORE TB and PSL TB difference <= 16usecs ? */ 73c2be663dSChristophe Lombard adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false; 74c2be663dSChristophe Lombard pr_devel("PSL timebase %s - delta: 0x%016llx\n", 75c2be663dSChristophe Lombard (tb_to_ns(delta) < 16000) ? "synchronized" : 76c2be663dSChristophe Lombard "not synchronized", tb_to_ns(delta)); 77c2be663dSChristophe Lombard } 78e009a7e8SFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced); 79e009a7e8SFrederic Barrat } 80e009a7e8SFrederic Barrat 8162fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device, 8262fa19d4SRyan Grimm struct device_attribute *attr, 8362fa19d4SRyan Grimm const char *buf, size_t count) 8462fa19d4SRyan Grimm { 8562fa19d4SRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 8662fa19d4SRyan Grimm int rc; 8762fa19d4SRyan Grimm int val; 8862fa19d4SRyan Grimm 8962fa19d4SRyan Grimm rc = sscanf(buf, "%i", &val); 9070b565bbSVaibhav Jain if ((rc != 1) || (val != 1 && val != -1)) 9162fa19d4SRyan Grimm return -EINVAL; 9262fa19d4SRyan Grimm 9370b565bbSVaibhav Jain /* 9470b565bbSVaibhav Jain * See if we can lock the context mapping that's only allowed 9570b565bbSVaibhav Jain * when there are no contexts attached to the adapter. Once 9670b565bbSVaibhav Jain * taken this will also prevent any context from getting activated. 9770b565bbSVaibhav Jain */ 9870b565bbSVaibhav Jain if (val == 1) { 9970b565bbSVaibhav Jain rc = cxl_adapter_context_lock(adapter); 10070b565bbSVaibhav Jain if (rc) 10170b565bbSVaibhav Jain goto out; 10270b565bbSVaibhav Jain 10370b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 10470b565bbSVaibhav Jain /* In case reset failed release context lock */ 10570b565bbSVaibhav Jain if (rc) 10670b565bbSVaibhav Jain cxl_adapter_context_unlock(adapter); 10770b565bbSVaibhav Jain 10870b565bbSVaibhav Jain } else if (val == -1) { 10970b565bbSVaibhav Jain /* Perform a forced adapter reset */ 11070b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 11170b565bbSVaibhav Jain } 11270b565bbSVaibhav Jain 11370b565bbSVaibhav Jain out: 11470b565bbSVaibhav Jain return rc ? rc : count; 11562fa19d4SRyan Grimm } 11662fa19d4SRyan Grimm 11795bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device, 11895bc11bcSRyan Grimm struct device_attribute *attr, 11995bc11bcSRyan Grimm char *buf) 12095bc11bcSRyan Grimm { 12195bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 12295bc11bcSRyan Grimm 12395bc11bcSRyan Grimm if (!adapter->perst_loads_image) 12495bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "none\n"); 12595bc11bcSRyan Grimm 12695bc11bcSRyan Grimm if (adapter->perst_select_user) 12795bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "user\n"); 12895bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "factory\n"); 12995bc11bcSRyan Grimm } 13095bc11bcSRyan Grimm 13195bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device, 13295bc11bcSRyan Grimm struct device_attribute *attr, 13395bc11bcSRyan Grimm const char *buf, size_t count) 13495bc11bcSRyan Grimm { 13595bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 13695bc11bcSRyan Grimm int rc; 13795bc11bcSRyan Grimm 13895bc11bcSRyan Grimm if (!strncmp(buf, "none", 4)) 13995bc11bcSRyan Grimm adapter->perst_loads_image = false; 14095bc11bcSRyan Grimm else if (!strncmp(buf, "user", 4)) { 14195bc11bcSRyan Grimm adapter->perst_select_user = true; 14295bc11bcSRyan Grimm adapter->perst_loads_image = true; 14395bc11bcSRyan Grimm } else if (!strncmp(buf, "factory", 7)) { 14495bc11bcSRyan Grimm adapter->perst_select_user = false; 14595bc11bcSRyan Grimm adapter->perst_loads_image = true; 14695bc11bcSRyan Grimm } else 14795bc11bcSRyan Grimm return -EINVAL; 14895bc11bcSRyan Grimm 14995bc11bcSRyan Grimm if ((rc = cxl_update_image_control(adapter))) 15095bc11bcSRyan Grimm return rc; 15195bc11bcSRyan Grimm 15295bc11bcSRyan Grimm return count; 15395bc11bcSRyan Grimm } 15495bc11bcSRyan Grimm 15513e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device, 15613e68d8bSDaniel Axtens struct device_attribute *attr, 15713e68d8bSDaniel Axtens char *buf) 15813e68d8bSDaniel Axtens { 15913e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 16013e68d8bSDaniel Axtens 16113e68d8bSDaniel Axtens return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image); 16213e68d8bSDaniel Axtens } 16313e68d8bSDaniel Axtens 16413e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device, 16513e68d8bSDaniel Axtens struct device_attribute *attr, 16613e68d8bSDaniel Axtens const char *buf, size_t count) 16713e68d8bSDaniel Axtens { 16813e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 16913e68d8bSDaniel Axtens int rc; 17013e68d8bSDaniel Axtens int val; 17113e68d8bSDaniel Axtens 17213e68d8bSDaniel Axtens rc = sscanf(buf, "%i", &val); 17313e68d8bSDaniel Axtens if ((rc != 1) || !(val == 1 || val == 0)) 17413e68d8bSDaniel Axtens return -EINVAL; 17513e68d8bSDaniel Axtens 17613e68d8bSDaniel Axtens adapter->perst_same_image = (val == 1 ? true : false); 17713e68d8bSDaniel Axtens return count; 17813e68d8bSDaniel Axtens } 17913e68d8bSDaniel Axtens 180f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = { 181f204e0b8SIan Munsie __ATTR_RO(caia_version), 182f204e0b8SIan Munsie __ATTR_RO(psl_revision), 183f204e0b8SIan Munsie __ATTR_RO(base_image), 184f204e0b8SIan Munsie __ATTR_RO(image_loaded), 185e009a7e8SFrederic Barrat __ATTR_RO(psl_timebase_synced), 18695bc11bcSRyan Grimm __ATTR_RW(load_image_on_perst), 18713e68d8bSDaniel Axtens __ATTR_RW(perst_reloads_same_image), 18862fa19d4SRyan Grimm __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), 189f204e0b8SIan Munsie }; 190f204e0b8SIan Munsie 191f204e0b8SIan Munsie 192f204e0b8SIan Munsie /********* AFU master specific attributes **********************************/ 193f204e0b8SIan Munsie 194f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device, 195f204e0b8SIan Munsie struct device_attribute *attr, 196f204e0b8SIan Munsie char *buf) 197f204e0b8SIan Munsie { 198f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 199f204e0b8SIan Munsie 200f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 201f204e0b8SIan Munsie } 202f204e0b8SIan Munsie 203f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device, 204f204e0b8SIan Munsie struct device_attribute *attr, 205f204e0b8SIan Munsie char *buf) 206f204e0b8SIan Munsie { 207f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 208f204e0b8SIan Munsie 209cbffa3a5SChristophe Lombard return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset); 210f204e0b8SIan Munsie } 211f204e0b8SIan Munsie 212f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device, 213f204e0b8SIan Munsie struct device_attribute *attr, 214f204e0b8SIan Munsie char *buf) 215f204e0b8SIan Munsie { 216f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 217f204e0b8SIan Munsie 218f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 219f204e0b8SIan Munsie } 220f204e0b8SIan Munsie 221f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = { 222f204e0b8SIan Munsie __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 223f204e0b8SIan Munsie __ATTR_RO(pp_mmio_off), 224f204e0b8SIan Munsie __ATTR_RO(pp_mmio_len), 225f204e0b8SIan Munsie }; 226f204e0b8SIan Munsie 227f204e0b8SIan Munsie 228f204e0b8SIan Munsie /********* AFU attributes **************************************************/ 229f204e0b8SIan Munsie 230f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device, 231f204e0b8SIan Munsie struct device_attribute *attr, 232f204e0b8SIan Munsie char *buf) 233f204e0b8SIan Munsie { 234f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 235f204e0b8SIan Munsie 236f204e0b8SIan Munsie if (afu->pp_size) 237f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 238f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 239f204e0b8SIan Munsie } 240f204e0b8SIan Munsie 241f204e0b8SIan Munsie static ssize_t reset_store_afu(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 int rc; 247f204e0b8SIan Munsie 248f204e0b8SIan Munsie /* Not safe to reset if it is currently in use */ 249ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 250f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) { 251f204e0b8SIan Munsie rc = -EBUSY; 252f204e0b8SIan Munsie goto err; 253f204e0b8SIan Munsie } 254f204e0b8SIan Munsie 2555be587b1SFrederic Barrat if ((rc = cxl_ops->afu_reset(afu))) 256f204e0b8SIan Munsie goto err; 257f204e0b8SIan Munsie 258f204e0b8SIan Munsie rc = count; 259f204e0b8SIan Munsie err: 260ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 261f204e0b8SIan Munsie return rc; 262f204e0b8SIan Munsie } 263f204e0b8SIan Munsie 264f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device, 265f204e0b8SIan Munsie struct device_attribute *attr, 266f204e0b8SIan Munsie char *buf) 267f204e0b8SIan Munsie { 268f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 269f204e0b8SIan Munsie 270f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 271f204e0b8SIan Munsie } 272f204e0b8SIan Munsie 273f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device, 274f204e0b8SIan Munsie struct device_attribute *attr, 275f204e0b8SIan Munsie char *buf) 276f204e0b8SIan Munsie { 277f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 278f204e0b8SIan Munsie 279f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 280f204e0b8SIan Munsie } 281f204e0b8SIan Munsie 282f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device, 283f204e0b8SIan Munsie struct device_attribute *attr, 284f204e0b8SIan Munsie const char *buf, size_t count) 285f204e0b8SIan Munsie { 286f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 287f204e0b8SIan Munsie ssize_t ret; 288f204e0b8SIan Munsie int irqs_max; 289f204e0b8SIan Munsie 290f204e0b8SIan Munsie ret = sscanf(buf, "%i", &irqs_max); 291f204e0b8SIan Munsie if (ret != 1) 292f204e0b8SIan Munsie return -EINVAL; 293f204e0b8SIan Munsie 294f204e0b8SIan Munsie if (irqs_max < afu->pp_irqs) 295f204e0b8SIan Munsie return -EINVAL; 296f204e0b8SIan Munsie 2974752876cSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 298f204e0b8SIan Munsie if (irqs_max > afu->adapter->user_irqs) 299f204e0b8SIan Munsie return -EINVAL; 3004752876cSChristophe Lombard } else { 3014752876cSChristophe Lombard /* pHyp sets a per-AFU limit */ 3024752876cSChristophe Lombard if (irqs_max > afu->guest->max_ints) 3034752876cSChristophe Lombard return -EINVAL; 3044752876cSChristophe Lombard } 305f204e0b8SIan Munsie 306f204e0b8SIan Munsie afu->irqs_max = irqs_max; 307f204e0b8SIan Munsie return count; 308f204e0b8SIan Munsie } 309f204e0b8SIan Munsie 310f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device, 311f204e0b8SIan Munsie struct device_attribute *attr, char *buf) 312f204e0b8SIan Munsie { 313f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 314f204e0b8SIan Munsie char *p = buf, *end = buf + PAGE_SIZE; 315f204e0b8SIan Munsie 316f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DEDICATED) 317f204e0b8SIan Munsie p += scnprintf(p, end - p, "dedicated_process\n"); 318f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DIRECTED) 319f204e0b8SIan Munsie p += scnprintf(p, end - p, "afu_directed\n"); 320f204e0b8SIan Munsie return (p - buf); 321f204e0b8SIan Munsie } 322f204e0b8SIan Munsie 323f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device, 324f204e0b8SIan Munsie struct device_attribute *attr, 325f204e0b8SIan Munsie char *buf) 326f204e0b8SIan Munsie { 327f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 328f204e0b8SIan Munsie 329f204e0b8SIan Munsie switch (afu->prefault_mode) { 330f204e0b8SIan Munsie case CXL_PREFAULT_WED: 331f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 332f204e0b8SIan Munsie case CXL_PREFAULT_ALL: 333f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "all\n"); 334f204e0b8SIan Munsie default: 335f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 336f204e0b8SIan Munsie } 337f204e0b8SIan Munsie } 338f204e0b8SIan Munsie 339f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device, 340f204e0b8SIan Munsie struct device_attribute *attr, 341f204e0b8SIan Munsie const char *buf, size_t count) 342f204e0b8SIan Munsie { 343f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 344f204e0b8SIan Munsie enum prefault_modes mode = -1; 345f204e0b8SIan Munsie 346*b6c84ba2SVaibhav Jain if (!strncmp(buf, "none", 4)) 347*b6c84ba2SVaibhav Jain mode = CXL_PREFAULT_NONE; 348*b6c84ba2SVaibhav Jain else { 349*b6c84ba2SVaibhav Jain if (!radix_enabled()) { 350*b6c84ba2SVaibhav Jain 351*b6c84ba2SVaibhav Jain /* only allowed when not in radix mode */ 352f204e0b8SIan Munsie if (!strncmp(buf, "work_element_descriptor", 23)) 353f204e0b8SIan Munsie mode = CXL_PREFAULT_WED; 354f204e0b8SIan Munsie if (!strncmp(buf, "all", 3)) 355f204e0b8SIan Munsie mode = CXL_PREFAULT_ALL; 356*b6c84ba2SVaibhav Jain } else { 357*b6c84ba2SVaibhav Jain dev_err(device, "Cannot prefault with radix enabled\n"); 358*b6c84ba2SVaibhav Jain } 359*b6c84ba2SVaibhav Jain } 360f204e0b8SIan Munsie 361f204e0b8SIan Munsie if (mode == -1) 362f204e0b8SIan Munsie return -EINVAL; 363f204e0b8SIan Munsie 364f204e0b8SIan Munsie afu->prefault_mode = mode; 365f204e0b8SIan Munsie return count; 366f204e0b8SIan Munsie } 367f204e0b8SIan Munsie 368f204e0b8SIan Munsie static ssize_t mode_show(struct device *device, 369f204e0b8SIan Munsie struct device_attribute *attr, 370f204e0b8SIan Munsie char *buf) 371f204e0b8SIan Munsie { 372f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 373f204e0b8SIan Munsie 374f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DEDICATED) 375f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 376f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DIRECTED) 377f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 378f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 379f204e0b8SIan Munsie } 380f204e0b8SIan Munsie 381f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr, 382f204e0b8SIan Munsie const char *buf, size_t count) 383f204e0b8SIan Munsie { 384f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 385f204e0b8SIan Munsie int old_mode, mode = -1; 386f204e0b8SIan Munsie int rc = -EBUSY; 387f204e0b8SIan Munsie 388f204e0b8SIan Munsie /* can't change this if we have a user */ 389ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 390f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) 391f204e0b8SIan Munsie goto err; 392f204e0b8SIan Munsie 393f204e0b8SIan Munsie if (!strncmp(buf, "dedicated_process", 17)) 394f204e0b8SIan Munsie mode = CXL_MODE_DEDICATED; 395f204e0b8SIan Munsie if (!strncmp(buf, "afu_directed", 12)) 396f204e0b8SIan Munsie mode = CXL_MODE_DIRECTED; 397f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 398f204e0b8SIan Munsie mode = 0; 399f204e0b8SIan Munsie 400f204e0b8SIan Munsie if (mode == -1) { 401f204e0b8SIan Munsie rc = -EINVAL; 402f204e0b8SIan Munsie goto err; 403f204e0b8SIan Munsie } 404f204e0b8SIan Munsie 405f204e0b8SIan Munsie /* 4065be587b1SFrederic Barrat * afu_deactivate_mode needs to be done outside the lock, prevent 407f204e0b8SIan Munsie * other contexts coming in before we are ready: 408f204e0b8SIan Munsie */ 409f204e0b8SIan Munsie old_mode = afu->current_mode; 410f204e0b8SIan Munsie afu->current_mode = 0; 411f204e0b8SIan Munsie afu->num_procs = 0; 412f204e0b8SIan Munsie 413ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 414f204e0b8SIan Munsie 4155be587b1SFrederic Barrat if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) 416f204e0b8SIan Munsie return rc; 4175be587b1SFrederic Barrat if ((rc = cxl_ops->afu_activate_mode(afu, mode))) 418f204e0b8SIan Munsie return rc; 419f204e0b8SIan Munsie 420f204e0b8SIan Munsie return count; 421f204e0b8SIan Munsie err: 422ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 423f204e0b8SIan Munsie return rc; 424f204e0b8SIan Munsie } 425f204e0b8SIan Munsie 426f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device, 427f204e0b8SIan Munsie struct device_attribute *attr, 428f204e0b8SIan Munsie char *buf) 429f204e0b8SIan Munsie { 430f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 431f204e0b8SIan Munsie } 432f204e0b8SIan Munsie 433f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device, 434f204e0b8SIan Munsie struct device_attribute *attr, 435f204e0b8SIan Munsie char *buf) 436f204e0b8SIan Munsie { 437f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 438f204e0b8SIan Munsie } 439f204e0b8SIan Munsie 440e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 441e36f6fe1SVaibhav Jain struct bin_attribute *bin_attr, char *buf, 442e36f6fe1SVaibhav Jain loff_t off, size_t count) 443e36f6fe1SVaibhav Jain { 44485016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj)); 445e36f6fe1SVaibhav Jain 4465be587b1SFrederic Barrat return cxl_ops->afu_read_err_buffer(afu, buf, off, count); 447e36f6fe1SVaibhav Jain } 448e36f6fe1SVaibhav Jain 449f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = { 450f204e0b8SIan Munsie __ATTR_RO(mmio_size), 451f204e0b8SIan Munsie __ATTR_RO(irqs_min), 452f204e0b8SIan Munsie __ATTR_RW(irqs_max), 453f204e0b8SIan Munsie __ATTR_RO(modes_supported), 454f204e0b8SIan Munsie __ATTR_RW(mode), 455f204e0b8SIan Munsie __ATTR_RW(prefault_mode), 456f204e0b8SIan Munsie __ATTR_RO(api_version), 457f204e0b8SIan Munsie __ATTR_RO(api_version_compatible), 458f204e0b8SIan Munsie __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 459f204e0b8SIan Munsie }; 460f204e0b8SIan Munsie 461f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter) 462f204e0b8SIan Munsie { 4634752876cSChristophe Lombard struct device_attribute *dev_attr; 464f204e0b8SIan Munsie int i, rc; 465f204e0b8SIan Munsie 466f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4674752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4684752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4694752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) { 4704752876cSChristophe Lombard if ((rc = device_create_file(&adapter->dev, dev_attr))) 471f204e0b8SIan Munsie goto err; 472f204e0b8SIan Munsie } 4734752876cSChristophe Lombard } 474f204e0b8SIan Munsie return 0; 475f204e0b8SIan Munsie err: 4764752876cSChristophe Lombard for (i--; i >= 0; i--) { 4774752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4784752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4794752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4804752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4814752876cSChristophe Lombard } 482f204e0b8SIan Munsie return rc; 483f204e0b8SIan Munsie } 4844752876cSChristophe Lombard 485f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter) 486f204e0b8SIan Munsie { 4874752876cSChristophe Lombard struct device_attribute *dev_attr; 488f204e0b8SIan Munsie int i; 489f204e0b8SIan Munsie 4904752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4914752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4924752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4934752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4944752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4954752876cSChristophe Lombard } 496f204e0b8SIan Munsie } 497f204e0b8SIan Munsie 498b087e619SIan Munsie struct afu_config_record { 499b087e619SIan Munsie struct kobject kobj; 500b087e619SIan Munsie struct bin_attribute config_attr; 501b087e619SIan Munsie struct list_head list; 502b087e619SIan Munsie int cr; 503b087e619SIan Munsie u16 device; 504b087e619SIan Munsie u16 vendor; 505b087e619SIan Munsie u32 class; 506b087e619SIan Munsie }; 507b087e619SIan Munsie 508b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 509b087e619SIan Munsie 510b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj, 511b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 512b087e619SIan Munsie { 513b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 514b087e619SIan Munsie 515b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 516b087e619SIan Munsie } 517b087e619SIan Munsie 518b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj, 519b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 520b087e619SIan Munsie { 521b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 522b087e619SIan Munsie 523b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); 524b087e619SIan Munsie } 525b087e619SIan Munsie 526b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj, 527b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 528b087e619SIan Munsie { 529b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 530b087e619SIan Munsie 531b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); 532b087e619SIan Munsie } 533b087e619SIan Munsie 534b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 535b087e619SIan Munsie struct bin_attribute *bin_attr, char *buf, 536b087e619SIan Munsie loff_t off, size_t count) 537b087e619SIan Munsie { 538b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 53985016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent)); 540b087e619SIan Munsie 5415be587b1SFrederic Barrat u64 i, j, val, rc; 542b087e619SIan Munsie 543b087e619SIan Munsie for (i = 0; i < count;) { 5445be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); 5455be587b1SFrederic Barrat if (rc) 5465be587b1SFrederic Barrat val = ~0ULL; 547b087e619SIan Munsie for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 548b087e619SIan Munsie buf[i] = (val >> (j * 8)) & 0xff; 549b087e619SIan Munsie } 550b087e619SIan Munsie 551b087e619SIan Munsie return count; 552b087e619SIan Munsie } 553b087e619SIan Munsie 554b087e619SIan Munsie static struct kobj_attribute vendor_attribute = 555b087e619SIan Munsie __ATTR_RO(vendor); 556b087e619SIan Munsie static struct kobj_attribute device_attribute = 557b087e619SIan Munsie __ATTR_RO(device); 558b087e619SIan Munsie static struct kobj_attribute class_attribute = 559b087e619SIan Munsie __ATTR_RO(class); 560b087e619SIan Munsie 561b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = { 562b087e619SIan Munsie &vendor_attribute.attr, 563b087e619SIan Munsie &device_attribute.attr, 564b087e619SIan Munsie &class_attribute.attr, 565b087e619SIan Munsie NULL, 566b087e619SIan Munsie }; 567b087e619SIan Munsie 568b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj) 569b087e619SIan Munsie { 570b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 571b087e619SIan Munsie 572b087e619SIan Munsie kfree(cr); 573b087e619SIan Munsie } 574b087e619SIan Munsie 575b087e619SIan Munsie static struct kobj_type afu_config_record_type = { 576b087e619SIan Munsie .sysfs_ops = &kobj_sysfs_ops, 577b087e619SIan Munsie .release = release_afu_config_record, 578b087e619SIan Munsie .default_attrs = afu_cr_attrs, 579b087e619SIan Munsie }; 580b087e619SIan Munsie 581b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 582b087e619SIan Munsie { 583b087e619SIan Munsie struct afu_config_record *cr; 584b087e619SIan Munsie int rc; 585b087e619SIan Munsie 586b087e619SIan Munsie cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 587b087e619SIan Munsie if (!cr) 588b087e619SIan Munsie return ERR_PTR(-ENOMEM); 589b087e619SIan Munsie 590b087e619SIan Munsie cr->cr = cr_idx; 5915be587b1SFrederic Barrat 5925be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); 5935be587b1SFrederic Barrat if (rc) 5945be587b1SFrederic Barrat goto err; 5955be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); 5965be587b1SFrederic Barrat if (rc) 5975be587b1SFrederic Barrat goto err; 5985be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); 5995be587b1SFrederic Barrat if (rc) 6005be587b1SFrederic Barrat goto err; 6015be587b1SFrederic Barrat cr->class >>= 8; 602b087e619SIan Munsie 603b087e619SIan Munsie /* 604b087e619SIan Munsie * Export raw AFU PCIe like config record. For now this is read only by 605b087e619SIan Munsie * root - we can expand that later to be readable by non-root and maybe 6064752876cSChristophe Lombard * even writable provided we have a good use-case. Once we support 607b087e619SIan Munsie * exposing AFUs through a virtual PHB they will get that for free from 608b087e619SIan Munsie * Linux' PCI infrastructure, but until then it's not clear that we 609b087e619SIan Munsie * need it for anything since the main use case is just identifying 610b087e619SIan Munsie * AFUs, which can be done via the vendor, device and class attributes. 611b087e619SIan Munsie */ 612b087e619SIan Munsie sysfs_bin_attr_init(&cr->config_attr); 613b087e619SIan Munsie cr->config_attr.attr.name = "config"; 614b087e619SIan Munsie cr->config_attr.attr.mode = S_IRUSR; 615b087e619SIan Munsie cr->config_attr.size = afu->crs_len; 616b087e619SIan Munsie cr->config_attr.read = afu_read_config; 617b087e619SIan Munsie 618b087e619SIan Munsie rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 619b087e619SIan Munsie &afu->dev.kobj, "cr%i", cr->cr); 620b087e619SIan Munsie if (rc) 621b087e619SIan Munsie goto err; 622b087e619SIan Munsie 623b087e619SIan Munsie rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 624b087e619SIan Munsie if (rc) 625b087e619SIan Munsie goto err1; 626b087e619SIan Munsie 627b087e619SIan Munsie rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 628b087e619SIan Munsie if (rc) 629b087e619SIan Munsie goto err2; 630b087e619SIan Munsie 631b087e619SIan Munsie return cr; 632b087e619SIan Munsie err2: 633b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 634b087e619SIan Munsie err1: 635b087e619SIan Munsie kobject_put(&cr->kobj); 636b087e619SIan Munsie return ERR_PTR(rc); 637b087e619SIan Munsie err: 638b087e619SIan Munsie kfree(cr); 639b087e619SIan Munsie return ERR_PTR(rc); 640b087e619SIan Munsie } 641b087e619SIan Munsie 642b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu) 643b087e619SIan Munsie { 6444752876cSChristophe Lombard struct device_attribute *dev_attr; 645b087e619SIan Munsie struct afu_config_record *cr, *tmp; 646b087e619SIan Munsie int i; 647b087e619SIan Munsie 648e36f6fe1SVaibhav Jain /* remove the err buffer bin attribute */ 649e36f6fe1SVaibhav Jain if (afu->eb_len) 650e36f6fe1SVaibhav Jain device_remove_bin_file(&afu->dev, &afu->attr_eb); 651e36f6fe1SVaibhav Jain 6524752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6534752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6544752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6554752876cSChristophe Lombard CXL_AFU_ATTRS)) 656b087e619SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 6574752876cSChristophe Lombard } 658b087e619SIan Munsie 659b087e619SIan Munsie list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 660b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 661b087e619SIan Munsie kobject_put(&cr->kobj); 662b087e619SIan Munsie } 663b087e619SIan Munsie } 664b087e619SIan Munsie 665f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu) 666f204e0b8SIan Munsie { 6674752876cSChristophe Lombard struct device_attribute *dev_attr; 668b087e619SIan Munsie struct afu_config_record *cr; 669f204e0b8SIan Munsie int i, rc; 670f204e0b8SIan Munsie 671b087e619SIan Munsie INIT_LIST_HEAD(&afu->crs); 672b087e619SIan Munsie 673f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6744752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6754752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6764752876cSChristophe Lombard CXL_AFU_ATTRS)) { 677f204e0b8SIan Munsie if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 678f204e0b8SIan Munsie goto err; 679f204e0b8SIan Munsie } 6804752876cSChristophe Lombard } 681f204e0b8SIan Munsie 682e36f6fe1SVaibhav Jain /* conditionally create the add the binary file for error info buffer */ 683e36f6fe1SVaibhav Jain if (afu->eb_len) { 684d6eb71a6SVaibhav Jain sysfs_attr_init(&afu->attr_eb.attr); 685d6eb71a6SVaibhav Jain 686e36f6fe1SVaibhav Jain afu->attr_eb.attr.name = "afu_err_buff"; 687e36f6fe1SVaibhav Jain afu->attr_eb.attr.mode = S_IRUGO; 688e36f6fe1SVaibhav Jain afu->attr_eb.size = afu->eb_len; 689e36f6fe1SVaibhav Jain afu->attr_eb.read = afu_eb_read; 690e36f6fe1SVaibhav Jain 691e36f6fe1SVaibhav Jain rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 692e36f6fe1SVaibhav Jain if (rc) { 693e36f6fe1SVaibhav Jain dev_err(&afu->dev, 694e36f6fe1SVaibhav Jain "Unable to create eb attr for the afu. Err(%d)\n", 695e36f6fe1SVaibhav Jain rc); 696e36f6fe1SVaibhav Jain goto err; 697e36f6fe1SVaibhav Jain } 698e36f6fe1SVaibhav Jain } 699e36f6fe1SVaibhav Jain 700b087e619SIan Munsie for (i = 0; i < afu->crs_num; i++) { 701b087e619SIan Munsie cr = cxl_sysfs_afu_new_cr(afu, i); 702b087e619SIan Munsie if (IS_ERR(cr)) { 703b087e619SIan Munsie rc = PTR_ERR(cr); 704b087e619SIan Munsie goto err1; 705b087e619SIan Munsie } 706b087e619SIan Munsie list_add(&cr->list, &afu->crs); 707b087e619SIan Munsie } 708b087e619SIan Munsie 709f204e0b8SIan Munsie return 0; 710f204e0b8SIan Munsie 711b087e619SIan Munsie err1: 712b087e619SIan Munsie cxl_sysfs_afu_remove(afu); 713b087e619SIan Munsie return rc; 714f204e0b8SIan Munsie err: 715e36f6fe1SVaibhav Jain /* reset the eb_len as we havent created the bin attr */ 716e36f6fe1SVaibhav Jain afu->eb_len = 0; 717e36f6fe1SVaibhav Jain 7184752876cSChristophe Lombard for (i--; i >= 0; i--) { 7194752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 7204752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7214752876cSChristophe Lombard CXL_AFU_ATTRS)) 722f204e0b8SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 7234752876cSChristophe Lombard } 724f204e0b8SIan Munsie return rc; 725f204e0b8SIan Munsie } 726f204e0b8SIan Munsie 727f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 728f204e0b8SIan Munsie { 7294752876cSChristophe Lombard struct device_attribute *dev_attr; 730f204e0b8SIan Munsie int i, rc; 731f204e0b8SIan Munsie 732f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7334752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7344752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7354752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) { 736f204e0b8SIan Munsie if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 737f204e0b8SIan Munsie goto err; 738f204e0b8SIan Munsie } 7394752876cSChristophe Lombard } 740f204e0b8SIan Munsie 741f204e0b8SIan Munsie return 0; 742f204e0b8SIan Munsie 743f204e0b8SIan Munsie err: 7444752876cSChristophe Lombard for (i--; i >= 0; i--) { 7454752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7464752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7474752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 748f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 7494752876cSChristophe Lombard } 750f204e0b8SIan Munsie return rc; 751f204e0b8SIan Munsie } 752f204e0b8SIan Munsie 753f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 754f204e0b8SIan Munsie { 7554752876cSChristophe Lombard struct device_attribute *dev_attr; 756f204e0b8SIan Munsie int i; 757f204e0b8SIan Munsie 7584752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7594752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7604752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7614752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 762f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 763f204e0b8SIan Munsie } 7644752876cSChristophe Lombard } 765