1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/configfs.h> 7 #include <linux/init.h> 8 #include <linux/module.h> 9 #include <linux/pci.h> 10 11 #include "xe_configfs.h" 12 #include "xe_module.h" 13 14 /** 15 * DOC: Xe Configfs 16 * 17 * Overview 18 * ========= 19 * 20 * Configfs is a filesystem-based manager of kernel objects. XE KMD registers a 21 * configfs subsystem called ``'xe'`` that creates a directory in the mounted configfs directory 22 * The user can create devices under this directory and configure them as necessary 23 * See Documentation/filesystems/configfs.rst for more information about how configfs works. 24 * 25 * Create devices 26 * =============== 27 * 28 * In order to create a device, the user has to create a directory inside ``'xe'``:: 29 * 30 * mkdir /sys/kernel/config/xe/0000:03:00.0/ 31 * 32 * Every device created is populated by the driver with entries that can be 33 * used to configure it:: 34 * 35 * /sys/kernel/config/xe/ 36 * .. 0000:03:00.0/ 37 * ... survivability_mode 38 * 39 * Configure Attributes 40 * ==================== 41 * 42 * Survivability mode: 43 * ------------------- 44 * 45 * Enable survivability mode on supported cards. This setting only takes 46 * effect when probing the device. Example to enable it:: 47 * 48 * # echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode 49 * # echo 0000:03:00.0 > /sys/bus/pci/drivers/xe/bind (Enters survivability mode if supported) 50 * 51 * Remove devices 52 * ============== 53 * 54 * The created device directories can be removed using ``rmdir``:: 55 * 56 * rmdir /sys/kernel/config/xe/0000:03:00.0/ 57 */ 58 59 struct xe_config_device { 60 struct config_group group; 61 62 bool survivability_mode; 63 64 /* protects attributes */ 65 struct mutex lock; 66 }; 67 68 static struct xe_config_device *to_xe_config_device(struct config_item *item) 69 { 70 return container_of(to_config_group(item), struct xe_config_device, group); 71 } 72 73 static ssize_t survivability_mode_show(struct config_item *item, char *page) 74 { 75 struct xe_config_device *dev = to_xe_config_device(item); 76 77 return sprintf(page, "%d\n", dev->survivability_mode); 78 } 79 80 static ssize_t survivability_mode_store(struct config_item *item, const char *page, size_t len) 81 { 82 struct xe_config_device *dev = to_xe_config_device(item); 83 bool survivability_mode; 84 int ret; 85 86 ret = kstrtobool(page, &survivability_mode); 87 if (ret) 88 return ret; 89 90 mutex_lock(&dev->lock); 91 dev->survivability_mode = survivability_mode; 92 mutex_unlock(&dev->lock); 93 94 return len; 95 } 96 97 CONFIGFS_ATTR(, survivability_mode); 98 99 static struct configfs_attribute *xe_config_device_attrs[] = { 100 &attr_survivability_mode, 101 NULL, 102 }; 103 104 static void xe_config_device_release(struct config_item *item) 105 { 106 struct xe_config_device *dev = to_xe_config_device(item); 107 108 mutex_destroy(&dev->lock); 109 kfree(dev); 110 } 111 112 static struct configfs_item_operations xe_config_device_ops = { 113 .release = xe_config_device_release, 114 }; 115 116 static const struct config_item_type xe_config_device_type = { 117 .ct_item_ops = &xe_config_device_ops, 118 .ct_attrs = xe_config_device_attrs, 119 .ct_owner = THIS_MODULE, 120 }; 121 122 static struct config_group *xe_config_make_device_group(struct config_group *group, 123 const char *name) 124 { 125 unsigned int domain, bus, slot, function; 126 struct xe_config_device *dev; 127 struct pci_dev *pdev; 128 int ret; 129 130 ret = sscanf(name, "%04x:%02x:%02x.%x", &domain, &bus, &slot, &function); 131 if (ret != 4) 132 return ERR_PTR(-EINVAL); 133 134 pdev = pci_get_domain_bus_and_slot(domain, bus, PCI_DEVFN(slot, function)); 135 if (!pdev) 136 return ERR_PTR(-EINVAL); 137 138 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 139 if (!dev) 140 return ERR_PTR(-ENOMEM); 141 142 config_group_init_type_name(&dev->group, name, &xe_config_device_type); 143 144 mutex_init(&dev->lock); 145 146 return &dev->group; 147 } 148 149 static struct configfs_group_operations xe_config_device_group_ops = { 150 .make_group = xe_config_make_device_group, 151 }; 152 153 static const struct config_item_type xe_configfs_type = { 154 .ct_group_ops = &xe_config_device_group_ops, 155 .ct_owner = THIS_MODULE, 156 }; 157 158 static struct configfs_subsystem xe_configfs = { 159 .su_group = { 160 .cg_item = { 161 .ci_namebuf = "xe", 162 .ci_type = &xe_configfs_type, 163 }, 164 }, 165 }; 166 167 static struct xe_config_device *configfs_find_group(struct pci_dev *pdev) 168 { 169 struct config_item *item; 170 char name[64]; 171 172 snprintf(name, sizeof(name), "%04x:%02x:%02x.%x", pci_domain_nr(pdev->bus), 173 pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 174 175 mutex_lock(&xe_configfs.su_mutex); 176 item = config_group_find_item(&xe_configfs.su_group, name); 177 mutex_unlock(&xe_configfs.su_mutex); 178 179 if (!item) 180 return NULL; 181 182 return to_xe_config_device(item); 183 } 184 185 /** 186 * xe_configfs_get_survivability_mode - get configfs survivability mode attribute 187 * @pdev: pci device 188 * 189 * find the configfs group that belongs to the pci device and return 190 * the survivability mode attribute 191 * 192 * Return: survivability mode if config group is found, false otherwise 193 */ 194 bool xe_configfs_get_survivability_mode(struct pci_dev *pdev) 195 { 196 struct xe_config_device *dev = configfs_find_group(pdev); 197 bool mode; 198 199 if (!dev) 200 return false; 201 202 mode = dev->survivability_mode; 203 config_item_put(&dev->group.cg_item); 204 205 return mode; 206 } 207 208 /** 209 * xe_configfs_clear_survivability_mode - clear configfs survivability mode attribute 210 * @pdev: pci device 211 * 212 * find the configfs group that belongs to the pci device and clear survivability 213 * mode attribute 214 */ 215 void xe_configfs_clear_survivability_mode(struct pci_dev *pdev) 216 { 217 struct xe_config_device *dev = configfs_find_group(pdev); 218 219 if (!dev) 220 return; 221 222 mutex_lock(&dev->lock); 223 dev->survivability_mode = 0; 224 mutex_unlock(&dev->lock); 225 226 config_item_put(&dev->group.cg_item); 227 } 228 229 int __init xe_configfs_init(void) 230 { 231 struct config_group *root = &xe_configfs.su_group; 232 int ret; 233 234 config_group_init(root); 235 mutex_init(&xe_configfs.su_mutex); 236 ret = configfs_register_subsystem(&xe_configfs); 237 if (ret) { 238 pr_err("Error %d while registering %s subsystem\n", 239 ret, root->cg_item.ci_namebuf); 240 return ret; 241 } 242 243 return 0; 244 } 245 246 void __exit xe_configfs_exit(void) 247 { 248 configfs_unregister_subsystem(&xe_configfs); 249 } 250 251