1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/bitops.h> 7 #include <linux/configfs.h> 8 #include <linux/find.h> 9 #include <linux/init.h> 10 #include <linux/module.h> 11 #include <linux/pci.h> 12 #include <linux/string.h> 13 14 #include "xe_configfs.h" 15 #include "xe_module.h" 16 17 #include "xe_hw_engine_types.h" 18 19 /** 20 * DOC: Xe Configfs 21 * 22 * Overview 23 * ========= 24 * 25 * Configfs is a filesystem-based manager of kernel objects. XE KMD registers a 26 * configfs subsystem called ``'xe'`` that creates a directory in the mounted configfs directory 27 * The user can create devices under this directory and configure them as necessary 28 * See Documentation/filesystems/configfs.rst for more information about how configfs works. 29 * 30 * Create devices 31 * =============== 32 * 33 * In order to create a device, the user has to create a directory inside ``'xe'``:: 34 * 35 * mkdir /sys/kernel/config/xe/0000:03:00.0/ 36 * 37 * Every device created is populated by the driver with entries that can be 38 * used to configure it:: 39 * 40 * /sys/kernel/config/xe/ 41 * .. 0000:03:00.0/ 42 * ... survivability_mode 43 * 44 * Configure Attributes 45 * ==================== 46 * 47 * Survivability mode: 48 * ------------------- 49 * 50 * Enable survivability mode on supported cards. This setting only takes 51 * effect when probing the device. Example to enable it:: 52 * 53 * # echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode 54 * # echo 0000:03:00.0 > /sys/bus/pci/drivers/xe/bind (Enters survivability mode if supported) 55 * 56 * Allowed engines: 57 * ---------------- 58 * 59 * Allow only a set of engine(s) to be available, disabling the other engines 60 * even if they are available in hardware. This is applied after HW fuses are 61 * considered on each tile. Examples: 62 * 63 * Allow only one render and one copy engines, nothing else:: 64 * 65 * # echo 'rcs0,bcs0' > /sys/kernel/config/xe/0000:03:00.0/engines_allowed 66 * 67 * Allow only compute engines and first copy engine:: 68 * 69 * # echo 'ccs*,bcs0' > /sys/kernel/config/xe/0000:03:00.0/engines_allowed 70 * 71 * Note that the engine names are the per-GT hardware names. On multi-tile 72 * platforms, writing ``rcs0,bcs0`` to this file would allow the first render 73 * and copy engines on each tile. 74 * 75 * The requested configuration may not be supported by the platform and driver 76 * may fail to probe. For example: if at least one copy engine is expected to be 77 * available for migrations, but it's disabled. This is intended for debugging 78 * purposes only. 79 * 80 * Remove devices 81 * ============== 82 * 83 * The created device directories can be removed using ``rmdir``:: 84 * 85 * rmdir /sys/kernel/config/xe/0000:03:00.0/ 86 */ 87 88 struct xe_config_device { 89 struct config_group group; 90 91 bool survivability_mode; 92 u64 engines_allowed; 93 94 /* protects attributes */ 95 struct mutex lock; 96 }; 97 98 struct engine_info { 99 const char *cls; 100 u64 mask; 101 }; 102 103 /* Some helpful macros to aid on the sizing of buffer allocation when parsing */ 104 #define MAX_ENGINE_CLASS_CHARS 5 105 #define MAX_ENGINE_INSTANCE_CHARS 2 106 107 static const struct engine_info engine_info[] = { 108 { .cls = "rcs", .mask = XE_HW_ENGINE_RCS_MASK }, 109 { .cls = "bcs", .mask = XE_HW_ENGINE_BCS_MASK }, 110 { .cls = "vcs", .mask = XE_HW_ENGINE_VCS_MASK }, 111 { .cls = "vecs", .mask = XE_HW_ENGINE_VECS_MASK }, 112 { .cls = "ccs", .mask = XE_HW_ENGINE_CCS_MASK }, 113 { .cls = "gsccs", .mask = XE_HW_ENGINE_GSCCS_MASK }, 114 }; 115 116 static struct xe_config_device *to_xe_config_device(struct config_item *item) 117 { 118 return container_of(to_config_group(item), struct xe_config_device, group); 119 } 120 121 static ssize_t survivability_mode_show(struct config_item *item, char *page) 122 { 123 struct xe_config_device *dev = to_xe_config_device(item); 124 125 return sprintf(page, "%d\n", dev->survivability_mode); 126 } 127 128 static ssize_t survivability_mode_store(struct config_item *item, const char *page, size_t len) 129 { 130 struct xe_config_device *dev = to_xe_config_device(item); 131 bool survivability_mode; 132 int ret; 133 134 ret = kstrtobool(page, &survivability_mode); 135 if (ret) 136 return ret; 137 138 mutex_lock(&dev->lock); 139 dev->survivability_mode = survivability_mode; 140 mutex_unlock(&dev->lock); 141 142 return len; 143 } 144 145 static ssize_t engines_allowed_show(struct config_item *item, char *page) 146 { 147 struct xe_config_device *dev = to_xe_config_device(item); 148 char *p = page; 149 150 for (size_t i = 0; i < ARRAY_SIZE(engine_info); i++) { 151 u64 mask = engine_info[i].mask; 152 153 if ((dev->engines_allowed & mask) == mask) { 154 p += sprintf(p, "%s*\n", engine_info[i].cls); 155 } else if (mask & dev->engines_allowed) { 156 u16 bit0 = __ffs64(mask), bit; 157 158 mask &= dev->engines_allowed; 159 160 for_each_set_bit(bit, (const unsigned long *)&mask, 64) 161 p += sprintf(p, "%s%u\n", engine_info[i].cls, 162 bit - bit0); 163 } 164 } 165 166 return p - page; 167 } 168 169 static bool lookup_engine_mask(const char *pattern, u64 *mask) 170 { 171 for (size_t i = 0; i < ARRAY_SIZE(engine_info); i++) { 172 u8 instance; 173 u16 bit; 174 175 if (!str_has_prefix(pattern, engine_info[i].cls)) 176 continue; 177 178 pattern += strlen(engine_info[i].cls); 179 180 if (!strcmp(pattern, "*")) { 181 *mask = engine_info[i].mask; 182 return true; 183 } 184 185 if (kstrtou8(pattern, 10, &instance)) 186 return false; 187 188 bit = __ffs64(engine_info[i].mask) + instance; 189 if (bit >= fls64(engine_info[i].mask)) 190 return false; 191 192 *mask = BIT_ULL(bit); 193 return true; 194 } 195 196 return false; 197 } 198 199 static ssize_t engines_allowed_store(struct config_item *item, const char *page, 200 size_t len) 201 { 202 struct xe_config_device *dev = to_xe_config_device(item); 203 size_t patternlen, p; 204 u64 mask, val = 0; 205 206 for (p = 0; p < len; p += patternlen + 1) { 207 char buf[MAX_ENGINE_CLASS_CHARS + MAX_ENGINE_INSTANCE_CHARS + 1]; 208 209 patternlen = strcspn(page + p, ",\n"); 210 if (patternlen >= sizeof(buf)) 211 return -EINVAL; 212 213 memcpy(buf, page + p, patternlen); 214 buf[patternlen] = '\0'; 215 216 if (!lookup_engine_mask(buf, &mask)) 217 return -EINVAL; 218 219 val |= mask; 220 } 221 222 mutex_lock(&dev->lock); 223 dev->engines_allowed = val; 224 mutex_unlock(&dev->lock); 225 226 return len; 227 } 228 229 CONFIGFS_ATTR(, survivability_mode); 230 CONFIGFS_ATTR(, engines_allowed); 231 232 static struct configfs_attribute *xe_config_device_attrs[] = { 233 &attr_survivability_mode, 234 &attr_engines_allowed, 235 NULL, 236 }; 237 238 static void xe_config_device_release(struct config_item *item) 239 { 240 struct xe_config_device *dev = to_xe_config_device(item); 241 242 mutex_destroy(&dev->lock); 243 kfree(dev); 244 } 245 246 static struct configfs_item_operations xe_config_device_ops = { 247 .release = xe_config_device_release, 248 }; 249 250 static const struct config_item_type xe_config_device_type = { 251 .ct_item_ops = &xe_config_device_ops, 252 .ct_attrs = xe_config_device_attrs, 253 .ct_owner = THIS_MODULE, 254 }; 255 256 static struct config_group *xe_config_make_device_group(struct config_group *group, 257 const char *name) 258 { 259 unsigned int domain, bus, slot, function; 260 struct xe_config_device *dev; 261 struct pci_dev *pdev; 262 int ret; 263 264 ret = sscanf(name, "%04x:%02x:%02x.%x", &domain, &bus, &slot, &function); 265 if (ret != 4) 266 return ERR_PTR(-EINVAL); 267 268 pdev = pci_get_domain_bus_and_slot(domain, bus, PCI_DEVFN(slot, function)); 269 if (!pdev) 270 return ERR_PTR(-ENODEV); 271 pci_dev_put(pdev); 272 273 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 274 if (!dev) 275 return ERR_PTR(-ENOMEM); 276 277 /* Default values */ 278 dev->engines_allowed = U64_MAX; 279 280 config_group_init_type_name(&dev->group, name, &xe_config_device_type); 281 282 mutex_init(&dev->lock); 283 284 return &dev->group; 285 } 286 287 static struct configfs_group_operations xe_config_device_group_ops = { 288 .make_group = xe_config_make_device_group, 289 }; 290 291 static const struct config_item_type xe_configfs_type = { 292 .ct_group_ops = &xe_config_device_group_ops, 293 .ct_owner = THIS_MODULE, 294 }; 295 296 static struct configfs_subsystem xe_configfs = { 297 .su_group = { 298 .cg_item = { 299 .ci_namebuf = "xe", 300 .ci_type = &xe_configfs_type, 301 }, 302 }, 303 }; 304 305 static struct xe_config_device *configfs_find_group(struct pci_dev *pdev) 306 { 307 struct config_item *item; 308 char name[64]; 309 310 snprintf(name, sizeof(name), "%04x:%02x:%02x.%x", pci_domain_nr(pdev->bus), 311 pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 312 313 mutex_lock(&xe_configfs.su_mutex); 314 item = config_group_find_item(&xe_configfs.su_group, name); 315 mutex_unlock(&xe_configfs.su_mutex); 316 317 if (!item) 318 return NULL; 319 320 return to_xe_config_device(item); 321 } 322 323 /** 324 * xe_configfs_get_survivability_mode - get configfs survivability mode attribute 325 * @pdev: pci device 326 * 327 * find the configfs group that belongs to the pci device and return 328 * the survivability mode attribute 329 * 330 * Return: survivability mode if config group is found, false otherwise 331 */ 332 bool xe_configfs_get_survivability_mode(struct pci_dev *pdev) 333 { 334 struct xe_config_device *dev = configfs_find_group(pdev); 335 bool mode; 336 337 if (!dev) 338 return false; 339 340 mode = dev->survivability_mode; 341 config_item_put(&dev->group.cg_item); 342 343 return mode; 344 } 345 346 /** 347 * xe_configfs_clear_survivability_mode - clear configfs survivability mode attribute 348 * @pdev: pci device 349 * 350 * find the configfs group that belongs to the pci device and clear survivability 351 * mode attribute 352 */ 353 void xe_configfs_clear_survivability_mode(struct pci_dev *pdev) 354 { 355 struct xe_config_device *dev = configfs_find_group(pdev); 356 357 if (!dev) 358 return; 359 360 mutex_lock(&dev->lock); 361 dev->survivability_mode = 0; 362 mutex_unlock(&dev->lock); 363 364 config_item_put(&dev->group.cg_item); 365 } 366 367 /** 368 * xe_configfs_get_engines_allowed - get engine allowed mask from configfs 369 * @pdev: pci device 370 * 371 * Find the configfs group that belongs to the pci device and return 372 * the mask of engines allowed to be used. 373 * 374 * Return: engine mask with allowed engines 375 */ 376 u64 xe_configfs_get_engines_allowed(struct pci_dev *pdev) 377 { 378 struct xe_config_device *dev = configfs_find_group(pdev); 379 u64 engines_allowed; 380 381 if (!dev) 382 return U64_MAX; 383 384 engines_allowed = dev->engines_allowed; 385 config_item_put(&dev->group.cg_item); 386 387 return engines_allowed; 388 } 389 390 int __init xe_configfs_init(void) 391 { 392 struct config_group *root = &xe_configfs.su_group; 393 int ret; 394 395 config_group_init(root); 396 mutex_init(&xe_configfs.su_mutex); 397 ret = configfs_register_subsystem(&xe_configfs); 398 if (ret) { 399 pr_err("Error %d while registering %s subsystem\n", 400 ret, root->cg_item.ci_namebuf); 401 return ret; 402 } 403 404 return 0; 405 } 406 407 void __exit xe_configfs_exit(void) 408 { 409 configfs_unregister_subsystem(&xe_configfs); 410 } 411 412