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