Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <saravanak@google.com>
Link: https://lore.kernel.org/r/20200521191800.136035-2-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Saravana Kannan and committed by
Greg Kroah-Hartman
287905e6 fe940d73

+375 -36
+8
Documentation/ABI/testing/sysfs-devices-consumer
··· 1 + What: /sys/devices/.../consumer:<consumer> 2 + Date: May 2020 3 + Contact: Saravana Kannan <saravanak@google.com> 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.
+8
Documentation/ABI/testing/sysfs-devices-supplier
··· 1 + What: /sys/devices/.../supplier:<supplier> 2 + Date: May 2020 3 + Contact: Saravana Kannan <saravanak@google.com> 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.
+203 -8
drivers/base/core.c
··· 235 235 device_links_read_unlock(idx); 236 236 } 237 237 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 + 238 418 #define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \ 239 419 DL_FLAG_AUTOREMOVE_SUPPLIER | \ 240 420 DL_FLAG_AUTOPROBE_CONSUMER | \ ··· 587 407 588 408 refcount_set(&link->rpm_active, 1); 589 409 590 - if (flags & DL_FLAG_PM_RUNTIME) { 591 - if (flags & DL_FLAG_RPM_ACTIVE) 592 - refcount_inc(&link->rpm_active); 593 - 594 - pm_runtime_new_link(consumer); 595 - } 596 - 597 410 get_device(supplier); 598 411 link->supplier = supplier; 599 412 INIT_LIST_HEAD(&link->s_node); ··· 595 422 INIT_LIST_HEAD(&link->c_node); 596 423 link->flags = flags; 597 424 kref_init(&link->kref); 425 + 426 + link->link_dev.class = &devlink_class; 427 + device_set_pm_not_required(&link->link_dev); 428 + dev_set_name(&link->link_dev, "%s:%s", 429 + dev_name(supplier), dev_name(consumer)); 430 + if (device_register(&link->link_dev)) { 431 + put_device(consumer); 432 + put_device(supplier); 433 + kfree(link); 434 + link = NULL; 435 + goto out; 436 + } 437 + 438 + if (flags & DL_FLAG_PM_RUNTIME) { 439 + if (flags & DL_FLAG_RPM_ACTIVE) 440 + refcount_inc(&link->rpm_active); 441 + 442 + pm_runtime_new_link(consumer); 443 + } 598 444 599 445 /* Determine the initial link state. */ 600 446 if (flags & DL_FLAG_STATELESS) ··· 737 545 738 546 put_device(link->consumer); 739 547 put_device(link->supplier); 740 - kfree(link); 548 + device_unregister(&link->link_dev); 741 549 } 742 550 743 551 #ifdef CONFIG_SRCU ··· 1350 1158 static void device_links_purge(struct device *dev) 1351 1159 { 1352 1160 struct device_link *link, *ln; 1161 + 1162 + if (dev->class == &devlink_class) 1163 + return; 1353 1164 1354 1165 mutex_lock(&wfs_lock); 1355 1166 list_del(&dev->links.needs_suppliers);
+30 -28
include/linux/device.h
··· 387 387 #define DL_FLAG_SYNC_STATE_ONLY BIT(7) 388 388 389 389 /** 390 - * struct device_link - Device link representation. 391 - * @supplier: The device on the supplier end of the link. 392 - * @s_node: Hook to the supplier device's list of links to consumers. 393 - * @consumer: The device on the consumer end of the link. 394 - * @c_node: Hook to the consumer device's list of links to suppliers. 395 - * @status: The state of the link (with respect to the presence of drivers). 396 - * @flags: Link flags. 397 - * @rpm_active: Whether or not the consumer device is runtime-PM-active. 398 - * @kref: Count repeated addition of the same link. 399 - * @rcu_head: An RCU head to use for deferred execution of SRCU callbacks. 400 - * @supplier_preactivated: Supplier has been made active before consumer probe. 401 - */ 402 - struct device_link { 403 - struct device *supplier; 404 - struct list_head s_node; 405 - struct device *consumer; 406 - struct list_head c_node; 407 - enum device_link_state status; 408 - u32 flags; 409 - refcount_t rpm_active; 410 - struct kref kref; 411 - #ifdef CONFIG_SRCU 412 - struct rcu_head rcu_head; 413 - #endif 414 - bool supplier_preactivated; /* Owned by consumer probe. */ 415 - }; 416 - 417 - /** 418 390 * enum dl_dev_state - Device driver presence tracking information. 419 391 * @DL_DEV_NO_DRIVER: There is no driver attached to the device. 420 392 * @DL_DEV_PROBING: A driver is probing. ··· 594 622 defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) 595 623 bool dma_coherent:1; 596 624 #endif 625 + }; 626 + 627 + /** 628 + * struct device_link - Device link representation. 629 + * @supplier: The device on the supplier end of the link. 630 + * @s_node: Hook to the supplier device's list of links to consumers. 631 + * @consumer: The device on the consumer end of the link. 632 + * @c_node: Hook to the consumer device's list of links to suppliers. 633 + * @link_dev: device used to expose link details in sysfs 634 + * @status: The state of the link (with respect to the presence of drivers). 635 + * @flags: Link flags. 636 + * @rpm_active: Whether or not the consumer device is runtime-PM-active. 637 + * @kref: Count repeated addition of the same link. 638 + * @rcu_head: An RCU head to use for deferred execution of SRCU callbacks. 639 + * @supplier_preactivated: Supplier has been made active before consumer probe. 640 + */ 641 + struct device_link { 642 + struct device *supplier; 643 + struct list_head s_node; 644 + struct device *consumer; 645 + struct list_head c_node; 646 + struct device link_dev; 647 + enum device_link_state status; 648 + u32 flags; 649 + refcount_t rpm_active; 650 + struct kref kref; 651 + #ifdef CONFIG_SRCU 652 + struct rcu_head rcu_head; 653 + #endif 654 + bool supplier_preactivated; /* Owned by consumer probe. */ 597 655 }; 598 656 599 657 static inline struct device *kobj_to_dev(struct kobject *kobj)