Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
59struct xe_config_device {
60 struct config_group group;
61
62 bool survivability_mode;
63
64 /* protects attributes */
65 struct mutex lock;
66};
67
68static 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
73static 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
80static 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
97CONFIGFS_ATTR(, survivability_mode);
98
99static struct configfs_attribute *xe_config_device_attrs[] = {
100 &attr_survivability_mode,
101 NULL,
102};
103
104static 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
112static struct configfs_item_operations xe_config_device_ops = {
113 .release = xe_config_device_release,
114};
115
116static 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
122static 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
149static struct configfs_group_operations xe_config_device_group_ops = {
150 .make_group = xe_config_make_device_group,
151};
152
153static const struct config_item_type xe_configfs_type = {
154 .ct_group_ops = &xe_config_device_group_ops,
155 .ct_owner = THIS_MODULE,
156};
157
158static 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
167static 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 */
194bool 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 */
215void 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
229int __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
246void __exit xe_configfs_exit(void)
247{
248 configfs_unregister_subsystem(&xe_configfs);
249}
250