Skip to content

Commit 287905e

Browse files
Saravana Kannangregkh
authored andcommitted
driver core: Expose device link details in sysfs
It's helpful to be able to look at device link details from sysfs. So, expose it in sysfs. Say device-A is supplier of device-B. These are the additional files this patch would create: /sys/class/devlink/device-A:device-B/ auto_remove_on consumer/ -> .../device-B/ runtime_pm status supplier/ -> .../device-A/ sync_state_only /sys/devices/.../device-A/ consumer:device-B/ -> /sys/class/devlink/device-A:device-B/ /sys/devices/.../device-B/ supplier:device-A/ -> /sys/class/devlink/device-A:device-B/ That way: To get a list of all the device link in the system: ls /sys/class/devlink/ To get the consumer names and links of a device: ls -d /sys/devices/.../device-X/consumer:* To get the supplier names and links of a device: ls -d /sys/devices/.../device-X/supplier:* Signed-off-by: Saravana Kannan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fe940d7 commit 287905e

File tree

5 files changed

+375
-36
lines changed

5 files changed

+375
-36
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
What: /sys/class/devlink/.../
2+
Date: May 2020
3+
Contact: Saravana Kannan <[email protected]>
4+
Description:
5+
Provide a place in sysfs for the device link objects in the
6+
kernel at any given time. The name of a device link directory,
7+
denoted as ... above, is of the form <supplier>:<consumer>
8+
where <supplier> is the supplier device name and <consumer> is
9+
the consumer device name.
10+
11+
What: /sys/class/devlink/.../auto_remove_on
12+
Date: May 2020
13+
Contact: Saravana Kannan <[email protected]>
14+
Description:
15+
This file indicates if the device link will ever be
16+
automatically removed by the driver core when the consumer and
17+
supplier devices themselves are still present.
18+
19+
This will be one of the following strings:
20+
21+
'consumer unbind'
22+
'supplier unbind'
23+
'never'
24+
25+
'consumer unbind' means the device link will be removed when
26+
the consumer's driver is unbound from the consumer device.
27+
28+
'supplier unbind' means the device link will be removed when
29+
the supplier's driver is unbound from the supplier device.
30+
31+
'never' means the device link will not be automatically removed
32+
when as long as the supplier and consumer devices themselves
33+
are still present.
34+
35+
What: /sys/class/devlink/.../consumer
36+
Date: May 2020
37+
Contact: Saravana Kannan <[email protected]>
38+
Description:
39+
This file is a symlink to the consumer device's sysfs directory.
40+
41+
What: /sys/class/devlink/.../runtime_pm
42+
Date: May 2020
43+
Contact: Saravana Kannan <[email protected]>
44+
Description:
45+
This file indicates if the device link has any impact on the
46+
runtime power management behavior of the consumer and supplier
47+
devices. For example: Making sure the supplier doesn't enter
48+
runtime suspend while the consumer is active.
49+
50+
This will be one of the following strings:
51+
52+
'0' - Does not affect runtime power management
53+
'1' - Affects runtime power management
54+
55+
What: /sys/class/devlink/.../status
56+
Date: May 2020
57+
Contact: Saravana Kannan <[email protected]>
58+
Description:
59+
This file indicates the status of the device link. The status
60+
of a device link is affected by whether the supplier and
61+
consumer devices have been bound to their corresponding
62+
drivers. The status of a device link also affects the binding
63+
and unbinding of the supplier and consumer devices with their
64+
drivers and also affects whether the software state of the
65+
supplier device is synced with the hardware state of the
66+
supplier device after boot up.
67+
See also: sysfs-devices-state_synced.
68+
69+
This will be one of the following strings:
70+
71+
'not tracked'
72+
'dormant'
73+
'available'
74+
'consumer probing'
75+
'active'
76+
'supplier unbinding'
77+
'unknown'
78+
79+
'not tracked' means this device link does not track the status
80+
and has no impact on the binding, unbinding and syncing the
81+
hardware and software device state.
82+
83+
'dormant' means the supplier and the consumer devices have not
84+
bound to their driver.
85+
86+
'available' means the supplier has bound to its driver and is
87+
available to supply resources to the consumer device.
88+
89+
'consumer probing' means the consumer device is currently
90+
trying to bind to its driver.
91+
92+
'active' means the supplier and consumer devices have both
93+
bound successfully to their drivers.
94+
95+
'supplier unbinding' means the supplier devices is currently in
96+
the process of unbinding from its driver.
97+
98+
'unknown' means the state of the device link is not any of the
99+
above. If this is ever the value, there's a bug in the kernel.
100+
101+
What: /sys/class/devlink/.../supplier
102+
Date: May 2020
103+
Contact: Saravana Kannan <[email protected]>
104+
Description:
105+
This file is a symlink to the supplier device's sysfs directory.
106+
107+
What: /sys/class/devlink/.../sync_state_only
108+
Date: May 2020
109+
Contact: Saravana Kannan <[email protected]>
110+
Description:
111+
This file indicates if the device link is limited to only
112+
affecting the syncing of the hardware and software state of the
113+
supplier device.
114+
115+
This will be one of the following strings:
116+
117+
'0'
118+
'1' - Affects runtime power management
119+
120+
'0' means the device link can affect other device behaviors
121+
like binding/unbinding, suspend/resume, runtime power
122+
management, etc.
123+
124+
'1' means the device link will only affect the syncing of
125+
hardware and software state of the supplier device after boot
126+
up and doesn't not affect other behaviors of the devices.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
What: /sys/devices/.../consumer:<consumer>
2+
Date: May 2020
3+
Contact: Saravana Kannan <[email protected]>
4+
Description:
5+
The /sys/devices/.../consumer:<consumer> are symlinks to device
6+
links where this device is the supplier. <consumer> denotes the
7+
name of the consumer in that device link. There can be zero or
8+
more of these symlinks for a given device.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
What: /sys/devices/.../supplier:<supplier>
2+
Date: May 2020
3+
Contact: Saravana Kannan <[email protected]>
4+
Description:
5+
The /sys/devices/.../supplier:<supplier> are symlinks to device
6+
links where this device is the consumer. <supplier> denotes the
7+
name of the supplier in that device link. There can be zero or
8+
more of these symlinks for a given device.

drivers/base/core.c

Lines changed: 203 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,186 @@ void device_pm_move_to_tail(struct device *dev)
235235
device_links_read_unlock(idx);
236236
}
237237

238+
#define to_devlink(dev) container_of((dev), struct device_link, link_dev)
239+
240+
static ssize_t status_show(struct device *dev,
241+
struct device_attribute *attr, char *buf)
242+
{
243+
char *status;
244+
245+
switch (to_devlink(dev)->status) {
246+
case DL_STATE_NONE:
247+
status = "not tracked"; break;
248+
case DL_STATE_DORMANT:
249+
status = "dormant"; break;
250+
case DL_STATE_AVAILABLE:
251+
status = "available"; break;
252+
case DL_STATE_CONSUMER_PROBE:
253+
status = "consumer probing"; break;
254+
case DL_STATE_ACTIVE:
255+
status = "active"; break;
256+
case DL_STATE_SUPPLIER_UNBIND:
257+
status = "supplier unbinding"; break;
258+
default:
259+
status = "unknown"; break;
260+
}
261+
return sprintf(buf, "%s\n", status);
262+
}
263+
static DEVICE_ATTR_RO(status);
264+
265+
static ssize_t auto_remove_on_show(struct device *dev,
266+
struct device_attribute *attr, char *buf)
267+
{
268+
struct device_link *link = to_devlink(dev);
269+
char *str;
270+
271+
if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
272+
str = "supplier unbind";
273+
else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
274+
str = "consumer unbind";
275+
else
276+
str = "never";
277+
278+
return sprintf(buf, "%s\n", str);
279+
}
280+
static DEVICE_ATTR_RO(auto_remove_on);
281+
282+
static ssize_t runtime_pm_show(struct device *dev,
283+
struct device_attribute *attr, char *buf)
284+
{
285+
struct device_link *link = to_devlink(dev);
286+
287+
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));
288+
}
289+
static DEVICE_ATTR_RO(runtime_pm);
290+
291+
static ssize_t sync_state_only_show(struct device *dev,
292+
struct device_attribute *attr, char *buf)
293+
{
294+
struct device_link *link = to_devlink(dev);
295+
296+
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
297+
}
298+
static DEVICE_ATTR_RO(sync_state_only);
299+
300+
static struct attribute *devlink_attrs[] = {
301+
&dev_attr_status.attr,
302+
&dev_attr_auto_remove_on.attr,
303+
&dev_attr_runtime_pm.attr,
304+
&dev_attr_sync_state_only.attr,
305+
NULL,
306+
};
307+
ATTRIBUTE_GROUPS(devlink);
308+
309+
static void devlink_dev_release(struct device *dev)
310+
{
311+
kfree(to_devlink(dev));
312+
}
313+
314+
static struct class devlink_class = {
315+
.name = "devlink",
316+
.owner = THIS_MODULE,
317+
.dev_groups = devlink_groups,
318+
.dev_release = devlink_dev_release,
319+
};
320+
321+
static int devlink_add_symlinks(struct device *dev,
322+
struct class_interface *class_intf)
323+
{
324+
int ret;
325+
size_t len;
326+
struct device_link *link = to_devlink(dev);
327+
struct device *sup = link->supplier;
328+
struct device *con = link->consumer;
329+
char *buf;
330+
331+
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
332+
len += strlen("supplier:") + 1;
333+
buf = kzalloc(len, GFP_KERNEL);
334+
if (!buf)
335+
return -ENOMEM;
336+
337+
ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier");
338+
if (ret)
339+
goto out;
340+
341+
ret = sysfs_create_link(&link->link_dev.kobj, &con->kobj, "consumer");
342+
if (ret)
343+
goto err_con;
344+
345+
snprintf(buf, len, "consumer:%s", dev_name(con));
346+
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
347+
if (ret)
348+
goto err_con_dev;
349+
350+
snprintf(buf, len, "supplier:%s", dev_name(sup));
351+
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
352+
if (ret)
353+
goto err_sup_dev;
354+
355+
goto out;
356+
357+
err_sup_dev:
358+
snprintf(buf, len, "consumer:%s", dev_name(con));
359+
sysfs_remove_link(&sup->kobj, buf);
360+
err_con_dev:
361+
sysfs_remove_link(&link->link_dev.kobj, "consumer");
362+
err_con:
363+
sysfs_remove_link(&link->link_dev.kobj, "supplier");
364+
out:
365+
kfree(buf);
366+
return ret;
367+
}
368+
369+
static void devlink_remove_symlinks(struct device *dev,
370+
struct class_interface *class_intf)
371+
{
372+
struct device_link *link = to_devlink(dev);
373+
size_t len;
374+
struct device *sup = link->supplier;
375+
struct device *con = link->consumer;
376+
char *buf;
377+
378+
sysfs_remove_link(&link->link_dev.kobj, "consumer");
379+
sysfs_remove_link(&link->link_dev.kobj, "supplier");
380+
381+
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
382+
len += strlen("supplier:") + 1;
383+
buf = kzalloc(len, GFP_KERNEL);
384+
if (!buf) {
385+
WARN(1, "Unable to properly free device link symlinks!\n");
386+
return;
387+
}
388+
389+
snprintf(buf, len, "supplier:%s", dev_name(sup));
390+
sysfs_remove_link(&con->kobj, buf);
391+
snprintf(buf, len, "consumer:%s", dev_name(con));
392+
sysfs_remove_link(&sup->kobj, buf);
393+
kfree(buf);
394+
}
395+
396+
static struct class_interface devlink_class_intf = {
397+
.class = &devlink_class,
398+
.add_dev = devlink_add_symlinks,
399+
.remove_dev = devlink_remove_symlinks,
400+
};
401+
402+
static int __init devlink_class_init(void)
403+
{
404+
int ret;
405+
406+
ret = class_register(&devlink_class);
407+
if (ret)
408+
return ret;
409+
410+
ret = class_interface_register(&devlink_class_intf);
411+
if (ret)
412+
class_unregister(&devlink_class);
413+
414+
return ret;
415+
}
416+
postcore_initcall(devlink_class_init);
417+
238418
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
239419
DL_FLAG_AUTOREMOVE_SUPPLIER | \
240420
DL_FLAG_AUTOPROBE_CONSUMER | \
@@ -407,13 +587,6 @@ struct device_link *device_link_add(struct device *consumer,
407587

408588
refcount_set(&link->rpm_active, 1);
409589

410-
if (flags & DL_FLAG_PM_RUNTIME) {
411-
if (flags & DL_FLAG_RPM_ACTIVE)
412-
refcount_inc(&link->rpm_active);
413-
414-
pm_runtime_new_link(consumer);
415-
}
416-
417590
get_device(supplier);
418591
link->supplier = supplier;
419592
INIT_LIST_HEAD(&link->s_node);
@@ -423,6 +596,25 @@ struct device_link *device_link_add(struct device *consumer,
423596
link->flags = flags;
424597
kref_init(&link->kref);
425598

599+
link->link_dev.class = &devlink_class;
600+
device_set_pm_not_required(&link->link_dev);
601+
dev_set_name(&link->link_dev, "%s:%s",
602+
dev_name(supplier), dev_name(consumer));
603+
if (device_register(&link->link_dev)) {
604+
put_device(consumer);
605+
put_device(supplier);
606+
kfree(link);
607+
link = NULL;
608+
goto out;
609+
}
610+
611+
if (flags & DL_FLAG_PM_RUNTIME) {
612+
if (flags & DL_FLAG_RPM_ACTIVE)
613+
refcount_inc(&link->rpm_active);
614+
615+
pm_runtime_new_link(consumer);
616+
}
617+
426618
/* Determine the initial link state. */
427619
if (flags & DL_FLAG_STATELESS)
428620
link->status = DL_STATE_NONE;
@@ -545,7 +737,7 @@ static void device_link_free(struct device_link *link)
545737

546738
put_device(link->consumer);
547739
put_device(link->supplier);
548-
kfree(link);
740+
device_unregister(&link->link_dev);
549741
}
550742

551743
#ifdef CONFIG_SRCU
@@ -1159,6 +1351,9 @@ static void device_links_purge(struct device *dev)
11591351
{
11601352
struct device_link *link, *ln;
11611353

1354+
if (dev->class == &devlink_class)
1355+
return;
1356+
11621357
mutex_lock(&wfs_lock);
11631358
list_del(&dev->links.needs_suppliers);
11641359
mutex_unlock(&wfs_lock);

0 commit comments

Comments
 (0)