1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2f204e0b8SIan Munsie /* 3f204e0b8SIan Munsie * Copyright 2014 IBM Corp. 4f204e0b8SIan Munsie */ 5f204e0b8SIan Munsie 6f204e0b8SIan Munsie #include <linux/kernel.h> 7f204e0b8SIan Munsie #include <linux/device.h> 8f204e0b8SIan Munsie #include <linux/sysfs.h> 9b087e619SIan Munsie #include <linux/pci_regs.h> 10f204e0b8SIan Munsie 11f204e0b8SIan Munsie #include "cxl.h" 12f204e0b8SIan Munsie 13f204e0b8SIan Munsie #define to_afu_chardev_m(d) dev_get_drvdata(d) 14f204e0b8SIan Munsie 15f204e0b8SIan Munsie /********* Adapter attributes **********************************************/ 16f204e0b8SIan Munsie 17f204e0b8SIan Munsie static ssize_t caia_version_show(struct device *device, 18f204e0b8SIan Munsie struct device_attribute *attr, 19f204e0b8SIan Munsie char *buf) 20f204e0b8SIan Munsie { 21f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 22f204e0b8SIan Munsie 23f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major, 24f204e0b8SIan Munsie adapter->caia_minor); 25f204e0b8SIan Munsie } 26f204e0b8SIan Munsie 27f204e0b8SIan Munsie static ssize_t psl_revision_show(struct device *device, 28f204e0b8SIan Munsie struct device_attribute *attr, 29f204e0b8SIan Munsie char *buf) 30f204e0b8SIan Munsie { 31f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 32f204e0b8SIan Munsie 33f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev); 34f204e0b8SIan Munsie } 35f204e0b8SIan Munsie 36f204e0b8SIan Munsie static ssize_t base_image_show(struct device *device, 37f204e0b8SIan Munsie struct device_attribute *attr, 38f204e0b8SIan Munsie char *buf) 39f204e0b8SIan Munsie { 40f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 41f204e0b8SIan Munsie 42f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image); 43f204e0b8SIan Munsie } 44f204e0b8SIan Munsie 45f204e0b8SIan Munsie static ssize_t image_loaded_show(struct device *device, 46f204e0b8SIan Munsie struct device_attribute *attr, 47f204e0b8SIan Munsie char *buf) 48f204e0b8SIan Munsie { 49f204e0b8SIan Munsie struct cxl *adapter = to_cxl_adapter(device); 50f204e0b8SIan Munsie 51f204e0b8SIan Munsie if (adapter->user_image_loaded) 52f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "user\n"); 53f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "factory\n"); 54f204e0b8SIan Munsie } 55f204e0b8SIan Munsie 56e009a7e8SFrederic Barrat static ssize_t psl_timebase_synced_show(struct device *device, 57e009a7e8SFrederic Barrat struct device_attribute *attr, 58e009a7e8SFrederic Barrat char *buf) 59e009a7e8SFrederic Barrat { 60e009a7e8SFrederic Barrat struct cxl *adapter = to_cxl_adapter(device); 61c2be663dSChristophe Lombard u64 psl_tb, delta; 62e009a7e8SFrederic Barrat 63c2be663dSChristophe Lombard /* Recompute the status only in native mode */ 64c2be663dSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 65c2be663dSChristophe Lombard psl_tb = adapter->native->sl_ops->timebase_read(adapter); 66c2be663dSChristophe Lombard delta = abs(mftb() - psl_tb); 67c2be663dSChristophe Lombard 68c2be663dSChristophe Lombard /* CORE TB and PSL TB difference <= 16usecs ? */ 69c2be663dSChristophe Lombard adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false; 70c2be663dSChristophe Lombard pr_devel("PSL timebase %s - delta: 0x%016llx\n", 71c2be663dSChristophe Lombard (tb_to_ns(delta) < 16000) ? "synchronized" : 72c2be663dSChristophe Lombard "not synchronized", tb_to_ns(delta)); 73c2be663dSChristophe Lombard } 74e009a7e8SFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced); 75e009a7e8SFrederic Barrat } 76e009a7e8SFrederic Barrat 77497a0790SPhilippe Bergheaud static ssize_t tunneled_ops_supported_show(struct device *device, 78497a0790SPhilippe Bergheaud struct device_attribute *attr, 79497a0790SPhilippe Bergheaud char *buf) 80497a0790SPhilippe Bergheaud { 81497a0790SPhilippe Bergheaud struct cxl *adapter = to_cxl_adapter(device); 82497a0790SPhilippe Bergheaud 83497a0790SPhilippe Bergheaud return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->tunneled_ops_supported); 84497a0790SPhilippe Bergheaud } 85497a0790SPhilippe Bergheaud 8662fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device, 8762fa19d4SRyan Grimm struct device_attribute *attr, 8862fa19d4SRyan Grimm const char *buf, size_t count) 8962fa19d4SRyan Grimm { 9062fa19d4SRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 9162fa19d4SRyan Grimm int rc; 9262fa19d4SRyan Grimm int val; 9362fa19d4SRyan Grimm 9462fa19d4SRyan Grimm rc = sscanf(buf, "%i", &val); 9570b565bbSVaibhav Jain if ((rc != 1) || (val != 1 && val != -1)) 9662fa19d4SRyan Grimm return -EINVAL; 9762fa19d4SRyan Grimm 9870b565bbSVaibhav Jain /* 9970b565bbSVaibhav Jain * See if we can lock the context mapping that's only allowed 10070b565bbSVaibhav Jain * when there are no contexts attached to the adapter. Once 10170b565bbSVaibhav Jain * taken this will also prevent any context from getting activated. 10270b565bbSVaibhav Jain */ 10370b565bbSVaibhav Jain if (val == 1) { 10470b565bbSVaibhav Jain rc = cxl_adapter_context_lock(adapter); 10570b565bbSVaibhav Jain if (rc) 10670b565bbSVaibhav Jain goto out; 10770b565bbSVaibhav Jain 10870b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 10970b565bbSVaibhav Jain /* In case reset failed release context lock */ 11070b565bbSVaibhav Jain if (rc) 11170b565bbSVaibhav Jain cxl_adapter_context_unlock(adapter); 11270b565bbSVaibhav Jain 11370b565bbSVaibhav Jain } else if (val == -1) { 11470b565bbSVaibhav Jain /* Perform a forced adapter reset */ 11570b565bbSVaibhav Jain rc = cxl_ops->adapter_reset(adapter); 11670b565bbSVaibhav Jain } 11770b565bbSVaibhav Jain 11870b565bbSVaibhav Jain out: 11970b565bbSVaibhav Jain return rc ? rc : count; 12062fa19d4SRyan Grimm } 12162fa19d4SRyan Grimm 12295bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device, 12395bc11bcSRyan Grimm struct device_attribute *attr, 12495bc11bcSRyan Grimm char *buf) 12595bc11bcSRyan Grimm { 12695bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 12795bc11bcSRyan Grimm 12895bc11bcSRyan Grimm if (!adapter->perst_loads_image) 12995bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "none\n"); 13095bc11bcSRyan Grimm 13195bc11bcSRyan Grimm if (adapter->perst_select_user) 13295bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "user\n"); 13395bc11bcSRyan Grimm return scnprintf(buf, PAGE_SIZE, "factory\n"); 13495bc11bcSRyan Grimm } 13595bc11bcSRyan Grimm 13695bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device, 13795bc11bcSRyan Grimm struct device_attribute *attr, 13895bc11bcSRyan Grimm const char *buf, size_t count) 13995bc11bcSRyan Grimm { 14095bc11bcSRyan Grimm struct cxl *adapter = to_cxl_adapter(device); 14195bc11bcSRyan Grimm int rc; 14295bc11bcSRyan Grimm 14395bc11bcSRyan Grimm if (!strncmp(buf, "none", 4)) 14495bc11bcSRyan Grimm adapter->perst_loads_image = false; 14595bc11bcSRyan Grimm else if (!strncmp(buf, "user", 4)) { 14695bc11bcSRyan Grimm adapter->perst_select_user = true; 14795bc11bcSRyan Grimm adapter->perst_loads_image = true; 14895bc11bcSRyan Grimm } else if (!strncmp(buf, "factory", 7)) { 14995bc11bcSRyan Grimm adapter->perst_select_user = false; 15095bc11bcSRyan Grimm adapter->perst_loads_image = true; 15195bc11bcSRyan Grimm } else 15295bc11bcSRyan Grimm return -EINVAL; 15395bc11bcSRyan Grimm 15495bc11bcSRyan Grimm if ((rc = cxl_update_image_control(adapter))) 15595bc11bcSRyan Grimm return rc; 15695bc11bcSRyan Grimm 15795bc11bcSRyan Grimm return count; 15895bc11bcSRyan Grimm } 15995bc11bcSRyan Grimm 16013e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device, 16113e68d8bSDaniel Axtens struct device_attribute *attr, 16213e68d8bSDaniel Axtens char *buf) 16313e68d8bSDaniel Axtens { 16413e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 16513e68d8bSDaniel Axtens 16613e68d8bSDaniel Axtens return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image); 16713e68d8bSDaniel Axtens } 16813e68d8bSDaniel Axtens 16913e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device, 17013e68d8bSDaniel Axtens struct device_attribute *attr, 17113e68d8bSDaniel Axtens const char *buf, size_t count) 17213e68d8bSDaniel Axtens { 17313e68d8bSDaniel Axtens struct cxl *adapter = to_cxl_adapter(device); 17413e68d8bSDaniel Axtens int rc; 17513e68d8bSDaniel Axtens int val; 17613e68d8bSDaniel Axtens 17713e68d8bSDaniel Axtens rc = sscanf(buf, "%i", &val); 17813e68d8bSDaniel Axtens if ((rc != 1) || !(val == 1 || val == 0)) 17913e68d8bSDaniel Axtens return -EINVAL; 18013e68d8bSDaniel Axtens 18113e68d8bSDaniel Axtens adapter->perst_same_image = (val == 1 ? true : false); 18213e68d8bSDaniel Axtens return count; 18313e68d8bSDaniel Axtens } 18413e68d8bSDaniel Axtens 185f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = { 186f204e0b8SIan Munsie __ATTR_RO(caia_version), 187f204e0b8SIan Munsie __ATTR_RO(psl_revision), 188f204e0b8SIan Munsie __ATTR_RO(base_image), 189f204e0b8SIan Munsie __ATTR_RO(image_loaded), 190e009a7e8SFrederic Barrat __ATTR_RO(psl_timebase_synced), 191497a0790SPhilippe Bergheaud __ATTR_RO(tunneled_ops_supported), 19295bc11bcSRyan Grimm __ATTR_RW(load_image_on_perst), 19313e68d8bSDaniel Axtens __ATTR_RW(perst_reloads_same_image), 19462fa19d4SRyan Grimm __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), 195f204e0b8SIan Munsie }; 196f204e0b8SIan Munsie 197f204e0b8SIan Munsie 198f204e0b8SIan Munsie /********* AFU master specific attributes **********************************/ 199f204e0b8SIan Munsie 200f204e0b8SIan Munsie static ssize_t mmio_size_show_master(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->adapter->ps_size); 207f204e0b8SIan Munsie } 208f204e0b8SIan Munsie 209f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device, 210f204e0b8SIan Munsie struct device_attribute *attr, 211f204e0b8SIan Munsie char *buf) 212f204e0b8SIan Munsie { 213f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 214f204e0b8SIan Munsie 215cbffa3a5SChristophe Lombard return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset); 216f204e0b8SIan Munsie } 217f204e0b8SIan Munsie 218f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device, 219f204e0b8SIan Munsie struct device_attribute *attr, 220f204e0b8SIan Munsie char *buf) 221f204e0b8SIan Munsie { 222f204e0b8SIan Munsie struct cxl_afu *afu = to_afu_chardev_m(device); 223f204e0b8SIan Munsie 224f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 225f204e0b8SIan Munsie } 226f204e0b8SIan Munsie 227f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = { 228f204e0b8SIan Munsie __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 229f204e0b8SIan Munsie __ATTR_RO(pp_mmio_off), 230f204e0b8SIan Munsie __ATTR_RO(pp_mmio_len), 231f204e0b8SIan Munsie }; 232f204e0b8SIan Munsie 233f204e0b8SIan Munsie 234f204e0b8SIan Munsie /********* AFU attributes **************************************************/ 235f204e0b8SIan Munsie 236f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device, 237f204e0b8SIan Munsie struct device_attribute *attr, 238f204e0b8SIan Munsie char *buf) 239f204e0b8SIan Munsie { 240f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 241f204e0b8SIan Munsie 242f204e0b8SIan Munsie if (afu->pp_size) 243f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 244f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 245f204e0b8SIan Munsie } 246f204e0b8SIan Munsie 247f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device, 248f204e0b8SIan Munsie struct device_attribute *attr, 249f204e0b8SIan Munsie const char *buf, size_t count) 250f204e0b8SIan Munsie { 251f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 252f204e0b8SIan Munsie int rc; 253f204e0b8SIan Munsie 254f204e0b8SIan Munsie /* Not safe to reset if it is currently in use */ 255ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 256f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) { 257f204e0b8SIan Munsie rc = -EBUSY; 258f204e0b8SIan Munsie goto err; 259f204e0b8SIan Munsie } 260f204e0b8SIan Munsie 2615be587b1SFrederic Barrat if ((rc = cxl_ops->afu_reset(afu))) 262f204e0b8SIan Munsie goto err; 263f204e0b8SIan Munsie 264f204e0b8SIan Munsie rc = count; 265f204e0b8SIan Munsie err: 266ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 267f204e0b8SIan Munsie return rc; 268f204e0b8SIan Munsie } 269f204e0b8SIan Munsie 270f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device, 271f204e0b8SIan Munsie struct device_attribute *attr, 272f204e0b8SIan Munsie char *buf) 273f204e0b8SIan Munsie { 274f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 275f204e0b8SIan Munsie 276f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 277f204e0b8SIan Munsie } 278f204e0b8SIan Munsie 279f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device, 280f204e0b8SIan Munsie struct device_attribute *attr, 281f204e0b8SIan Munsie char *buf) 282f204e0b8SIan Munsie { 283f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 284f204e0b8SIan Munsie 285f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 286f204e0b8SIan Munsie } 287f204e0b8SIan Munsie 288f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device, 289f204e0b8SIan Munsie struct device_attribute *attr, 290f204e0b8SIan Munsie const char *buf, size_t count) 291f204e0b8SIan Munsie { 292f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 293f204e0b8SIan Munsie ssize_t ret; 294f204e0b8SIan Munsie int irqs_max; 295f204e0b8SIan Munsie 296f204e0b8SIan Munsie ret = sscanf(buf, "%i", &irqs_max); 297f204e0b8SIan Munsie if (ret != 1) 298f204e0b8SIan Munsie return -EINVAL; 299f204e0b8SIan Munsie 300f204e0b8SIan Munsie if (irqs_max < afu->pp_irqs) 301f204e0b8SIan Munsie return -EINVAL; 302f204e0b8SIan Munsie 3034752876cSChristophe Lombard if (cpu_has_feature(CPU_FTR_HVMODE)) { 304f204e0b8SIan Munsie if (irqs_max > afu->adapter->user_irqs) 305f204e0b8SIan Munsie return -EINVAL; 3064752876cSChristophe Lombard } else { 3074752876cSChristophe Lombard /* pHyp sets a per-AFU limit */ 3084752876cSChristophe Lombard if (irqs_max > afu->guest->max_ints) 3094752876cSChristophe Lombard return -EINVAL; 3104752876cSChristophe Lombard } 311f204e0b8SIan Munsie 312f204e0b8SIan Munsie afu->irqs_max = irqs_max; 313f204e0b8SIan Munsie return count; 314f204e0b8SIan Munsie } 315f204e0b8SIan Munsie 316f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device, 317f204e0b8SIan Munsie struct device_attribute *attr, char *buf) 318f204e0b8SIan Munsie { 319f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 320f204e0b8SIan Munsie char *p = buf, *end = buf + PAGE_SIZE; 321f204e0b8SIan Munsie 322f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DEDICATED) 323f204e0b8SIan Munsie p += scnprintf(p, end - p, "dedicated_process\n"); 324f204e0b8SIan Munsie if (afu->modes_supported & CXL_MODE_DIRECTED) 325f204e0b8SIan Munsie p += scnprintf(p, end - p, "afu_directed\n"); 326f204e0b8SIan Munsie return (p - buf); 327f204e0b8SIan Munsie } 328f204e0b8SIan Munsie 329f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device, 330f204e0b8SIan Munsie struct device_attribute *attr, 331f204e0b8SIan Munsie char *buf) 332f204e0b8SIan Munsie { 333f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 334f204e0b8SIan Munsie 335f204e0b8SIan Munsie switch (afu->prefault_mode) { 336f204e0b8SIan Munsie case CXL_PREFAULT_WED: 337f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 338f204e0b8SIan Munsie case CXL_PREFAULT_ALL: 339f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "all\n"); 340f204e0b8SIan Munsie default: 341f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 342f204e0b8SIan Munsie } 343f204e0b8SIan Munsie } 344f204e0b8SIan Munsie 345f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device, 346f204e0b8SIan Munsie struct device_attribute *attr, 347f204e0b8SIan Munsie const char *buf, size_t count) 348f204e0b8SIan Munsie { 349f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 350f204e0b8SIan Munsie enum prefault_modes mode = -1; 351f204e0b8SIan Munsie 352b6c84ba2SVaibhav Jain if (!strncmp(buf, "none", 4)) 353b6c84ba2SVaibhav Jain mode = CXL_PREFAULT_NONE; 354b6c84ba2SVaibhav Jain else { 355b6c84ba2SVaibhav Jain if (!radix_enabled()) { 356b6c84ba2SVaibhav Jain 357b6c84ba2SVaibhav Jain /* only allowed when not in radix mode */ 358f204e0b8SIan Munsie if (!strncmp(buf, "work_element_descriptor", 23)) 359f204e0b8SIan Munsie mode = CXL_PREFAULT_WED; 360f204e0b8SIan Munsie if (!strncmp(buf, "all", 3)) 361f204e0b8SIan Munsie mode = CXL_PREFAULT_ALL; 362b6c84ba2SVaibhav Jain } else { 363b6c84ba2SVaibhav Jain dev_err(device, "Cannot prefault with radix enabled\n"); 364b6c84ba2SVaibhav Jain } 365b6c84ba2SVaibhav Jain } 366f204e0b8SIan Munsie 367f204e0b8SIan Munsie if (mode == -1) 368f204e0b8SIan Munsie return -EINVAL; 369f204e0b8SIan Munsie 370f204e0b8SIan Munsie afu->prefault_mode = mode; 371f204e0b8SIan Munsie return count; 372f204e0b8SIan Munsie } 373f204e0b8SIan Munsie 374f204e0b8SIan Munsie static ssize_t mode_show(struct device *device, 375f204e0b8SIan Munsie struct device_attribute *attr, 376f204e0b8SIan Munsie char *buf) 377f204e0b8SIan Munsie { 378f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 379f204e0b8SIan Munsie 380f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DEDICATED) 381f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 382f204e0b8SIan Munsie if (afu->current_mode == CXL_MODE_DIRECTED) 383f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 384f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "none\n"); 385f204e0b8SIan Munsie } 386f204e0b8SIan Munsie 387f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr, 388f204e0b8SIan Munsie const char *buf, size_t count) 389f204e0b8SIan Munsie { 390f204e0b8SIan Munsie struct cxl_afu *afu = to_cxl_afu(device); 391f204e0b8SIan Munsie int old_mode, mode = -1; 392f204e0b8SIan Munsie int rc = -EBUSY; 393f204e0b8SIan Munsie 394f204e0b8SIan Munsie /* can't change this if we have a user */ 395ee41d11dSIan Munsie mutex_lock(&afu->contexts_lock); 396f204e0b8SIan Munsie if (!idr_is_empty(&afu->contexts_idr)) 397f204e0b8SIan Munsie goto err; 398f204e0b8SIan Munsie 399f204e0b8SIan Munsie if (!strncmp(buf, "dedicated_process", 17)) 400f204e0b8SIan Munsie mode = CXL_MODE_DEDICATED; 401f204e0b8SIan Munsie if (!strncmp(buf, "afu_directed", 12)) 402f204e0b8SIan Munsie mode = CXL_MODE_DIRECTED; 403f204e0b8SIan Munsie if (!strncmp(buf, "none", 4)) 404f204e0b8SIan Munsie mode = 0; 405f204e0b8SIan Munsie 406f204e0b8SIan Munsie if (mode == -1) { 407f204e0b8SIan Munsie rc = -EINVAL; 408f204e0b8SIan Munsie goto err; 409f204e0b8SIan Munsie } 410f204e0b8SIan Munsie 411f204e0b8SIan Munsie /* 4125be587b1SFrederic Barrat * afu_deactivate_mode needs to be done outside the lock, prevent 413f204e0b8SIan Munsie * other contexts coming in before we are ready: 414f204e0b8SIan Munsie */ 415f204e0b8SIan Munsie old_mode = afu->current_mode; 416f204e0b8SIan Munsie afu->current_mode = 0; 417f204e0b8SIan Munsie afu->num_procs = 0; 418f204e0b8SIan Munsie 419ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 420f204e0b8SIan Munsie 4215be587b1SFrederic Barrat if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) 422f204e0b8SIan Munsie return rc; 4235be587b1SFrederic Barrat if ((rc = cxl_ops->afu_activate_mode(afu, mode))) 424f204e0b8SIan Munsie return rc; 425f204e0b8SIan Munsie 426f204e0b8SIan Munsie return count; 427f204e0b8SIan Munsie err: 428ee41d11dSIan Munsie mutex_unlock(&afu->contexts_lock); 429f204e0b8SIan Munsie return rc; 430f204e0b8SIan Munsie } 431f204e0b8SIan Munsie 432f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device, 433f204e0b8SIan Munsie struct device_attribute *attr, 434f204e0b8SIan Munsie char *buf) 435f204e0b8SIan Munsie { 436f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 437f204e0b8SIan Munsie } 438f204e0b8SIan Munsie 439f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device, 440f204e0b8SIan Munsie struct device_attribute *attr, 441f204e0b8SIan Munsie char *buf) 442f204e0b8SIan Munsie { 443f204e0b8SIan Munsie return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 444f204e0b8SIan Munsie } 445f204e0b8SIan Munsie 446e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 447e36f6fe1SVaibhav Jain struct bin_attribute *bin_attr, char *buf, 448e36f6fe1SVaibhav Jain loff_t off, size_t count) 449e36f6fe1SVaibhav Jain { 45085016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj)); 451e36f6fe1SVaibhav Jain 4525be587b1SFrederic Barrat return cxl_ops->afu_read_err_buffer(afu, buf, off, count); 453e36f6fe1SVaibhav Jain } 454e36f6fe1SVaibhav Jain 455f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = { 456f204e0b8SIan Munsie __ATTR_RO(mmio_size), 457f204e0b8SIan Munsie __ATTR_RO(irqs_min), 458f204e0b8SIan Munsie __ATTR_RW(irqs_max), 459f204e0b8SIan Munsie __ATTR_RO(modes_supported), 460f204e0b8SIan Munsie __ATTR_RW(mode), 461f204e0b8SIan Munsie __ATTR_RW(prefault_mode), 462f204e0b8SIan Munsie __ATTR_RO(api_version), 463f204e0b8SIan Munsie __ATTR_RO(api_version_compatible), 464f204e0b8SIan Munsie __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 465f204e0b8SIan Munsie }; 466f204e0b8SIan Munsie 467f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter) 468f204e0b8SIan Munsie { 4694752876cSChristophe Lombard struct device_attribute *dev_attr; 470f204e0b8SIan Munsie int i, rc; 471f204e0b8SIan Munsie 472f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4734752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4744752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4754752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) { 4764752876cSChristophe Lombard if ((rc = device_create_file(&adapter->dev, dev_attr))) 477f204e0b8SIan Munsie goto err; 478f204e0b8SIan Munsie } 4794752876cSChristophe Lombard } 480f204e0b8SIan Munsie return 0; 481f204e0b8SIan Munsie err: 4824752876cSChristophe Lombard for (i--; i >= 0; 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 return rc; 489f204e0b8SIan Munsie } 4904752876cSChristophe Lombard 491f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter) 492f204e0b8SIan Munsie { 4934752876cSChristophe Lombard struct device_attribute *dev_attr; 494f204e0b8SIan Munsie int i; 495f204e0b8SIan Munsie 4964752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 4974752876cSChristophe Lombard dev_attr = &adapter_attrs[i]; 4984752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 4994752876cSChristophe Lombard CXL_ADAPTER_ATTRS)) 5004752876cSChristophe Lombard device_remove_file(&adapter->dev, dev_attr); 5014752876cSChristophe Lombard } 502f204e0b8SIan Munsie } 503f204e0b8SIan Munsie 504b087e619SIan Munsie struct afu_config_record { 505b087e619SIan Munsie struct kobject kobj; 506b087e619SIan Munsie struct bin_attribute config_attr; 507b087e619SIan Munsie struct list_head list; 508b087e619SIan Munsie int cr; 509b087e619SIan Munsie u16 device; 510b087e619SIan Munsie u16 vendor; 511b087e619SIan Munsie u32 class; 512b087e619SIan Munsie }; 513b087e619SIan Munsie 514b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 515b087e619SIan Munsie 516b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj, 517b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 518b087e619SIan Munsie { 519b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 520b087e619SIan Munsie 521b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 522b087e619SIan Munsie } 523b087e619SIan Munsie 524b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj, 525b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 526b087e619SIan Munsie { 527b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 528b087e619SIan Munsie 529b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); 530b087e619SIan Munsie } 531b087e619SIan Munsie 532b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj, 533b087e619SIan Munsie struct kobj_attribute *attr, char *buf) 534b087e619SIan Munsie { 535b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 536b087e619SIan Munsie 537b087e619SIan Munsie return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); 538b087e619SIan Munsie } 539b087e619SIan Munsie 540b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 541b087e619SIan Munsie struct bin_attribute *bin_attr, char *buf, 542b087e619SIan Munsie loff_t off, size_t count) 543b087e619SIan Munsie { 544b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 54585016ff3SGeliang Tang struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent)); 546b087e619SIan Munsie 5475be587b1SFrederic Barrat u64 i, j, val, rc; 548b087e619SIan Munsie 549b087e619SIan Munsie for (i = 0; i < count;) { 5505be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); 5515be587b1SFrederic Barrat if (rc) 5525be587b1SFrederic Barrat val = ~0ULL; 553b087e619SIan Munsie for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 554b087e619SIan Munsie buf[i] = (val >> (j * 8)) & 0xff; 555b087e619SIan Munsie } 556b087e619SIan Munsie 557b087e619SIan Munsie return count; 558b087e619SIan Munsie } 559b087e619SIan Munsie 560b087e619SIan Munsie static struct kobj_attribute vendor_attribute = 561b087e619SIan Munsie __ATTR_RO(vendor); 562b087e619SIan Munsie static struct kobj_attribute device_attribute = 563b087e619SIan Munsie __ATTR_RO(device); 564b087e619SIan Munsie static struct kobj_attribute class_attribute = 565b087e619SIan Munsie __ATTR_RO(class); 566b087e619SIan Munsie 567b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = { 568b087e619SIan Munsie &vendor_attribute.attr, 569b087e619SIan Munsie &device_attribute.attr, 570b087e619SIan Munsie &class_attribute.attr, 571b087e619SIan Munsie NULL, 572b087e619SIan Munsie }; 573b087e619SIan Munsie 574b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj) 575b087e619SIan Munsie { 576b087e619SIan Munsie struct afu_config_record *cr = to_cr(kobj); 577b087e619SIan Munsie 578b087e619SIan Munsie kfree(cr); 579b087e619SIan Munsie } 580b087e619SIan Munsie 581b087e619SIan Munsie static struct kobj_type afu_config_record_type = { 582b087e619SIan Munsie .sysfs_ops = &kobj_sysfs_ops, 583b087e619SIan Munsie .release = release_afu_config_record, 584b087e619SIan Munsie .default_attrs = afu_cr_attrs, 585b087e619SIan Munsie }; 586b087e619SIan Munsie 587b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 588b087e619SIan Munsie { 589b087e619SIan Munsie struct afu_config_record *cr; 590b087e619SIan Munsie int rc; 591b087e619SIan Munsie 592b087e619SIan Munsie cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 593b087e619SIan Munsie if (!cr) 594b087e619SIan Munsie return ERR_PTR(-ENOMEM); 595b087e619SIan Munsie 596b087e619SIan Munsie cr->cr = cr_idx; 5975be587b1SFrederic Barrat 5985be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); 5995be587b1SFrederic Barrat if (rc) 6005be587b1SFrederic Barrat goto err; 6015be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); 6025be587b1SFrederic Barrat if (rc) 6035be587b1SFrederic Barrat goto err; 6045be587b1SFrederic Barrat rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); 6055be587b1SFrederic Barrat if (rc) 6065be587b1SFrederic Barrat goto err; 6075be587b1SFrederic Barrat cr->class >>= 8; 608b087e619SIan Munsie 609b087e619SIan Munsie /* 610b087e619SIan Munsie * Export raw AFU PCIe like config record. For now this is read only by 611b087e619SIan Munsie * root - we can expand that later to be readable by non-root and maybe 6124752876cSChristophe Lombard * even writable provided we have a good use-case. Once we support 613b087e619SIan Munsie * exposing AFUs through a virtual PHB they will get that for free from 614b087e619SIan Munsie * Linux' PCI infrastructure, but until then it's not clear that we 615b087e619SIan Munsie * need it for anything since the main use case is just identifying 616b087e619SIan Munsie * AFUs, which can be done via the vendor, device and class attributes. 617b087e619SIan Munsie */ 618b087e619SIan Munsie sysfs_bin_attr_init(&cr->config_attr); 619b087e619SIan Munsie cr->config_attr.attr.name = "config"; 620b087e619SIan Munsie cr->config_attr.attr.mode = S_IRUSR; 621b087e619SIan Munsie cr->config_attr.size = afu->crs_len; 622b087e619SIan Munsie cr->config_attr.read = afu_read_config; 623b087e619SIan Munsie 624b087e619SIan Munsie rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 625b087e619SIan Munsie &afu->dev.kobj, "cr%i", cr->cr); 626b087e619SIan Munsie if (rc) 627b087e619SIan Munsie goto err; 628b087e619SIan Munsie 629b087e619SIan Munsie rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 630b087e619SIan Munsie if (rc) 631b087e619SIan Munsie goto err1; 632b087e619SIan Munsie 633b087e619SIan Munsie rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 634b087e619SIan Munsie if (rc) 635b087e619SIan Munsie goto err2; 636b087e619SIan Munsie 637b087e619SIan Munsie return cr; 638b087e619SIan Munsie err2: 639b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 640b087e619SIan Munsie err1: 641b087e619SIan Munsie kobject_put(&cr->kobj); 642b087e619SIan Munsie return ERR_PTR(rc); 643b087e619SIan Munsie err: 644b087e619SIan Munsie kfree(cr); 645b087e619SIan Munsie return ERR_PTR(rc); 646b087e619SIan Munsie } 647b087e619SIan Munsie 648b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu) 649b087e619SIan Munsie { 6504752876cSChristophe Lombard struct device_attribute *dev_attr; 651b087e619SIan Munsie struct afu_config_record *cr, *tmp; 652b087e619SIan Munsie int i; 653b087e619SIan Munsie 654e36f6fe1SVaibhav Jain /* remove the err buffer bin attribute */ 655e36f6fe1SVaibhav Jain if (afu->eb_len) 656e36f6fe1SVaibhav Jain device_remove_bin_file(&afu->dev, &afu->attr_eb); 657e36f6fe1SVaibhav Jain 6584752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6594752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6604752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6614752876cSChristophe Lombard CXL_AFU_ATTRS)) 662b087e619SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 6634752876cSChristophe Lombard } 664b087e619SIan Munsie 665b087e619SIan Munsie list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 666b087e619SIan Munsie sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 667b087e619SIan Munsie kobject_put(&cr->kobj); 668b087e619SIan Munsie } 669b087e619SIan Munsie } 670b087e619SIan Munsie 671f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu) 672f204e0b8SIan Munsie { 6734752876cSChristophe Lombard struct device_attribute *dev_attr; 674b087e619SIan Munsie struct afu_config_record *cr; 675f204e0b8SIan Munsie int i, rc; 676f204e0b8SIan Munsie 677b087e619SIan Munsie INIT_LIST_HEAD(&afu->crs); 678b087e619SIan Munsie 679f204e0b8SIan Munsie for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 6804752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 6814752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 6824752876cSChristophe Lombard CXL_AFU_ATTRS)) { 683f204e0b8SIan Munsie if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 684f204e0b8SIan Munsie goto err; 685f204e0b8SIan Munsie } 6864752876cSChristophe Lombard } 687f204e0b8SIan Munsie 688e36f6fe1SVaibhav Jain /* conditionally create the add the binary file for error info buffer */ 689e36f6fe1SVaibhav Jain if (afu->eb_len) { 690d6eb71a6SVaibhav Jain sysfs_attr_init(&afu->attr_eb.attr); 691d6eb71a6SVaibhav Jain 692e36f6fe1SVaibhav Jain afu->attr_eb.attr.name = "afu_err_buff"; 693e36f6fe1SVaibhav Jain afu->attr_eb.attr.mode = S_IRUGO; 694e36f6fe1SVaibhav Jain afu->attr_eb.size = afu->eb_len; 695e36f6fe1SVaibhav Jain afu->attr_eb.read = afu_eb_read; 696e36f6fe1SVaibhav Jain 697e36f6fe1SVaibhav Jain rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 698e36f6fe1SVaibhav Jain if (rc) { 699e36f6fe1SVaibhav Jain dev_err(&afu->dev, 700e36f6fe1SVaibhav Jain "Unable to create eb attr for the afu. Err(%d)\n", 701e36f6fe1SVaibhav Jain rc); 702e36f6fe1SVaibhav Jain goto err; 703e36f6fe1SVaibhav Jain } 704e36f6fe1SVaibhav Jain } 705e36f6fe1SVaibhav Jain 706b087e619SIan Munsie for (i = 0; i < afu->crs_num; i++) { 707b087e619SIan Munsie cr = cxl_sysfs_afu_new_cr(afu, i); 708b087e619SIan Munsie if (IS_ERR(cr)) { 709b087e619SIan Munsie rc = PTR_ERR(cr); 710b087e619SIan Munsie goto err1; 711b087e619SIan Munsie } 712b087e619SIan Munsie list_add(&cr->list, &afu->crs); 713b087e619SIan Munsie } 714b087e619SIan Munsie 715f204e0b8SIan Munsie return 0; 716f204e0b8SIan Munsie 717b087e619SIan Munsie err1: 718b087e619SIan Munsie cxl_sysfs_afu_remove(afu); 719b087e619SIan Munsie return rc; 720f204e0b8SIan Munsie err: 721e36f6fe1SVaibhav Jain /* reset the eb_len as we havent created the bin attr */ 722e36f6fe1SVaibhav Jain afu->eb_len = 0; 723e36f6fe1SVaibhav Jain 7244752876cSChristophe Lombard for (i--; i >= 0; i--) { 7254752876cSChristophe Lombard dev_attr = &afu_attrs[i]; 7264752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7274752876cSChristophe Lombard CXL_AFU_ATTRS)) 728f204e0b8SIan Munsie device_remove_file(&afu->dev, &afu_attrs[i]); 7294752876cSChristophe Lombard } 730f204e0b8SIan Munsie return rc; 731f204e0b8SIan Munsie } 732f204e0b8SIan Munsie 733f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 734f204e0b8SIan Munsie { 7354752876cSChristophe Lombard struct device_attribute *dev_attr; 736f204e0b8SIan Munsie int i, rc; 737f204e0b8SIan Munsie 738f204e0b8SIan Munsie 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 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 743f204e0b8SIan Munsie goto err; 744f204e0b8SIan Munsie } 7454752876cSChristophe Lombard } 746f204e0b8SIan Munsie 747f204e0b8SIan Munsie return 0; 748f204e0b8SIan Munsie 749f204e0b8SIan Munsie err: 7504752876cSChristophe Lombard for (i--; i >= 0; 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]); 7554752876cSChristophe Lombard } 756f204e0b8SIan Munsie return rc; 757f204e0b8SIan Munsie } 758f204e0b8SIan Munsie 759f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 760f204e0b8SIan Munsie { 7614752876cSChristophe Lombard struct device_attribute *dev_attr; 762f204e0b8SIan Munsie int i; 763f204e0b8SIan Munsie 7644752876cSChristophe Lombard for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 7654752876cSChristophe Lombard dev_attr = &afu_master_attrs[i]; 7664752876cSChristophe Lombard if (cxl_ops->support_attributes(dev_attr->attr.name, 7674752876cSChristophe Lombard CXL_AFU_MASTER_ATTRS)) 768f204e0b8SIan Munsie device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 769f204e0b8SIan Munsie } 7704752876cSChristophe Lombard } 771