When ACPI table includes _PLD fields for a device, create a new
directory (physical_location) in sysfs to share _PLD fields.
Currently without PLD information, when there are multiple of same
devices, it is hard to distinguish which device corresponds to which
physical device at which location. For example, when there are two Type
C connectors, it is hard to find out which connector corresponds to the
Type C port on the left panel versus the Type C port on the right panel.
With PLD information provided, we can determine which specific device at
which location is doing what.
_PLD output includes much more fields, but only generic fields are added
and exposed to sysfs, so that non-ACPI devices can also support it in
the future. The minimal generic fields needed for locating a device are
the following.
- panel
- vertical_position
- horizontal_position
- dock
- lid
Signed-off-by: Won Chung <[email protected]>
---
Changes from v4
- Remove physical_location directory when device is deleted.
- Correctly handle error from adding physical_location in
device_add_attrs().
Changes from v3
- Move dev_add_physical_location() and dev_attr_physical_location_group
to driver/base/physical_location.h.
- Use pointer and reorder physical_location in struct device to pack its
bytes. (checked using pahole)
- Unify naming to physical_location since the name location is used in
some places like USB port for different information.
Changes from v2
- Use sysfs_emit to create files.
- Correct mix of spaces and tabs.
Changes from v1
- Correct directory names in Documentation.
- Clarify namings in core.c
.../testing/sysfs-devices-physical_location | 42 ++++++
drivers/base/Makefile | 1 +
drivers/base/core.c | 11 ++
drivers/base/physical_location.c | 137 ++++++++++++++++++
drivers/base/physical_location.h | 16 ++
include/linux/device.h | 73 ++++++++++
6 files changed, 280 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-devices-physical_location
create mode 100644 drivers/base/physical_location.c
create mode 100644 drivers/base/physical_location.h
diff --git a/Documentation/ABI/testing/sysfs-devices-physical_location b/Documentation/ABI/testing/sysfs-devices-physical_location
new file mode 100644
index 000000000000..202324b87083
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-physical_location
@@ -0,0 +1,42 @@
+What: /sys/devices/.../physical_location
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ This directory contains information on physical location of
+ the device connection point with respect to the system's
+ housing.
+
+What: /sys/devices/.../physical_location/panel
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ Describes which panel surface of the system’s housing the
+ device connection point resides on.
+
+What: /sys/devices/.../physical_location/vertical_position
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ Describes vertical position of the device connection point on
+ the panel surface.
+
+What: /sys/devices/.../physical_location/horizontal_position
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ Describes horizontal position of the device connection point on
+ the panel surface.
+
+What: /sys/devices/.../physical_location/dock
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ "Yes" if the device connection point resides in a docking
+ station or a port replicator. "No" otherwise.
+
+What: /sys/devices/.../physical_location/lid
+Date: March 2022
+Contact: Won Chung <[email protected]>
+Description:
+ "Yes" if the device connection point resides on the lid of
+ laptop system. "No" otherwise.
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 02f7f1358e86..83217d243c25 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o
+obj-$(CONFIG_ACPI) += physical_location.o
obj-y += test/
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 7bb957b11861..9054a2d8bbb6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -32,6 +32,7 @@
#include <linux/dma-map-ops.h> /* for dma_default_coherent */
#include "base.h"
+#include "physical_location.h"
#include "power/power.h"
#ifdef CONFIG_SYSFS_DEPRECATED
@@ -2649,8 +2650,17 @@ static int device_add_attrs(struct device *dev)
goto err_remove_dev_waiting_for_supplier;
}
+ if (dev_add_physical_location(dev)) {
+ error = device_add_group(dev,
+ &dev_attr_physical_location_group);
+ if (error)
+ goto err_remove_dev_removable;
+ }
+
return 0;
+ err_remove_dev_removable:
+ device_remove_file(dev, &dev_attr_removable);
err_remove_dev_waiting_for_supplier:
device_remove_file(dev, &dev_attr_waiting_for_supplier);
err_remove_dev_online:
@@ -2672,6 +2682,7 @@ static void device_remove_attrs(struct device *dev)
struct class *class = dev->class;
const struct device_type *type = dev->type;
+ device_remove_group(dev, &dev_attr_physical_location_group);
device_remove_file(dev, &dev_attr_removable);
device_remove_file(dev, &dev_attr_waiting_for_supplier);
device_remove_file(dev, &dev_attr_online);
diff --git a/drivers/base/physical_location.c b/drivers/base/physical_location.c
new file mode 100644
index 000000000000..4c1a52ecd7f6
--- /dev/null
+++ b/drivers/base/physical_location.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device physical location support
+ *
+ * Author: Won Chung <[email protected]>
+ */
+
+#include <linux/acpi.h>
+#include <linux/sysfs.h>
+
+#include "physical_location.h"
+
+bool dev_add_physical_location(struct device *dev)
+{
+ struct acpi_pld_info *pld;
+ acpi_status status;
+
+ if (!has_acpi_companion(dev))
+ return false;
+
+ status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ dev->physical_location =
+ kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
+ dev->physical_location->panel = pld->panel;
+ dev->physical_location->vertical_position = pld->vertical_position;
+ dev->physical_location->horizontal_position = pld->horizontal_position;
+ dev->physical_location->dock = pld->dock;
+ dev->physical_location->lid = pld->lid;
+
+ return true;
+}
+
+static ssize_t panel_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ const char *panel;
+
+ switch (dev->physical_location->panel) {
+ case DEVICE_PANEL_TOP:
+ panel = "top";
+ break;
+ case DEVICE_PANEL_BOTTOM:
+ panel = "bottom";
+ break;
+ case DEVICE_PANEL_LEFT:
+ panel = "left";
+ break;
+ case DEVICE_PANEL_RIGHT:
+ panel = "right";
+ break;
+ case DEVICE_PANEL_FRONT:
+ panel = "front";
+ break;
+ default:
+ panel = "unknown";
+ }
+ return sysfs_emit(buf, "%s\n", panel);
+}
+static DEVICE_ATTR_RO(panel);
+
+static ssize_t vertical_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const char *vertical_position;
+
+ switch (dev->physical_location->vertical_position) {
+ case DEVICE_VERT_POS_UPPER:
+ vertical_position = "upper";
+ break;
+ case DEVICE_VERT_POS_CENTER:
+ vertical_position = "center";
+ break;
+ case DEVICE_VERT_POS_LOWER:
+ vertical_position = "lower";
+ break;
+ default:
+ vertical_position = "unknown";
+ }
+ return sysfs_emit(buf, "%s\n", vertical_position);
+}
+static DEVICE_ATTR_RO(vertical_position);
+
+static ssize_t horizontal_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const char *horizontal_position;
+
+ switch (dev->physical_location->horizontal_position) {
+ case DEVICE_HORI_POS_LEFT:
+ horizontal_position = "left";
+ break;
+ case DEVICE_HORI_POS_CENTER:
+ horizontal_position = "center";
+ break;
+ case DEVICE_HORI_POS_RIGHT:
+ horizontal_position = "right";
+ break;
+ default:
+ horizontal_position = "unknown";
+ }
+ return sysfs_emit(buf, "%s\n", horizontal_position);
+}
+static DEVICE_ATTR_RO(horizontal_position);
+
+static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n",
+ dev->physical_location->dock ? "yes" : "no");
+}
+static DEVICE_ATTR_RO(dock);
+
+static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n",
+ dev->physical_location->lid ? "yes" : "no");
+}
+static DEVICE_ATTR_RO(lid);
+
+static struct attribute *dev_attr_physical_location[] = {
+ &dev_attr_panel.attr,
+ &dev_attr_vertical_position.attr,
+ &dev_attr_horizontal_position.attr,
+ &dev_attr_dock.attr,
+ &dev_attr_lid.attr,
+ NULL,
+};
+
+const struct attribute_group dev_attr_physical_location_group = {
+ .name = "physical_location",
+ .attrs = dev_attr_physical_location,
+};
+
diff --git a/drivers/base/physical_location.h b/drivers/base/physical_location.h
new file mode 100644
index 000000000000..82cde9f1b161
--- /dev/null
+++ b/drivers/base/physical_location.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device physical location support
+ *
+ * Author: Won Chung <[email protected]>
+ */
+
+#include <linux/device.h>
+
+#ifdef CONFIG_ACPI
+extern bool dev_add_physical_location(struct device *dev);
+extern const struct attribute_group dev_attr_physical_location_group;
+#else
+static inline bool dev_add_physical_location(struct device *dev) { return false; };
+static const struct attribute_group dev_attr_physical_location_group = {};
+#endif
diff --git a/include/linux/device.h b/include/linux/device.h
index 93459724dcde..766fbea6ca83 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -386,6 +386,75 @@ struct dev_msi_info {
#endif
};
+/**
+ * enum device_physical_location_panel - Describes which panel surface of the
+ * system's housing the device connection point resides on.
+ * @DEVICE_PANEL_TOP: Device connection point is on the top panel.
+ * @DEVICE_PANEL_BOTTOM: Device connection point is on the bottom panel.
+ * @DEVICE_PANEL_LEFT: Device connection point is on the left panel.
+ * @DEVICE_PANEL_RIGHT: Device connection point is on the right panel.
+ * @DEVICE_PANEL_FRONT: Device connection point is on the front panel.
+ * @DEVICE_PANEL_BACK: Device connection point is on the back panel.
+ * @DEVICE_PANEL_UNKNOWN: The panel with device connection point is unknown.
+ */
+enum device_physical_location_panel {
+ DEVICE_PANEL_TOP,
+ DEVICE_PANEL_BOTTOM,
+ DEVICE_PANEL_LEFT,
+ DEVICE_PANEL_RIGHT,
+ DEVICE_PANEL_FRONT,
+ DEVICE_PANEL_BACK,
+ DEVICE_PANEL_UNKNOWN,
+};
+
+/**
+ * enum device_physical_location_vertical_position - Describes vertical
+ * position of the device connection point on the panel surface.
+ * @DEVICE_VERT_POS_UPPER: Device connection point is at upper part of panel.
+ * @DEVICE_VERT_POS_CENTER: Device connection point is at center part of panel.
+ * @DEVICE_VERT_POS_LOWER: Device connection point is at lower part of panel.
+ */
+enum device_physical_location_vertical_position {
+ DEVICE_VERT_POS_UPPER,
+ DEVICE_VERT_POS_CENTER,
+ DEVICE_VERT_POS_LOWER,
+};
+
+/**
+ * enum device_physical_location_horizontal_position - Describes horizontal
+ * position of the device connection point on the panel surface.
+ * @DEVICE_HORI_POS_LEFT: Device connection point is at left part of panel.
+ * @DEVICE_HORI_POS_CENTER: Device connection point is at center part of panel.
+ * @DEVICE_HORI_POS_RIGHT: Device connection point is at right part of panel.
+ */
+enum device_physical_location_horizontal_position {
+ DEVICE_HORI_POS_LEFT,
+ DEVICE_HORI_POS_CENTER,
+ DEVICE_HORI_POS_RIGHT,
+};
+
+/**
+ * struct device_physical_location - Device data related to physical location
+ * of the device connection point.
+ * @panel: Panel surface of the system's housing that the device connection
+ * point resides on.
+ * @vertical_position: Vertical position of the device connection point within
+ * the panel.
+ * @horizontal_position: Horizontal position of the device connection point
+ * within the panel.
+ * @dock: Set if the device connection point resides in a docking station or
+ * port replicator.
+ * @lid: Set if this device connection point resides on the lid of laptop
+ * system.
+ */
+struct device_physical_location {
+ enum device_physical_location_panel panel;
+ enum device_physical_location_vertical_position vertical_position;
+ enum device_physical_location_horizontal_position horizontal_position;
+ bool dock;
+ bool lid;
+};
+
/**
* struct device - The basic device structure
* @parent: The device's "parent" device, the device to which it is attached.
@@ -453,6 +522,8 @@ struct dev_msi_info {
* device (i.e. the bus driver that discovered the device).
* @iommu_group: IOMMU group the device belongs to.
* @iommu: Per device generic IOMMU runtime data
+ * @physical_location: Describes physical location of the device connection
+ * point in the system housing.
* @removable: Whether the device can be removed from the system. This
* should be set by the subsystem / bus driver that discovered
* the device.
@@ -567,6 +638,8 @@ struct device {
struct iommu_group *iommu_group;
struct dev_iommu *iommu;
+ struct device_physical_location *physical_location;
+
enum device_removable removable;
bool offline_disabled:1;
--
2.35.1.723.g4982287a31-goog
Greeting,
FYI, we noticed the following commit (built with gcc-9):
commit: 0f629466144d6d8ec3ffe9639382f19c428a7039 ("[PATCH v5] driver core: Add sysfs support for physical location of a device")
url: https://github.com/0day-ci/linux/commits/Won-Chung/driver-core-Add-sysfs-support-for-physical-location-of-a-device/20220311-052431
base: https://git.kernel.org/cgit/linux/kernel/git/gregkh/driver-core.git 4a248f85b3dd8e010ff8335755c927130e9b0764
patch link: https://lore.kernel.org/lkml/[email protected]
in testcase: xfstests
version: xfstests-x86_64-1de1db8-1_20220217
with following parameters:
disk: 4HDD
fs: xfs
test: xfs-reflink-16
ucode: 0x28
test-description: xfstests is a regression test suite for xfs and other files ystems.
test-url: git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git
on test machine: 8 threads 1 sockets Intel(R) Core(TM) i7-4790 v3 @ 3.60GHz with 6G memory
caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):
If you fix the issue, kindly add following tag
Reported-by: kernel test robot <[email protected]>
[ 3.954010][ T1] WARNING: CPU: 1 PID: 1 at fs/sysfs/group.c:278 sysfs_remove_group (fs/sysfs/group.c:278 fs/sysfs/group.c:269)
[ 3.962886][ T1] Modules linked in:
[ 3.966664][ T1] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.17.0-rc6-00042-g0f629466144d #1
[ 3.975367][ T1] Hardware name: Dell Inc. OptiPlex 9020/03CPWF, BIOS A11 04/01/2015
[ 3.983288][ T1] RIP: 0010:sysfs_remove_group (fs/sysfs/group.c:278 fs/sysfs/group.c:269)
[ 3.988963][ T1] Code: 48 89 d9 49 8b 14 24 48 b8 00 00 00 00 00 fc ff df 48 c1 e9 03 80 3c 01 00 75 48 48 8b 33 48 c7 c7 e0 df b7 83 e8 cc 74 8c 01 <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 e8 15 3f d1 ff e9 02 ff ff ff 48
All code
========
0: 48 89 d9 mov %rbx,%rcx
3: 49 8b 14 24 mov (%r12),%rdx
7: 48 b8 00 00 00 00 00 movabs $0xdffffc0000000000,%rax
e: fc ff df
11: 48 c1 e9 03 shr $0x3,%rcx
15: 80 3c 01 00 cmpb $0x0,(%rcx,%rax,1)
19: 75 48 jne 0x63
1b: 48 8b 33 mov (%rbx),%rsi
1e: 48 c7 c7 e0 df b7 83 mov $0xffffffff83b7dfe0,%rdi
25: e8 cc 74 8c 01 callq 0x18c74f6
2a:* 0f 0b ud2 <-- trapping instruction
2c: 48 83 c4 08 add $0x8,%rsp
30: 5b pop %rbx
31: 5d pop %rbp
32: 41 5c pop %r12
34: c3 retq
35: e8 15 3f d1 ff callq 0xffffffffffd13f4f
3a: e9 02 ff ff ff jmpq 0xffffffffffffff41
3f: 48 rex.W
Code starting with the faulting instruction
===========================================
0: 0f 0b ud2
2: 48 83 c4 08 add $0x8,%rsp
6: 5b pop %rbx
7: 5d pop %rbp
8: 41 5c pop %r12
a: c3 retq
b: e8 15 3f d1 ff callq 0xffffffffffd13f25
10: e9 02 ff ff ff jmpq 0xffffffffffffff17
15: 48 rex.W
[ 4.008355][ T1] RSP: 0000:ffffc900000378d8 EFLAGS: 00010286
[ 4.014290][ T1] RAX: 0000000000000000 RBX: ffffffff83cff1c0 RCX: 0000000000000000
[ 4.022127][ T1] RDX: c0000000ffff7fff RSI: ffffc900000375f8 RDI: fffff52000006f0d
[ 4.029964][ T1] RBP: 0000000000000000 R08: 0000000000000000 R09: fffff52000006ea9
[ 4.037803][ T1] R10: ffffc90000037547 R11: fffff52000006ea8 R12: ffff888100eb4000
[ 4.045638][ T1] R13: ffff888100eb4000 R14: dffffc0000000000 R15: ffff888100eb4048
[ 4.053474][ T1] FS: 0000000000000000(0000) GS:ffff888138c80000(0000) knlGS:0000000000000000
[ 4.062263][ T1] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 4.068711][ T1] CR2: 0000000000000000 CR3: 000000019ce0e001 CR4: 00000000001706e0
[ 4.076551][ T1] Call Trace:
[ 4.079727][ T1] <TASK>
[ 4.082557][ T1] sysfs_remove_groups (fs/sysfs/group.c:311 fs/sysfs/group.c:304)
[ 4.087371][ T1] device_remove_attrs (drivers/base/core.c:2786 drivers/base/core.c:2686)
[ 4.092262][ T1] ? device_remove_file (drivers/base/core.c:2681)
[ 4.097163][ T1] ? up_write (arch/x86/include/asm/atomic64_64.h:172 include/linux/atomic/atomic-long.h:95 include/linux/atomic/atomic-instrumented.h:1348 kernel/locking/rwsem.c:1318 kernel/locking/rwsem.c:1567)
[ 4.101193][ T1] ? kernfs_remove_by_name_ns (fs/kernfs/dir.c:1579)
[ 4.106695][ T1] device_del (drivers/base/core.c:3603)
[ 4.110916][ T1] ? __device_link_del (drivers/base/core.c:3559)
[ 4.115911][ T1] ? rcu_gp_is_expedited (arch/x86/include/asm/atomic.h:29 include/linux/atomic/atomic-instrumented.h:28 kernel/rcu/update.c:158)
[ 4.120907][ T1] device_unregister (drivers/base/core.c:3522 drivers/base/core.c:3636)
[ 4.125539][ T1] wakeup_source_unregister (drivers/base/power/wakeup.c:253)
[ 4.132839][ T1] device_wakeup_enable (drivers/base/power/wakeup.c:322 drivers/base/power/wakeup.c:352)
[ 4.137913][ T1] acpi_button_add (drivers/acpi/button.c:571)
[ 4.142545][ T1] acpi_device_probe (drivers/acpi/bus.c:994)
[ 4.147265][ T1] really_probe (drivers/base/dd.c:751)
[ 4.152252][ T1] __driver_probe_device (drivers/base/dd.c:755)
[ 4.157410][ T1] driver_probe_device (drivers/base/dd.c:785)
[ 4.162299][ T1] __driver_attach (drivers/base/dd.c:1145)
[ 4.166939][ T1] ? __device_attach_driver (drivers/base/dd.c:1097)
[ 4.172354][ T1] bus_for_each_dev (drivers/base/bus.c:301)
[ 4.177081][ T1] ? _raw_spin_lock_bh (kernel/locking/spinlock.c:153)
[ 4.182059][ T1] ? subsys_dev_iter_exit (drivers/base/bus.c:290)
[ 4.187118][ T1] ? klist_node_init (arch/x86/include/asm/atomic.h:41 include/linux/atomic/atomic-instrumented.h:42 include/linux/refcount.h:136 include/linux/kref.h:31 lib/klist.c:111)
[ 4.191846][ T1] bus_add_driver (drivers/base/bus.c:619)
[ 4.196389][ T1] driver_register (drivers/base/driver.c:171)
[ 4.201021][ T1] ? dmi_first_match (drivers/firmware/dmi_scan.c:921)
[ 4.205654][ T1] ? acpi_ac_init (drivers/acpi/button.c:658)
[ 4.210036][ T1] do_one_initcall (init/main.c:1300)
[ 4.214591][ T1] ? trace_event_raw_event_initcall_level (init/main.c:1291)
[ 4.221212][ T1] ? parameq (kernel/params.c:170)
[ 4.225322][ T1] ? kasan_unpoison (mm/kasan/shadow.c:108 mm/kasan/shadow.c:142)
[ 4.229886][ T1] ? __kasan_slab_alloc (mm/kasan/common.c:431 mm/kasan/common.c:469)
[ 4.234784][ T1] kernel_init_freeable (init/main.c:1372 init/main.c:1389 init/main.c:1408 init/main.c:1613)
[ 4.239878][ T1] ? console_on_rootfs (init/main.c:1584)
[ 4.244693][ T1] ? _raw_spin_lock_irq (arch/x86/include/asm/atomic.h:202 include/linux/atomic/atomic-instrumented.h:543 include/asm-generic/qspinlock.h:82 include/linux/spinlock.h:185 include/linux/spinlock_api_smp.h:120 kernel/locking/spinlock.c:170)
[ 4.249584][ T1] ? _raw_spin_lock (kernel/locking/spinlock.c:169)
[ 4.254299][ T1] ? rest_init (init/main.c:1494)
[ 4.258597][ T1] kernel_init (init/main.c:1504)
[ 4.262806][ T1] ret_from_fork (arch/x86/entry/entry_64.S:301)
[ 4.267091][ T1] </TASK>
[ 4.270008][ T1] ---[ end trace 0000000000000000 ]---
[ 4.275431][ T1] ACPI: button: Power Button [PWRB]
[ 4.280738][ T1] input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input1
[ 4.288963][ T1] ------------[ cut here ]------------
[ 4.294284][ T1] sysfs group 'physical_location' not found for kobject 'wakeup17'
To reproduce:
git clone https://github.com/intel/lkp-tests.git
cd lkp-tests
sudo bin/lkp install job.yaml # job file is attached in this email
bin/lkp split-job --compatible job.yaml # generate the yaml file for lkp run
sudo bin/lkp run generated-yaml-file
# if come across any failure that blocks the test,
# please remove ~/.lkp and /lkp dir to run from a clean state.
---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/[email protected]
Thanks,
Oliver Sang