Unverified Commit a85503d5 authored by Nitin Joshi's avatar Nitin Joshi Committed by Ilpo Järvinen
Browse files

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: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: default avatarNitin Joshi <nitjoshi@gmail.com>
Link: https://patch.msgid.link/20260106174519.6402-2-nitjoshi@gmail.com


Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent 28c43bdd
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -1580,7 +1580,7 @@ Documentation/ABI/testing/sysfs-class-power.
Hardware damage detection capability
------------------------------------

sysfs attributes: hwdd_status
sysfs attributes: hwdd_status, hwdd_detail

Thinkpads are adding the ability to detect and report hardware damage.
Add new sysfs interface to identify the damaged device status.
@@ -1595,6 +1595,21 @@ This value displays status of device damaged.
- 0 = Not Damaged
- 1 = Damaged

The command to check location of damaged device is::

        cat /sys/devices/platform/thinkpad_acpi/hwdd_detail

This value displays location of damaged device having 1 line per damaged "item".
For example:

if no damage is detected:

- No damage detected

if damage detected:

- TYPE-C: Base, Right side, Center port

The property is read-only. If feature is not supported then sysfs
attribute is not created.

+102 −2
Original line number Diff line number Diff line
@@ -11091,6 +11091,22 @@ static const struct attribute_group auxmac_attr_group = {
#define HWDD_SUPPORT_USBC	BIT(0)

#define PORT_STATUS     GENMASK(7, 4)
#define LID_STATUS      GENMASK(11, 8)
#define BASE_STATUS     GENMASK(15, 12)
#define POS_STATUS      GENMASK(3, 2)
#define PANEL_STATUS    GENMASK(1, 0)

#define PORT_DETAIL_OFFSET	16

#define PANEL_TOP	0
#define PANEL_BASE	1
#define PANEL_LEFT	2
#define PANEL_RIGHT	3

#define POS_LEFT	0
#define POS_CENTER	1
#define POS_RIGHT	2

#define NUM_PORTS	4

static bool hwdd_support_available;
@@ -11109,6 +11125,88 @@ static int hwdd_command(int command, int *output)
	return 0;
}

static bool display_damage(char *buf, int *count, char *type, unsigned int dmg_status)
{
	unsigned char lid_status, base_status, port_status;
	unsigned char loc_status, pos_status, panel_status;
	bool damage_detected = false;
	int i;

	port_status = FIELD_GET(PORT_STATUS, dmg_status);
	lid_status = FIELD_GET(LID_STATUS, dmg_status);
	base_status = FIELD_GET(BASE_STATUS, dmg_status);
	for (i = 0; i < NUM_PORTS; i++) {
		if (!(dmg_status & BIT(i)) || !(port_status & BIT(i)))
			continue;

		*count += sysfs_emit_at(buf, *count, "%s: ", type);
		loc_status = (dmg_status >> (PORT_DETAIL_OFFSET + (4 * i))) & 0xF;
		pos_status = FIELD_GET(POS_STATUS, loc_status);
		panel_status = FIELD_GET(PANEL_STATUS, loc_status);

		if (lid_status & BIT(i))
			*count += sysfs_emit_at(buf, *count, "Lid, ");
		if (base_status & BIT(i))
			*count += sysfs_emit_at(buf, *count, "Base, ");

		switch (pos_status) {
		case PANEL_TOP:
			*count += sysfs_emit_at(buf, *count, "Top, ");
			break;
		case PANEL_BASE:
			*count += sysfs_emit_at(buf, *count, "Bottom, ");
			break;
		case PANEL_LEFT:
			*count += sysfs_emit_at(buf, *count, "Left, ");
			break;
		case PANEL_RIGHT:
			*count += sysfs_emit_at(buf, *count, "Right, ");
			break;
		default:
			pr_err("Unexpected value %d in switch statement\n", pos_status);
		}

		switch (panel_status) {
		case POS_LEFT:
			*count += sysfs_emit_at(buf, *count, "Left port\n");
			break;
		case POS_CENTER:
			*count += sysfs_emit_at(buf, *count, "Center port\n");
			break;
		case POS_RIGHT:
			*count += sysfs_emit_at(buf, *count, "Right port\n");
			break;
		default:
			*count += sysfs_emit_at(buf, *count, "Undefined\n");
			break;
		}
		damage_detected = true;
	}
	return damage_detected;
}

/* sysfs type-c damage detection detail */
static ssize_t hwdd_detail_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	unsigned int damage_status;
	int err, count = 0;

	if (!ucdd_supported)
		return -ENODEV;

	/* Get USB TYPE-C damage status */
	err = hwdd_command(HWDD_GET_DMG_USBC, &damage_status);
	if (err)
		return err;

	if (!display_damage(buf, &count, "Type-C", damage_status))
		count += sysfs_emit_at(buf, count, "No damage detected\n");

	return count;
}

/* sysfs type-c damage detection capability */
static ssize_t hwdd_status_show(struct device *dev,
				struct device_attribute *attr,
@@ -11136,9 +11234,11 @@ static ssize_t hwdd_status_show(struct device *dev,
	return sysfs_emit(buf, "0\n");
}
static DEVICE_ATTR_RO(hwdd_status);
static DEVICE_ATTR_RO(hwdd_detail);

static struct attribute *hwdd_attributes[] = {
	&dev_attr_hwdd_status.attr,
	&dev_attr_hwdd_detail.attr,
	NULL
};