116280dedSRiana Tauro // SPDX-License-Identifier: MIT 216280dedSRiana Tauro /* 316280dedSRiana Tauro * Copyright © 2025 Intel Corporation 416280dedSRiana Tauro */ 516280dedSRiana Tauro 616280dedSRiana Tauro #include <linux/configfs.h> 716280dedSRiana Tauro #include <linux/init.h> 816280dedSRiana Tauro #include <linux/module.h> 916280dedSRiana Tauro #include <linux/pci.h> 1016280dedSRiana Tauro 1116280dedSRiana Tauro #include "xe_configfs.h" 1216280dedSRiana Tauro #include "xe_module.h" 1316280dedSRiana Tauro 1416280dedSRiana Tauro /** 1516280dedSRiana Tauro * DOC: Xe Configfs 1616280dedSRiana Tauro * 1716280dedSRiana Tauro * Overview 1816280dedSRiana Tauro * ========= 1916280dedSRiana Tauro * 2016280dedSRiana Tauro * Configfs is a filesystem-based manager of kernel objects. XE KMD registers a 2116280dedSRiana Tauro * configfs subsystem called ``'xe'`` that creates a directory in the mounted configfs directory 2216280dedSRiana Tauro * The user can create devices under this directory and configure them as necessary 2316280dedSRiana Tauro * See Documentation/filesystems/configfs.rst for more information about how configfs works. 2416280dedSRiana Tauro * 2516280dedSRiana Tauro * Create devices 2616280dedSRiana Tauro * =============== 2716280dedSRiana Tauro * 2816280dedSRiana Tauro * In order to create a device, the user has to create a directory inside ``'xe'``:: 2916280dedSRiana Tauro * 3016280dedSRiana Tauro * mkdir /sys/kernel/config/xe/0000:03:00.0/ 3116280dedSRiana Tauro * 3216280dedSRiana Tauro * Every device created is populated by the driver with entries that can be 3316280dedSRiana Tauro * used to configure it:: 3416280dedSRiana Tauro * 3516280dedSRiana Tauro * /sys/kernel/config/xe/ 3616280dedSRiana Tauro * .. 0000:03:00.0/ 3716280dedSRiana Tauro * ... survivability_mode 3816280dedSRiana Tauro * 3916280dedSRiana Tauro * Configure Attributes 4016280dedSRiana Tauro * ==================== 4116280dedSRiana Tauro * 4216280dedSRiana Tauro * Survivability mode: 4316280dedSRiana Tauro * ------------------- 4416280dedSRiana Tauro * 4516280dedSRiana Tauro * Enable survivability mode on supported cards. This setting only takes 4616280dedSRiana Tauro * effect when probing the device. Example to enable it:: 4716280dedSRiana Tauro * 4816280dedSRiana Tauro * # echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode 4916280dedSRiana Tauro * # echo 0000:03:00.0 > /sys/bus/pci/drivers/xe/bind (Enters survivability mode if supported) 5016280dedSRiana Tauro * 5116280dedSRiana Tauro * Remove devices 5216280dedSRiana Tauro * ============== 5316280dedSRiana Tauro * 5416280dedSRiana Tauro * The created device directories can be removed using ``rmdir``:: 5516280dedSRiana Tauro * 5616280dedSRiana Tauro * rmdir /sys/kernel/config/xe/0000:03:00.0/ 5716280dedSRiana Tauro */ 5816280dedSRiana Tauro 5916280dedSRiana Tauro struct xe_config_device { 6016280dedSRiana Tauro struct config_group group; 6116280dedSRiana Tauro 6216280dedSRiana Tauro bool survivability_mode; 6316280dedSRiana Tauro 6416280dedSRiana Tauro /* protects attributes */ 6516280dedSRiana Tauro struct mutex lock; 6616280dedSRiana Tauro }; 6716280dedSRiana Tauro 6816280dedSRiana Tauro static struct xe_config_device *to_xe_config_device(struct config_item *item) 6916280dedSRiana Tauro { 7016280dedSRiana Tauro return container_of(to_config_group(item), struct xe_config_device, group); 7116280dedSRiana Tauro } 7216280dedSRiana Tauro 7316280dedSRiana Tauro static ssize_t survivability_mode_show(struct config_item *item, char *page) 7416280dedSRiana Tauro { 7516280dedSRiana Tauro struct xe_config_device *dev = to_xe_config_device(item); 7616280dedSRiana Tauro 7716280dedSRiana Tauro return sprintf(page, "%d\n", dev->survivability_mode); 7816280dedSRiana Tauro } 7916280dedSRiana Tauro 8016280dedSRiana Tauro static ssize_t survivability_mode_store(struct config_item *item, const char *page, size_t len) 8116280dedSRiana Tauro { 8216280dedSRiana Tauro struct xe_config_device *dev = to_xe_config_device(item); 8316280dedSRiana Tauro bool survivability_mode; 8416280dedSRiana Tauro int ret; 8516280dedSRiana Tauro 8616280dedSRiana Tauro ret = kstrtobool(page, &survivability_mode); 8716280dedSRiana Tauro if (ret) 8816280dedSRiana Tauro return ret; 8916280dedSRiana Tauro 9016280dedSRiana Tauro mutex_lock(&dev->lock); 9116280dedSRiana Tauro dev->survivability_mode = survivability_mode; 9216280dedSRiana Tauro mutex_unlock(&dev->lock); 9316280dedSRiana Tauro 9416280dedSRiana Tauro return len; 9516280dedSRiana Tauro } 9616280dedSRiana Tauro 9716280dedSRiana Tauro CONFIGFS_ATTR(, survivability_mode); 9816280dedSRiana Tauro 9916280dedSRiana Tauro static struct configfs_attribute *xe_config_device_attrs[] = { 10016280dedSRiana Tauro &attr_survivability_mode, 10116280dedSRiana Tauro NULL, 10216280dedSRiana Tauro }; 10316280dedSRiana Tauro 10416280dedSRiana Tauro static void xe_config_device_release(struct config_item *item) 10516280dedSRiana Tauro { 10616280dedSRiana Tauro struct xe_config_device *dev = to_xe_config_device(item); 10716280dedSRiana Tauro 10816280dedSRiana Tauro mutex_destroy(&dev->lock); 10916280dedSRiana Tauro kfree(dev); 11016280dedSRiana Tauro } 11116280dedSRiana Tauro 11216280dedSRiana Tauro static struct configfs_item_operations xe_config_device_ops = { 11316280dedSRiana Tauro .release = xe_config_device_release, 11416280dedSRiana Tauro }; 11516280dedSRiana Tauro 11616280dedSRiana Tauro static const struct config_item_type xe_config_device_type = { 11716280dedSRiana Tauro .ct_item_ops = &xe_config_device_ops, 11816280dedSRiana Tauro .ct_attrs = xe_config_device_attrs, 11916280dedSRiana Tauro .ct_owner = THIS_MODULE, 12016280dedSRiana Tauro }; 12116280dedSRiana Tauro 12216280dedSRiana Tauro static struct config_group *xe_config_make_device_group(struct config_group *group, 12316280dedSRiana Tauro const char *name) 12416280dedSRiana Tauro { 12516280dedSRiana Tauro unsigned int domain, bus, slot, function; 12616280dedSRiana Tauro struct xe_config_device *dev; 12716280dedSRiana Tauro struct pci_dev *pdev; 12816280dedSRiana Tauro int ret; 12916280dedSRiana Tauro 13016280dedSRiana Tauro ret = sscanf(name, "%04x:%02x:%02x.%x", &domain, &bus, &slot, &function); 13116280dedSRiana Tauro if (ret != 4) 13216280dedSRiana Tauro return ERR_PTR(-EINVAL); 13316280dedSRiana Tauro 13416280dedSRiana Tauro pdev = pci_get_domain_bus_and_slot(domain, bus, PCI_DEVFN(slot, function)); 13516280dedSRiana Tauro if (!pdev) 13616280dedSRiana Tauro return ERR_PTR(-EINVAL); 13716280dedSRiana Tauro 13816280dedSRiana Tauro dev = kzalloc(sizeof(*dev), GFP_KERNEL); 13916280dedSRiana Tauro if (!dev) 14016280dedSRiana Tauro return ERR_PTR(-ENOMEM); 14116280dedSRiana Tauro 14216280dedSRiana Tauro config_group_init_type_name(&dev->group, name, &xe_config_device_type); 14316280dedSRiana Tauro 14416280dedSRiana Tauro mutex_init(&dev->lock); 14516280dedSRiana Tauro 14616280dedSRiana Tauro return &dev->group; 14716280dedSRiana Tauro } 14816280dedSRiana Tauro 14916280dedSRiana Tauro static struct configfs_group_operations xe_config_device_group_ops = { 15016280dedSRiana Tauro .make_group = xe_config_make_device_group, 15116280dedSRiana Tauro }; 15216280dedSRiana Tauro 15316280dedSRiana Tauro static const struct config_item_type xe_configfs_type = { 15416280dedSRiana Tauro .ct_group_ops = &xe_config_device_group_ops, 15516280dedSRiana Tauro .ct_owner = THIS_MODULE, 15616280dedSRiana Tauro }; 15716280dedSRiana Tauro 15816280dedSRiana Tauro static struct configfs_subsystem xe_configfs = { 15916280dedSRiana Tauro .su_group = { 16016280dedSRiana Tauro .cg_item = { 16116280dedSRiana Tauro .ci_namebuf = "xe", 16216280dedSRiana Tauro .ci_type = &xe_configfs_type, 16316280dedSRiana Tauro }, 16416280dedSRiana Tauro }, 16516280dedSRiana Tauro }; 16616280dedSRiana Tauro 167*bc417e54SRiana Tauro static struct xe_config_device *configfs_find_group(struct pci_dev *pdev) 168*bc417e54SRiana Tauro { 169*bc417e54SRiana Tauro struct config_item *item; 170*bc417e54SRiana Tauro char name[64]; 171*bc417e54SRiana Tauro 172*bc417e54SRiana Tauro snprintf(name, sizeof(name), "%04x:%02x:%02x.%x", pci_domain_nr(pdev->bus), 173*bc417e54SRiana Tauro pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 174*bc417e54SRiana Tauro 175*bc417e54SRiana Tauro mutex_lock(&xe_configfs.su_mutex); 176*bc417e54SRiana Tauro item = config_group_find_item(&xe_configfs.su_group, name); 177*bc417e54SRiana Tauro mutex_unlock(&xe_configfs.su_mutex); 178*bc417e54SRiana Tauro 179*bc417e54SRiana Tauro if (!item) 180*bc417e54SRiana Tauro return NULL; 181*bc417e54SRiana Tauro 182*bc417e54SRiana Tauro return to_xe_config_device(item); 183*bc417e54SRiana Tauro } 184*bc417e54SRiana Tauro 185*bc417e54SRiana Tauro /** 186*bc417e54SRiana Tauro * xe_configfs_get_survivability_mode - get configfs survivability mode attribute 187*bc417e54SRiana Tauro * @pdev: pci device 188*bc417e54SRiana Tauro * 189*bc417e54SRiana Tauro * find the configfs group that belongs to the pci device and return 190*bc417e54SRiana Tauro * the survivability mode attribute 191*bc417e54SRiana Tauro * 192*bc417e54SRiana Tauro * Return: survivability mode if config group is found, false otherwise 193*bc417e54SRiana Tauro */ 194*bc417e54SRiana Tauro bool xe_configfs_get_survivability_mode(struct pci_dev *pdev) 195*bc417e54SRiana Tauro { 196*bc417e54SRiana Tauro struct xe_config_device *dev = configfs_find_group(pdev); 197*bc417e54SRiana Tauro bool mode; 198*bc417e54SRiana Tauro 199*bc417e54SRiana Tauro if (!dev) 200*bc417e54SRiana Tauro return false; 201*bc417e54SRiana Tauro 202*bc417e54SRiana Tauro mode = dev->survivability_mode; 203*bc417e54SRiana Tauro config_item_put(&dev->group.cg_item); 204*bc417e54SRiana Tauro 205*bc417e54SRiana Tauro return mode; 206*bc417e54SRiana Tauro } 207*bc417e54SRiana Tauro 208*bc417e54SRiana Tauro /** 209*bc417e54SRiana Tauro * xe_configfs_clear_survivability_mode - clear configfs survivability mode attribute 210*bc417e54SRiana Tauro * @pdev: pci device 211*bc417e54SRiana Tauro * 212*bc417e54SRiana Tauro * find the configfs group that belongs to the pci device and clear survivability 213*bc417e54SRiana Tauro * mode attribute 214*bc417e54SRiana Tauro */ 215*bc417e54SRiana Tauro void xe_configfs_clear_survivability_mode(struct pci_dev *pdev) 216*bc417e54SRiana Tauro { 217*bc417e54SRiana Tauro struct xe_config_device *dev = configfs_find_group(pdev); 218*bc417e54SRiana Tauro 219*bc417e54SRiana Tauro if (!dev) 220*bc417e54SRiana Tauro return; 221*bc417e54SRiana Tauro 222*bc417e54SRiana Tauro mutex_lock(&dev->lock); 223*bc417e54SRiana Tauro dev->survivability_mode = 0; 224*bc417e54SRiana Tauro mutex_unlock(&dev->lock); 225*bc417e54SRiana Tauro 226*bc417e54SRiana Tauro config_item_put(&dev->group.cg_item); 227*bc417e54SRiana Tauro } 228*bc417e54SRiana Tauro 22916280dedSRiana Tauro int __init xe_configfs_init(void) 23016280dedSRiana Tauro { 23116280dedSRiana Tauro struct config_group *root = &xe_configfs.su_group; 23216280dedSRiana Tauro int ret; 23316280dedSRiana Tauro 23416280dedSRiana Tauro config_group_init(root); 23516280dedSRiana Tauro mutex_init(&xe_configfs.su_mutex); 23616280dedSRiana Tauro ret = configfs_register_subsystem(&xe_configfs); 23716280dedSRiana Tauro if (ret) { 23816280dedSRiana Tauro pr_err("Error %d while registering %s subsystem\n", 23916280dedSRiana Tauro ret, root->cg_item.ci_namebuf); 24016280dedSRiana Tauro return ret; 24116280dedSRiana Tauro } 24216280dedSRiana Tauro 24316280dedSRiana Tauro return 0; 24416280dedSRiana Tauro } 24516280dedSRiana Tauro 24616280dedSRiana Tauro void __exit xe_configfs_exit(void) 24716280dedSRiana Tauro { 24816280dedSRiana Tauro configfs_unregister_subsystem(&xe_configfs); 24916280dedSRiana Tauro } 25016280dedSRiana Tauro 251