Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. */ #include <linux/cpu.h> #include <linux/delay.h> #include <linux/fs.h> #include <linux/semaphore.h> #include <linux/slab.h> #include "ifs.h" /* * Protects against simultaneous tests on multiple cores, or * reloading can file while a test is in progress */ static DEFINE_SEMAPHORE(ifs_sem, 1); /* * The sysfs interface to check additional details of last test * cat /sys/devices/system/platform/ifs/details */ static ssize_t details_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ifs_data *ifsd = ifs_get_data(dev); return sysfs_emit(buf, "%#llx\n", ifsd->scan_details); } static DEVICE_ATTR_RO(details); static const char * const status_msg[] = { [SCAN_NOT_TESTED] = "untested", [SCAN_TEST_PASS] = "pass", [SCAN_TEST_FAIL] = "fail" }; /* * The sysfs interface to check the test status: * To check the status of last test * cat /sys/devices/platform/ifs/status */ static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ifs_data *ifsd = ifs_get_data(dev); return sysfs_emit(buf, "%s\n", status_msg[ifsd->status]); } static DEVICE_ATTR_RO(status); /* * The sysfs interface for single core testing * To start test, for example, cpu5 * echo 5 > /sys/devices/platform/ifs/run_test * To check the result: * cat /sys/devices/platform/ifs/result * The sibling core gets tested at the same time. */ static ssize_t run_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int cpu; int rc; rc = kstrtouint(buf, 0, &cpu); if (rc < 0 || cpu >= nr_cpu_ids) return -EINVAL; if (down_interruptible(&ifs_sem)) return -EINTR; rc = do_core_test(cpu, dev); up(&ifs_sem); return rc ? rc : count; } static DEVICE_ATTR_WO(run_test); static ssize_t current_batch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ifs_data *ifsd = ifs_get_data(dev); unsigned int cur_batch; int rc; rc = kstrtouint(buf, 0, &cur_batch); if (rc < 0 || cur_batch > 0xff) return -EINVAL; if (down_interruptible(&ifs_sem)) return -EINTR; ifsd->cur_batch = cur_batch; rc = ifs_load_firmware(dev); up(&ifs_sem); return (rc == 0) ? count : rc; } static ssize_t current_batch_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ifs_data *ifsd = ifs_get_data(dev); if (!ifsd->loaded) return sysfs_emit(buf, "none\n"); else return sysfs_emit(buf, "0x%02x\n", ifsd->cur_batch); } static DEVICE_ATTR_RW(current_batch); /* * Display currently loaded IFS image version. */ static ssize_t image_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ifs_data *ifsd = ifs_get_data(dev); if (!ifsd->loaded) return sysfs_emit(buf, "%s\n", "none"); else return sysfs_emit(buf, "%#x\n", ifsd->loaded_version); } static DEVICE_ATTR_RO(image_version); /* global scan sysfs attributes */ struct attribute *plat_ifs_attrs[] = { &dev_attr_details.attr, &dev_attr_status.attr, &dev_attr_run_test.attr, &dev_attr_current_batch.attr, &dev_attr_image_version.attr, NULL }; /* global array sysfs attributes */ struct attribute *plat_ifs_array_attrs[] = { &dev_attr_details.attr, &dev_attr_status.attr, &dev_attr_run_test.attr, NULL }; |