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); 65*c2be663dSChristophe Lombard u64 psl_tb, delta; 66e009a7e8SFrederic Barrat 67*c2be663dSChristophe Lombard /* Recompute the status only in native mode */ 68*c2be663dSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 69*c2be663dSChristophe Lombard psl_tb = adapter->native->sl_ops->timebase_read(adapter); 70*c2be663dSChristophe Lombard delta = abs(mftb() - psl_tb); 71*c2be663dSChristophe Lombard 72*c2be663dSChristophe Lombard /* CORE TB and PSL TB difference <= 16usecs ? */ 73*c2be663dSChristophe Lombard adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false; 74*c2be663dSChristophe Lombard pr_devel("PSL timebase %s - delta: 0x%016llx\n", 75*c2be663dSChristophe Lombard (tb_to_ns(delta) < 16000) ? "synchronized" : 76*c2be663dSChristophe Lombard "not synchronized", tb_to_ns(delta)); 77*c2be663dSChristophe 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 346f204e0b8SIan Munsie if (!strncmp(buf, "work_element_descriptor", 23)) 347f204e0b8SIan Munsie mode = CXL_PREFAULT_WED; 348f204e0b8SIan Munsie if (!strncmp(buf, "all", 3)) 349f204e0b8SIan Munsie mode = CXL_PREFAULT_ALL; 350f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 351f204e0b8SIan Munsie mode = CXL_PREFAULT_NONE; 352f204e0b8SIan Munsie 353f204e0b8SIan Munsie if (mode == -1) 354f204e0b8SIan Munsie return -EINVAL; 355f204e0b8SIan Munsie 356f204e0b8SIan Munsie afu->prefault_mode = mode; 357f204e0b8SIan Munsie return count; 358f204e0b8SIan Munsie } 359f204e0b8SIan Munsie 360f204e0b8SIan Munsie static ssize_t mode_show(struct device *device, 361f204e0b8SIan Munsie struct device_attribute *attr, 362f204e0b8SIan Munsie char *buf) 363f204e0b8SIan Munsie { 364f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 365f204e0b8SIan Munsie 366f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DEDICATED) 367f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 368f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DIRECTED) 369f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 370f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 371f204e0b8SIan Munsie } 372f204e0b8SIan Munsie 373f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr, 374f204e0b8SIan Munsie const char *buf, size_t count) 375f204e0b8SIan Munsie { 376f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 377f204e0b8SIan Munsie int old_mode, mode = -1; 378f204e0b8SIan Munsie int rc = -EBUSY; 379f204e0b8SIan Munsie 380f204e0b8SIan Munsie /* can't change this if we have a user */ 381ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 382f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) 383f204e0b8SIan Munsie goto err; 384f204e0b8SIan Munsie 385f204e0b8SIan Munsie if (!strncmp(buf, "dedicated_process", 17)) 386f204e0b8SIan Munsie mode = CXL_MODE_DEDICATED; 387f204e0b8SIan Munsie if (!strncmp(buf, "afu_directed", 12)) 388f204e0b8SIan Munsie mode = CXL_MODE_DIRECTED; 389f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 390f204e0b8SIan Munsie mode = 0; 391f204e0b8SIan Munsie 392f204e0b8SIan Munsie if (mode == -1) { 393f204e0b8SIan Munsie rc = -EINVAL; 394f204e0b8SIan Munsie goto err; 395f204e0b8SIan Munsie } 396f204e0b8SIan Munsie 397f204e0b8SIan Munsie /* 3985be587b1SFrederic Barrat * afu_deactivate_mode needs to be done outside the lock, prevent 399f204e0b8SIan Munsie * other contexts coming in before we are ready: 400f204e0b8SIan Munsie */ 401f204e0b8SIan Munsie old_mode = afu->current_mode; 402f204e0b8SIan Munsie afu->current_mode = 0; 403f204e0b8SIan Munsie afu->num_procs = 0; 404f204e0b8SIan Munsie 405ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 406f204e0b8SIan Munsie 4075be587b1SFrederic Barrat if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) 408f204e0b8SIan Munsie return rc; 4095be587b1SFrederic Barrat if ((rc = cxl_ops->afu_activate_mode(afu, mode))) 410f204e0b8SIan Munsie return rc; 411f204e0b8SIan Munsie 412f204e0b8SIan Munsie return count; 413f204e0b8SIan Munsie err: 414ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 415f204e0b8SIan Munsie return rc; 416f204e0b8SIan Munsie } 417f204e0b8SIan Munsie 418f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device, 419f204e0b8SIan Munsie struct device_attribute *attr, 420f204e0b8SIan Munsie char *buf) 421f204e0b8SIan Munsie { 422f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 423f204e0b8SIan Munsie } 424f204e0b8SIan Munsie 425f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device, 426f204e0b8SIan Munsie struct device_attribute *attr, 427f204e0b8SIan Munsie char *buf) 428f204e0b8SIan Munsie { 429f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 430f204e0b8SIan Munsie } 431f204e0b8SIan Munsie 432e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 433e36f6fe1SVaibhav Jain struct bin_attribute *bin_attr, char *buf, 434e36f6fe1SVaibhav Jain loff_t off, size_t count) 435e36f6fe1SVaibhav Jain { 43685016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj)); 437e36f6fe1SVaibhav Jain 4385be587b1SFrederic Barrat return cxl_ops->afu_read_err_buffer(afu, buf, off, count); 439e36f6fe1SVaibhav Jain } 440e36f6fe1SVaibhav Jain 441f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = { 442f204e0b8SIan Munsie __ATTR_RO(mmio_size), 443f204e0b8SIan Munsie __ATTR_RO(irqs_min), 444f204e0b8SIan Munsie __ATTR_RW(irqs_max), 445f204e0b8SIan Munsie __ATTR_RO(modes_supported), 446f204e0b8SIan Munsie __ATTR_RW(mode), 447f204e0b8SIan Munsie __ATTR_RW(prefault_mode), 448f204e0b8SIan Munsie __ATTR_RO(api_version), 449f204e0b8SIan Munsie __ATTR_RO(api_version_compatible), 450f204e0b8SIan Munsie __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 451f204e0b8SIan Munsie }; 452f204e0b8SIan Munsie 453f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter) 454f204e0b8SIan Munsie { 4554752876cSChristophe Lombard struct device_attribute *dev_attr; 456f204e0b8SIan Munsie int i, rc; 457f204e0b8SIan Munsie 458f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4594752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4604752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4614752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) { 4624752876cSChristophe Lombard if ((rc = device_create_file(&adapter->dev, dev_attr))) 463f204e0b8SIan Munsie goto err; 464f204e0b8SIan Munsie } 4654752876cSChristophe Lombard } 466f204e0b8SIan Munsie return 0; 467f204e0b8SIan Munsie err: 4684752876cSChristophe Lombard for (i--; i >= 0; i--) { 4694752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4704752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4714752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4724752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4734752876cSChristophe Lombard } 474f204e0b8SIan Munsie return rc; 475f204e0b8SIan Munsie } 4764752876cSChristophe Lombard 477f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter) 478f204e0b8SIan Munsie { 4794752876cSChristophe Lombard struct device_attribute *dev_attr; 480f204e0b8SIan Munsie int i; 481f204e0b8SIan Munsie 4824752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4834752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4844752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4854752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 4864752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 4874752876cSChristophe Lombard } 488f204e0b8SIan Munsie } 489f204e0b8SIan Munsie 490b087e619SIan Munsie struct afu_config_record { 491b087e619SIan Munsie struct kobject kobj; 492b087e619SIan Munsie struct bin_attribute config_attr; 493b087e619SIan Munsie struct list_head list; 494b087e619SIan Munsie int cr; 495b087e619SIan Munsie u16 device; 496b087e619SIan Munsie u16 vendor; 497b087e619SIan Munsie u32 class; 498b087e619SIan Munsie }; 499b087e619SIan Munsie 500b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 501b087e619SIan Munsie 502b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj, 503b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 504b087e619SIan Munsie { 505b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 506b087e619SIan Munsie 507b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 508b087e619SIan Munsie } 509b087e619SIan Munsie 510b087e619SIan Munsie static ssize_t device_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->device); 516b087e619SIan Munsie } 517b087e619SIan Munsie 518b087e619SIan Munsie static ssize_t class_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%.6x\n", cr->class); 524b087e619SIan Munsie } 525b087e619SIan Munsie 526b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 527b087e619SIan Munsie struct bin_attribute *bin_attr, char *buf, 528b087e619SIan Munsie loff_t off, size_t count) 529b087e619SIan Munsie { 530b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 53185016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent)); 532b087e619SIan Munsie 5335be587b1SFrederic Barrat u64 i, j, val, rc; 534b087e619SIan Munsie 535b087e619SIan Munsie for (i = 0; i < count;) { 5365be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); 5375be587b1SFrederic Barrat if (rc) 5385be587b1SFrederic Barrat val = ~0ULL; 539b087e619SIan Munsie for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 540b087e619SIan Munsie buf[i] = (val >> (j * 8)) & 0xff; 541b087e619SIan Munsie } 542b087e619SIan Munsie 543b087e619SIan Munsie return count; 544b087e619SIan Munsie } 545b087e619SIan Munsie 546b087e619SIan Munsie static struct kobj_attribute vendor_attribute = 547b087e619SIan Munsie __ATTR_RO(vendor); 548b087e619SIan Munsie static struct kobj_attribute device_attribute = 549b087e619SIan Munsie __ATTR_RO(device); 550b087e619SIan Munsie static struct kobj_attribute class_attribute = 551b087e619SIan Munsie __ATTR_RO(class); 552b087e619SIan Munsie 553b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = { 554b087e619SIan Munsie &vendor_attribute.attr, 555b087e619SIan Munsie &device_attribute.attr, 556b087e619SIan Munsie &class_attribute.attr, 557b087e619SIan Munsie NULL, 558b087e619SIan Munsie }; 559b087e619SIan Munsie 560b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj) 561b087e619SIan Munsie { 562b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 563b087e619SIan Munsie 564b087e619SIan Munsie kfree(cr); 565b087e619SIan Munsie } 566b087e619SIan Munsie 567b087e619SIan Munsie static struct kobj_type afu_config_record_type = { 568b087e619SIan Munsie .sysfs_ops = &kobj_sysfs_ops, 569b087e619SIan Munsie .release = release_afu_config_record, 570b087e619SIan Munsie .default_attrs = afu_cr_attrs, 571b087e619SIan Munsie }; 572b087e619SIan Munsie 573b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 574b087e619SIan Munsie { 575b087e619SIan Munsie struct afu_config_record *cr; 576b087e619SIan Munsie int rc; 577b087e619SIan Munsie 578b087e619SIan Munsie cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 579b087e619SIan Munsie if (!cr) 580b087e619SIan Munsie return ERR_PTR(-ENOMEM); 581b087e619SIan Munsie 582b087e619SIan Munsie cr->cr = cr_idx; 5835be587b1SFrederic Barrat 5845be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); 5855be587b1SFrederic Barrat if (rc) 5865be587b1SFrederic Barrat goto err; 5875be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); 5885be587b1SFrederic Barrat if (rc) 5895be587b1SFrederic Barrat goto err; 5905be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); 5915be587b1SFrederic Barrat if (rc) 5925be587b1SFrederic Barrat goto err; 5935be587b1SFrederic Barrat cr->class >>= 8; 594b087e619SIan Munsie 595b087e619SIan Munsie /* 596b087e619SIan Munsie * Export raw AFU PCIe like config record. For now this is read only by 597b087e619SIan Munsie * root - we can expand that later to be readable by non-root and maybe 5984752876cSChristophe Lombard * even writable provided we have a good use-case. Once we support 599b087e619SIan Munsie * exposing AFUs through a virtual PHB they will get that for free from 600b087e619SIan Munsie * Linux' PCI infrastructure, but until then it's not clear that we 601b087e619SIan Munsie * need it for anything since the main use case is just identifying 602b087e619SIan Munsie * AFUs, which can be done via the vendor, device and class attributes. 603b087e619SIan Munsie */ 604b087e619SIan Munsie sysfs_bin_attr_init(&cr->config_attr); 605b087e619SIan Munsie cr->config_attr.attr.name = "config"; 606b087e619SIan Munsie cr->config_attr.attr.mode = S_IRUSR; 607b087e619SIan Munsie cr->config_attr.size = afu->crs_len; 608b087e619SIan Munsie cr->config_attr.read = afu_read_config; 609b087e619SIan Munsie 610b087e619SIan Munsie rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 611b087e619SIan Munsie &afu->dev.kobj, "cr%i", cr->cr); 612b087e619SIan Munsie if (rc) 613b087e619SIan Munsie goto err; 614b087e619SIan Munsie 615b087e619SIan Munsie rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 616b087e619SIan Munsie if (rc) 617b087e619SIan Munsie goto err1; 618b087e619SIan Munsie 619b087e619SIan Munsie rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 620b087e619SIan Munsie if (rc) 621b087e619SIan Munsie goto err2; 622b087e619SIan Munsie 623b087e619SIan Munsie return cr; 624b087e619SIan Munsie err2: 625b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 626b087e619SIan Munsie err1: 627b087e619SIan Munsie kobject_put(&cr->kobj); 628b087e619SIan Munsie return ERR_PTR(rc); 629b087e619SIan Munsie err: 630b087e619SIan Munsie kfree(cr); 631b087e619SIan Munsie return ERR_PTR(rc); 632b087e619SIan Munsie } 633b087e619SIan Munsie 634b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu) 635b087e619SIan Munsie { 6364752876cSChristophe Lombard struct device_attribute *dev_attr; 637b087e619SIan Munsie struct afu_config_record *cr, *tmp; 638b087e619SIan Munsie int i; 639b087e619SIan Munsie 640e36f6fe1SVaibhav Jain /* remove the err buffer bin attribute */ 641e36f6fe1SVaibhav Jain if (afu->eb_len) 642e36f6fe1SVaibhav Jain device_remove_bin_file(&afu->dev, &afu->attr_eb); 643e36f6fe1SVaibhav Jain 6444752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6454752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6464752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6474752876cSChristophe Lombard CXL_AFU_ATTRS)) 648b087e619SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 6494752876cSChristophe Lombard } 650b087e619SIan Munsie 651b087e619SIan Munsie list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 652b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 653b087e619SIan Munsie kobject_put(&cr->kobj); 654b087e619SIan Munsie } 655b087e619SIan Munsie } 656b087e619SIan Munsie 657f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu) 658f204e0b8SIan Munsie { 6594752876cSChristophe Lombard struct device_attribute *dev_attr; 660b087e619SIan Munsie struct afu_config_record *cr; 661f204e0b8SIan Munsie int i, rc; 662f204e0b8SIan Munsie 663b087e619SIan Munsie INIT_LIST_HEAD(&afu->crs); 664b087e619SIan Munsie 665f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6664752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6674752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6684752876cSChristophe Lombard CXL_AFU_ATTRS)) { 669f204e0b8SIan Munsie if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 670f204e0b8SIan Munsie goto err; 671f204e0b8SIan Munsie } 6724752876cSChristophe Lombard } 673f204e0b8SIan Munsie 674e36f6fe1SVaibhav Jain /* conditionally create the add the binary file for error info buffer */ 675e36f6fe1SVaibhav Jain if (afu->eb_len) { 676d6eb71a6SVaibhav Jain sysfs_attr_init(&afu->attr_eb.attr); 677d6eb71a6SVaibhav Jain 678e36f6fe1SVaibhav Jain afu->attr_eb.attr.name = "afu_err_buff"; 679e36f6fe1SVaibhav Jain afu->attr_eb.attr.mode = S_IRUGO; 680e36f6fe1SVaibhav Jain afu->attr_eb.size = afu->eb_len; 681e36f6fe1SVaibhav Jain afu->attr_eb.read = afu_eb_read; 682e36f6fe1SVaibhav Jain 683e36f6fe1SVaibhav Jain rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 684e36f6fe1SVaibhav Jain if (rc) { 685e36f6fe1SVaibhav Jain dev_err(&afu->dev, 686e36f6fe1SVaibhav Jain "Unable to create eb attr for the afu. Err(%d)\n", 687e36f6fe1SVaibhav Jain rc); 688e36f6fe1SVaibhav Jain goto err; 689e36f6fe1SVaibhav Jain } 690e36f6fe1SVaibhav Jain } 691e36f6fe1SVaibhav Jain 692b087e619SIan Munsie for (i = 0; i < afu->crs_num; i++) { 693b087e619SIan Munsie cr = cxl_sysfs_afu_new_cr(afu, i); 694b087e619SIan Munsie if (IS_ERR(cr)) { 695b087e619SIan Munsie rc = PTR_ERR(cr); 696b087e619SIan Munsie goto err1; 697b087e619SIan Munsie } 698b087e619SIan Munsie list_add(&cr->list, &afu->crs); 699b087e619SIan Munsie } 700b087e619SIan Munsie 701f204e0b8SIan Munsie return 0; 702f204e0b8SIan Munsie 703b087e619SIan Munsie err1: 704b087e619SIan Munsie cxl_sysfs_afu_remove(afu); 705b087e619SIan Munsie return rc; 706f204e0b8SIan Munsie err: 707e36f6fe1SVaibhav Jain /* reset the eb_len as we havent created the bin attr */ 708e36f6fe1SVaibhav Jain afu->eb_len = 0; 709e36f6fe1SVaibhav Jain 7104752876cSChristophe Lombard for (i--; i >= 0; i--) { 7114752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 7124752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7134752876cSChristophe Lombard CXL_AFU_ATTRS)) 714f204e0b8SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 7154752876cSChristophe Lombard } 716f204e0b8SIan Munsie return rc; 717f204e0b8SIan Munsie } 718f204e0b8SIan Munsie 719f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 720f204e0b8SIan Munsie { 7214752876cSChristophe Lombard struct device_attribute *dev_attr; 722f204e0b8SIan Munsie int i, rc; 723f204e0b8SIan Munsie 724f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_master_attrs); 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 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 729f204e0b8SIan Munsie goto err; 730f204e0b8SIan Munsie } 7314752876cSChristophe Lombard } 732f204e0b8SIan Munsie 733f204e0b8SIan Munsie return 0; 734f204e0b8SIan Munsie 735f204e0b8SIan Munsie err: 7364752876cSChristophe Lombard for (i--; i >= 0; i--) { 7374752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7384752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7394752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 740f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 7414752876cSChristophe Lombard } 742f204e0b8SIan Munsie return rc; 743f204e0b8SIan Munsie } 744f204e0b8SIan Munsie 745f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 746f204e0b8SIan Munsie { 7474752876cSChristophe Lombard struct device_attribute *dev_attr; 748f204e0b8SIan Munsie int i; 749f204e0b8SIan Munsie 7504752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7514752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7524752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7534752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 754f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 755f204e0b8SIan Munsie } 7564752876cSChristophe Lombard } 757