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

Configure Feed

Select the types of activity you want to include in your feed.

platform/x86: thinkpad_acpi: Add sysfs to display details of damaged device.

Add new sysfs interface to identify the impacted component with location of
device.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Nitin Joshi <nitjoshi@gmail.com>
Link: https://patch.msgid.link/20260106174519.6402-2-nitjoshi@gmail.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Nitin Joshi and committed by
Ilpo Järvinen
a85503d5 28c43bdd

+118 -3
+16 -1
Documentation/admin-guide/laptops/thinkpad-acpi.rst
··· 1580 1580 Hardware damage detection capability 1581 1581 ------------------------------------ 1582 1582 1583 - sysfs attributes: hwdd_status 1583 + sysfs attributes: hwdd_status, hwdd_detail 1584 1584 1585 1585 Thinkpads are adding the ability to detect and report hardware damage. 1586 1586 Add new sysfs interface to identify the damaged device status. ··· 1594 1594 1595 1595 - 0 = Not Damaged 1596 1596 - 1 = Damaged 1597 + 1598 + The command to check location of damaged device is:: 1599 + 1600 + cat /sys/devices/platform/thinkpad_acpi/hwdd_detail 1601 + 1602 + This value displays location of damaged device having 1 line per damaged "item". 1603 + For example: 1604 + 1605 + if no damage is detected: 1606 + 1607 + - No damage detected 1608 + 1609 + if damage detected: 1610 + 1611 + - TYPE-C: Base, Right side, Center port 1597 1612 1598 1613 The property is read-only. If feature is not supported then sysfs 1599 1614 attribute is not created.
+102 -2
drivers/platform/x86/lenovo/thinkpad_acpi.c
··· 11090 11090 #define HWDD_NOT_SUPPORTED BIT(31) 11091 11091 #define HWDD_SUPPORT_USBC BIT(0) 11092 11092 11093 - #define PORT_STATUS GENMASK(7, 4) 11094 - #define NUM_PORTS 4 11093 + #define PORT_STATUS GENMASK(7, 4) 11094 + #define LID_STATUS GENMASK(11, 8) 11095 + #define BASE_STATUS GENMASK(15, 12) 11096 + #define POS_STATUS GENMASK(3, 2) 11097 + #define PANEL_STATUS GENMASK(1, 0) 11098 + 11099 + #define PORT_DETAIL_OFFSET 16 11100 + 11101 + #define PANEL_TOP 0 11102 + #define PANEL_BASE 1 11103 + #define PANEL_LEFT 2 11104 + #define PANEL_RIGHT 3 11105 + 11106 + #define POS_LEFT 0 11107 + #define POS_CENTER 1 11108 + #define POS_RIGHT 2 11109 + 11110 + #define NUM_PORTS 4 11095 11111 11096 11112 static bool hwdd_support_available; 11097 11113 static bool ucdd_supported; ··· 11123 11107 return -EIO; 11124 11108 11125 11109 return 0; 11110 + } 11111 + 11112 + static bool display_damage(char *buf, int *count, char *type, unsigned int dmg_status) 11113 + { 11114 + unsigned char lid_status, base_status, port_status; 11115 + unsigned char loc_status, pos_status, panel_status; 11116 + bool damage_detected = false; 11117 + int i; 11118 + 11119 + port_status = FIELD_GET(PORT_STATUS, dmg_status); 11120 + lid_status = FIELD_GET(LID_STATUS, dmg_status); 11121 + base_status = FIELD_GET(BASE_STATUS, dmg_status); 11122 + for (i = 0; i < NUM_PORTS; i++) { 11123 + if (!(dmg_status & BIT(i)) || !(port_status & BIT(i))) 11124 + continue; 11125 + 11126 + *count += sysfs_emit_at(buf, *count, "%s: ", type); 11127 + loc_status = (dmg_status >> (PORT_DETAIL_OFFSET + (4 * i))) & 0xF; 11128 + pos_status = FIELD_GET(POS_STATUS, loc_status); 11129 + panel_status = FIELD_GET(PANEL_STATUS, loc_status); 11130 + 11131 + if (lid_status & BIT(i)) 11132 + *count += sysfs_emit_at(buf, *count, "Lid, "); 11133 + if (base_status & BIT(i)) 11134 + *count += sysfs_emit_at(buf, *count, "Base, "); 11135 + 11136 + switch (pos_status) { 11137 + case PANEL_TOP: 11138 + *count += sysfs_emit_at(buf, *count, "Top, "); 11139 + break; 11140 + case PANEL_BASE: 11141 + *count += sysfs_emit_at(buf, *count, "Bottom, "); 11142 + break; 11143 + case PANEL_LEFT: 11144 + *count += sysfs_emit_at(buf, *count, "Left, "); 11145 + break; 11146 + case PANEL_RIGHT: 11147 + *count += sysfs_emit_at(buf, *count, "Right, "); 11148 + break; 11149 + default: 11150 + pr_err("Unexpected value %d in switch statement\n", pos_status); 11151 + } 11152 + 11153 + switch (panel_status) { 11154 + case POS_LEFT: 11155 + *count += sysfs_emit_at(buf, *count, "Left port\n"); 11156 + break; 11157 + case POS_CENTER: 11158 + *count += sysfs_emit_at(buf, *count, "Center port\n"); 11159 + break; 11160 + case POS_RIGHT: 11161 + *count += sysfs_emit_at(buf, *count, "Right port\n"); 11162 + break; 11163 + default: 11164 + *count += sysfs_emit_at(buf, *count, "Undefined\n"); 11165 + break; 11166 + } 11167 + damage_detected = true; 11168 + } 11169 + return damage_detected; 11170 + } 11171 + 11172 + /* sysfs type-c damage detection detail */ 11173 + static ssize_t hwdd_detail_show(struct device *dev, 11174 + struct device_attribute *attr, 11175 + char *buf) 11176 + { 11177 + unsigned int damage_status; 11178 + int err, count = 0; 11179 + 11180 + if (!ucdd_supported) 11181 + return -ENODEV; 11182 + 11183 + /* Get USB TYPE-C damage status */ 11184 + err = hwdd_command(HWDD_GET_DMG_USBC, &damage_status); 11185 + if (err) 11186 + return err; 11187 + 11188 + if (!display_damage(buf, &count, "Type-C", damage_status)) 11189 + count += sysfs_emit_at(buf, count, "No damage detected\n"); 11190 + 11191 + return count; 11126 11192 } 11127 11193 11128 11194 /* sysfs type-c damage detection capability */ ··· 11234 11136 return sysfs_emit(buf, "0\n"); 11235 11137 } 11236 11138 static DEVICE_ATTR_RO(hwdd_status); 11139 + static DEVICE_ATTR_RO(hwdd_detail); 11237 11140 11238 11141 static struct attribute *hwdd_attributes[] = { 11239 11142 &dev_attr_hwdd_status.attr, 11143 + &dev_attr_hwdd_detail.attr, 11240 11144 NULL 11241 11145 }; 11242 11146