xref: /linux/drivers/gpu/drm/xe/xe_configfs.c (revision fcad9bbf9e1a7de6c53908954ba1b1a1ab11ef1e)
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