public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/9] platform/wmi: Introduce marshalling support
@ 2026-01-09 21:46 Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 1/9] " Armin Wolf
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

The Windows WMI-ACPI driver likely uses wmilib [1] to interact with
the WMI service in userspace. Said library uses plain byte buffers
for exchanging data, so the WMI-ACPI driver has to convert between
those byte buffers and ACPI objects returned by the ACPI firmware.

The format of the byte buffer is publicly documented [2], and after
some reverse eingineering of the WMI-ACPI driver using a set of custom
ACPI tables, the following conversion rules have been discovered:

- ACPI integers are always converted into a uint32
- ACPI strings are converted into special WMI strings
- ACPI buffers are copied as-is
- ACPI packages are unpacked

Extending the ACPI-WMI to perform this kind of marshalling for WMI
data blocks, methods and events would give us a number of benefits:

- WMI drivers are not restricted to a fixed set of supported ACPI data
  types anymore, see dell-wmi-aio (integer vs buffer) and
  hp-wmi-sensors (string vs buffer)

- correct marshalling of WMI strings when data blocks are marked
  as requiring ACPI strings instead of ACPI buffers

- development of WMI drivers without having to understand ACPI

This eventually should result in better compatibility with some
ACPI firmware implementations and in simpler WMI drivers. 

The first patch extends the WMI driver core to perform said
marshalling as well as a new API not based on ACPI objects. The next
patch adds a KUnit test for testing the marshalling code. The
following two patches then add a set of helper functions for dealing
with WMI string data together with another KUnit test.

The remaining patches then convert some simple WMI drivers to use the
new WMI API and update the driver development guide so that new WMI
drivers stop using the ACPI-based API.

The series has been tested on multiple machines, with the xiaomi-wmi
and intel-wmi-sbl-fw-update being tested using a set of custom ACPI
tables loaded over configFS.

[1] https://learn.microsoft.com/de-de/windows-hardware/drivers/ddi/wmilib/

Changes since v2:
- assert that kmallloc aligns buffer on a 8 byte boundary
- add missing includes
- fix some code style issues

Changes since v1:
- fix spelling issues inside the documentation
- add Reviewed-by tag for the documentation

Armin Wolf (9):
  platform/wmi: Introduce marshalling support
  platform/wmi: Add kunit test for the marshalling code
  platform/wmi: Add helper functions for WMI string conversions
  platform/wmi: Add kunit test for the string conversion code
  platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API
  platform/x86/intel/wmi: thunderbolt: Use new buffer-based WMI API
  platform/x86: xiaomi-wmi: Use new buffer-based WMI API
  platform/x86: wmi-bmof: Use new buffer-based WMI API
  platform/wmi: Update driver development guide

 Documentation/driver-api/wmi.rst              |   3 +
 Documentation/wmi/acpi-interface.rst          |  68 +++
 .../wmi/driver-development-guide.rst          |  76 ++-
 drivers/platform/wmi/Kconfig                  |   3 +
 drivers/platform/wmi/Makefile                 |   5 +-
 drivers/platform/wmi/core.c                   | 160 ++++++-
 drivers/platform/wmi/internal.h               |  17 +
 drivers/platform/wmi/marshalling.c            | 241 ++++++++++
 drivers/platform/wmi/string.c                 |  92 ++++
 drivers/platform/wmi/tests/Kconfig            |  27 ++
 drivers/platform/wmi/tests/Makefile           |  11 +
 .../platform/wmi/tests/marshalling_kunit.c    | 449 ++++++++++++++++++
 drivers/platform/wmi/tests/string_kunit.c     | 278 +++++++++++
 .../platform/x86/intel/wmi/sbl-fw-update.c    |  43 +-
 drivers/platform/x86/intel/wmi/thunderbolt.c  |  26 +-
 drivers/platform/x86/wmi-bmof.c               |  34 +-
 drivers/platform/x86/xiaomi-wmi.c             |   5 +-
 include/linux/wmi.h                           |  45 +-
 18 files changed, 1491 insertions(+), 92 deletions(-)
 create mode 100644 drivers/platform/wmi/internal.h
 create mode 100644 drivers/platform/wmi/marshalling.c
 create mode 100644 drivers/platform/wmi/string.c
 create mode 100644 drivers/platform/wmi/tests/Kconfig
 create mode 100644 drivers/platform/wmi/tests/Makefile
 create mode 100644 drivers/platform/wmi/tests/marshalling_kunit.c
 create mode 100644 drivers/platform/wmi/tests/string_kunit.c

-- 
2.39.5


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v3 1/9] platform/wmi: Introduce marshalling support
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 2/9] platform/wmi: Add kunit test for the marshalling code Armin Wolf
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

The Windows WMI-ACPI driver likely uses wmilib [1] to interact with
the WMI service in userspace. Said library uses plain byte buffers
for exchanging data, so the WMI-ACPI driver has to convert between
those byte buffers and ACPI objects returned by the ACPI firmware.

The format of the byte buffer is publicly documented [2], and after
some reverse eingineering of the WMI-ACPI driver using a set of custom
ACPI tables, the following conversion rules have been discovered:

- ACPI integers are always converted into a uint32
- ACPI strings are converted into special WMI strings
- ACPI buffers are copied as-is
- ACPI packages are unpacked

Extend the ACPI-WMI driver to also perform this kind of marshalling
for WMI data blocks, methods and events. Doing so gives us a number
of benefits:

- WMI drivers are not restricted to a fixed set of supported ACPI data
  types anymore, see dell-wmi-aio (integer vs buffer) and
  hp-wmi-sensors (string vs buffer)

- correct marshalling of WMI strings when data blocks are marked
  as requiring ACPI strings instead of ACPI buffers

- development of WMI drivers without having to understand ACPI

This eventually should result in better compatibility with some
ACPI firmware implementations and in simpler WMI drivers. There are
however some differences between the original Windows driver and
the ACPI-WMI driver when it comes to ACPI object conversions:

- the Windows driver copies internal _ACPI_METHOD_ARGUMENT_V1 data
  structures into the output buffer when encountering nested ACPI
  packages. This is very likely an error inside the driver itself, so
  we do not support nested ACPI packages.

- when converting WMI strings (UTF-16LE) into ACPI strings (ASCII),
  the Windows driver replaces non-ascii characters (ä -> a, & -> ?)
  instead of returning an error. This behavior is not documented
  anywhere and might lead to severe errors in some cases (like
  setting BIOS passwords over WMI), so we simply return an error.

As the current bus-based WMI API is based on ACPI buffers, a new
API is necessary. The legacy GUID-based WMI API is not extended to
support marshalling, as WMI drivers using said API are expected to
move to the bus-based WMI API in the future.

[1] https://learn.microsoft.com/de-de/windows-hardware/drivers/ddi/wmilib/
[2] https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/
    driver-defined-wmi-data-items

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/wmi/Makefile      |   2 +-
 drivers/platform/wmi/core.c        | 160 ++++++++++++++++++-
 drivers/platform/wmi/internal.h    |  17 ++
 drivers/platform/wmi/marshalling.c | 241 +++++++++++++++++++++++++++++
 include/linux/wmi.h                |  40 ++++-
 5 files changed, 453 insertions(+), 7 deletions(-)
 create mode 100644 drivers/platform/wmi/internal.h
 create mode 100644 drivers/platform/wmi/marshalling.c

diff --git a/drivers/platform/wmi/Makefile b/drivers/platform/wmi/Makefile
index 98393d7391ec..6f2bf8cc709e 100644
--- a/drivers/platform/wmi/Makefile
+++ b/drivers/platform/wmi/Makefile
@@ -4,5 +4,5 @@
 # ACPI WMI core
 #
 
-wmi-y			:= core.o
+wmi-y			:= core.o marshalling.o
 obj-$(CONFIG_ACPI_WMI)	+= wmi.o
diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c
index 6878c4fcb0b5..1601bf9fe135 100644
--- a/drivers/platform/wmi/core.c
+++ b/drivers/platform/wmi/core.c
@@ -23,6 +23,7 @@
 #include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/limits.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/rwsem.h>
@@ -33,6 +34,8 @@
 #include <linux/wmi.h>
 #include <linux/fs.h>
 
+#include "internal.h"
+
 MODULE_AUTHOR("Carlos Corbacho");
 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
 MODULE_LICENSE("GPL");
@@ -302,7 +305,7 @@ acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method
 EXPORT_SYMBOL_GPL(wmi_evaluate_method);
 
 /**
- * wmidev_evaluate_method - Evaluate a WMI method
+ * wmidev_evaluate_method - Evaluate a WMI method (deprecated)
  * @wdev: A wmi bus device from a driver
  * @instance: Instance index
  * @method_id: Method ID to call
@@ -360,6 +363,70 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met
 }
 EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
 
+/**
+ * wmidev_invoke_method - Invoke a WMI method
+ * @wdev: A wmi bus device from a driver
+ * @instance: Instance index
+ * @method_id: Method ID to call
+ * @in: Mandatory WMI buffer containing input for the method call
+ * @out: Optional WMI buffer to return the method results
+ *
+ * Invoke a WMI method, the caller must free the resulting data inside @out.
+ * Said data is guaranteed to be aligned on a 8-byte boundary.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
+			 const struct wmi_buffer *in, struct wmi_buffer *out)
+{
+	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
+	struct acpi_buffer aout = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer ain;
+	union acpi_object *obj;
+	acpi_status status;
+	int ret;
+
+	if (wblock->gblock.flags & ACPI_WMI_STRING) {
+		ret = wmi_marshal_string(in, &ain);
+		if (ret < 0)
+			return ret;
+	} else {
+		if (in->length > U32_MAX)
+			return -E2BIG;
+
+		ain.length = in->length;
+		ain.pointer = in->data;
+	}
+
+	if (out)
+		status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout);
+	else
+		status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL);
+
+	if (wblock->gblock.flags & ACPI_WMI_STRING)
+		kfree(ain.pointer);
+
+	if (ACPI_FAILURE(status))
+		return -EIO;
+
+	if (!out)
+		return 0;
+
+	obj = aout.pointer;
+	if (!obj) {
+		out->length = 0;
+		out->data = ZERO_SIZE_PTR;
+
+		return 0;
+	}
+
+	ret = wmi_unmarshal_acpi_object(obj, out);
+	kfree(obj);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wmidev_invoke_method);
+
 static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
 				 struct acpi_buffer *out)
 {
@@ -432,7 +499,7 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
 EXPORT_SYMBOL_GPL(wmi_query_block);
 
 /**
- * wmidev_block_query - Return contents of a WMI block
+ * wmidev_block_query - Return contents of a WMI block (deprectated)
  * @wdev: A wmi bus device from a driver
  * @instance: Instance index
  *
@@ -452,6 +519,33 @@ union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)
 }
 EXPORT_SYMBOL_GPL(wmidev_block_query);
 
+/**
+ * wmidev_query_block - Return contents of a WMI data block
+ * @wdev: A wmi bus device from a driver
+ * @instance: Instance index
+ * @out: WMI buffer to fill
+ *
+ * Query a WMI data block, the caller must free the resulting data inside @out.
+ * Said data is guaranteed to be aligned on a 8-byte boundary.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out)
+{
+	union acpi_object *obj;
+	int ret;
+
+	obj = wmidev_block_query(wdev, instance);
+	if (!obj)
+		return -EIO;
+
+	ret = wmi_unmarshal_acpi_object(obj, out);
+	kfree(obj);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wmidev_query_block);
+
 /**
  * wmi_set_block - Write to a WMI block (deprecated)
  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -486,7 +580,7 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acp
 EXPORT_SYMBOL_GPL(wmi_set_block);
 
 /**
- * wmidev_block_set - Write to a WMI block
+ * wmidev_block_set - Write to a WMI block (deprecated)
  * @wdev: A wmi bus device from a driver
  * @instance: Instance index
  * @in: Buffer containing new values for the data block
@@ -535,6 +629,46 @@ acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct
 }
 EXPORT_SYMBOL_GPL(wmidev_block_set);
 
+/**
+ * wmidev_set_block - Write to a WMI data block
+ * @wdev: A wmi bus device from a driver
+ * @instance: Instance index
+ * @in: WMI buffer containing new values for the data block
+ *
+ * Write the content of @in into a WMI data block.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wmidev_set_block(struct wmi_device *wdev, u8 instance, const struct wmi_buffer *in)
+{
+	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
+	struct acpi_buffer buffer;
+	acpi_status status;
+	int ret;
+
+	if (wblock->gblock.flags & ACPI_WMI_STRING) {
+		ret = wmi_marshal_string(in, &buffer);
+		if (ret < 0)
+			return ret;
+	} else {
+		if (in->length > U32_MAX)
+			return -E2BIG;
+
+		buffer.length = in->length;
+		buffer.pointer = in->data;
+	}
+
+	status = wmidev_block_set(wdev, instance, &buffer);
+	if (wblock->gblock.flags & ACPI_WMI_STRING)
+		kfree(buffer.pointer);
+
+	if (ACPI_FAILURE(status))
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wmidev_set_block);
+
 /**
  * wmi_install_notify_handler - Register handler for WMI events (deprecated)
  * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
@@ -862,7 +996,7 @@ static int wmi_dev_probe(struct device *dev)
 		return -ENODEV;
 	}
 
-	if (wdriver->notify) {
+	if (wdriver->notify || wdriver->notify_new) {
 		if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)
 			return -ENODEV;
 	}
@@ -1221,6 +1355,8 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj
 static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
 {
 	struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver);
+	struct wmi_buffer buffer;
+	int ret;
 
 	if (!obj && !driver->no_notify_data) {
 		dev_warn(&wblock->dev.dev, "Event contains no event data\n");
@@ -1229,6 +1365,22 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
 
 	if (driver->notify)
 		driver->notify(&wblock->dev, obj);
+
+	if (driver->notify_new) {
+		if (!obj) {
+			driver->notify_new(&wblock->dev, NULL);
+			return;
+		}
+
+		ret = wmi_unmarshal_acpi_object(obj, &buffer);
+		if (ret < 0) {
+			dev_warn(&wblock->dev.dev, "Failed to unmarshal event data: %d\n", ret);
+			return;
+		}
+
+		driver->notify_new(&wblock->dev, &buffer);
+		kfree(buffer.data);
+	}
 }
 
 static int wmi_notify_device(struct device *dev, void *data)
diff --git a/drivers/platform/wmi/internal.h b/drivers/platform/wmi/internal.h
new file mode 100644
index 000000000000..9a39ffa31ad1
--- /dev/null
+++ b/drivers/platform/wmi/internal.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Internal interfaces used by the WMI core.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#ifndef _WMI_INTERNAL_H_
+#define _WMI_INTERNAL_H_
+
+union acpi_object;
+struct wmi_buffer;
+
+int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer);
+int wmi_marshal_string(const struct wmi_buffer *buffer, struct acpi_buffer *out);
+
+#endif /* _WMI_INTERNAL_H_ */
diff --git a/drivers/platform/wmi/marshalling.c b/drivers/platform/wmi/marshalling.c
new file mode 100644
index 000000000000..ef9fb4ffb15f
--- /dev/null
+++ b/drivers/platform/wmi/marshalling.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ACPI-WMI buffer marshalling.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#include <linux/acpi.h>
+#include <linux/align.h>
+#include <linux/build_bug.h>
+#include <linux/overflow.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
+#include <linux/wmi.h>
+
+#include <kunit/visibility.h>
+
+#include "internal.h"
+
+/*
+ * The WMI buffer data needs to be aligned on a 8 byte boundary to properly
+ * support 64-bit WMI integers.
+ */
+static_assert(ARCH_KMALLOC_MINALIGN >= 8);
+
+static int wmi_adjust_buffer_length(size_t *length, const union acpi_object *obj)
+{
+	size_t alignment, size;
+
+	switch (obj->type) {
+	case ACPI_TYPE_INTEGER:
+		/*
+		 * Integers are threated as 32 bit even if the ACPI DSDT
+		 * declares 64 bit integer width.
+		 */
+		alignment = 4;
+		size = sizeof(u32);
+		break;
+	case ACPI_TYPE_STRING:
+		/*
+		 * Strings begin with a single little-endian 16-bit field containing
+		 * the string length in bytes and are encoded as UTF-16LE with a terminating
+		 * nul character.
+		 */
+		if (obj->string.length + 1 > U16_MAX / 2)
+			return -EOVERFLOW;
+
+		alignment = 2;
+		size = struct_size_t(struct wmi_string, chars, obj->string.length + 1);
+		break;
+	case ACPI_TYPE_BUFFER:
+		/*
+		 * Buffers are copied as-is.
+		 */
+		alignment = 1;
+		size = obj->buffer.length;
+		break;
+	default:
+		return -EPROTO;
+	}
+
+	*length = size_add(ALIGN(*length, alignment), size);
+
+	return 0;
+}
+
+static int wmi_obj_get_buffer_length(const union acpi_object *obj, size_t *length)
+{
+	size_t total = 0;
+	int ret;
+
+	if (obj->type == ACPI_TYPE_PACKAGE) {
+		for (int i = 0; i < obj->package.count; i++) {
+			ret = wmi_adjust_buffer_length(&total, &obj->package.elements[i]);
+			if (ret < 0)
+				return ret;
+		}
+	} else {
+		ret = wmi_adjust_buffer_length(&total, obj);
+		if (ret < 0)
+			return ret;
+	}
+
+	*length = total;
+
+	return 0;
+}
+
+static int wmi_obj_transform_simple(const union acpi_object *obj, u8 *buffer, size_t *consumed)
+{
+	struct wmi_string *string;
+	size_t length;
+	__le32 value;
+	u8 *aligned;
+
+	switch (obj->type) {
+	case ACPI_TYPE_INTEGER:
+		aligned = PTR_ALIGN(buffer, 4);
+		length = sizeof(value);
+
+		value = cpu_to_le32(obj->integer.value);
+		memcpy(aligned, &value, length);
+		break;
+	case ACPI_TYPE_STRING:
+		aligned = PTR_ALIGN(buffer, 2);
+		string = (struct wmi_string *)aligned;
+		length = struct_size(string, chars, obj->string.length + 1);
+
+		/* We do not have to worry about unaligned accesses here as the WMI
+		 * string will already be aligned on a two-byte boundary.
+		 */
+		string->length = cpu_to_le16((obj->string.length + 1) * 2);
+		for (int i = 0; i < obj->string.length; i++)
+			string->chars[i] = cpu_to_le16(obj->string.pointer[i]);
+
+		/*
+		 * The Windows WMI-ACPI driver always emits a terminating nul character,
+		 * so we emulate this behavior here as well.
+		 */
+		string->chars[obj->string.length] = '\0';
+		break;
+	case ACPI_TYPE_BUFFER:
+		aligned = buffer;
+		length = obj->buffer.length;
+
+		memcpy(aligned, obj->buffer.pointer, length);
+		break;
+	default:
+		return -EPROTO;
+	}
+
+	*consumed = (aligned - buffer) + length;
+
+	return 0;
+}
+
+static int wmi_obj_transform(const union acpi_object *obj, u8 *buffer)
+{
+	size_t consumed;
+	int ret;
+
+	if (obj->type == ACPI_TYPE_PACKAGE) {
+		for (int i = 0; i < obj->package.count; i++) {
+			ret = wmi_obj_transform_simple(&obj->package.elements[i], buffer,
+						       &consumed);
+			if (ret < 0)
+				return ret;
+
+			buffer += consumed;
+		}
+	} else {
+		ret = wmi_obj_transform_simple(obj, buffer, &consumed);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer)
+{
+	ssize_t length;
+	u8 *data;
+	int ret;
+
+	ret = wmi_obj_get_buffer_length(obj, &length);
+	if (ret < 0)
+		return ret;
+
+	data = kzalloc(length, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ret = wmi_obj_transform(obj, data);
+	if (ret < 0) {
+		kfree(data);
+		return ret;
+	}
+
+	buffer->length = length;
+	buffer->data = data;
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(wmi_unmarshal_acpi_object);
+
+int wmi_marshal_string(const struct wmi_buffer *buffer, struct acpi_buffer *out)
+{
+	const struct wmi_string *string;
+	u16 length, value;
+	size_t chars;
+	char *str;
+
+	if (buffer->length < sizeof(*string))
+		return -ENODATA;
+
+	string = buffer->data;
+	length = get_unaligned_le16(&string->length);
+	if (buffer->length < sizeof(*string) + length)
+		return -ENODATA;
+
+	/* Each character needs to be 16 bits long */
+	if (length % 2)
+		return -EINVAL;
+
+	chars = length / 2;
+	str = kmalloc(chars + 1, GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	for (int i = 0; i < chars; i++) {
+		value = get_unaligned_le16(&string->chars[i]);
+
+		/* ACPI only accepts ASCII strings */
+		if (value > 0x7F) {
+			kfree(str);
+			return -EINVAL;
+		}
+
+		str[i] = value & 0xFF;
+
+		/*
+		 * ACPI strings should only contain a single nul character at the end.
+		 * Because of this we must not copy any padding from the WMI string.
+		 */
+		if (!value) {
+			/* ACPICA wants the length of the string without the nul character */
+			out->length = i;
+			out->pointer = str;
+			return 0;
+		}
+	}
+
+	str[chars] = '\0';
+
+	out->length = chars;
+	out->pointer = str;
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(wmi_marshal_string);
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index 665ea7dc8a92..81f24d238a2c 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -8,9 +8,11 @@
 #ifndef _LINUX_WMI_H
 #define _LINUX_WMI_H
 
+#include <linux/compiler_attributes.h>
 #include <linux/device.h>
 #include <linux/acpi.h>
 #include <linux/mod_devicetable.h>
+#include <linux/types.h>
 
 /**
  * struct wmi_device - WMI device structure
@@ -36,6 +38,37 @@ struct wmi_device {
  */
 #define to_wmi_device(device)	container_of_const(device, struct wmi_device, dev)
 
+/**
+ * struct wmi_buffer - WMI data buffer
+ * @length: Buffer length in bytes
+ * @data: Pointer to the buffer content
+ *
+ * This structure is used to exchange data with the WMI driver core.
+ */
+struct wmi_buffer {
+	size_t length;
+	void *data;
+};
+
+/**
+ * struct wmi_string - WMI string representation
+ * @length: Size of @chars in bytes
+ * @chars: UTF16-LE characters with optional nul termination and padding
+ *
+ * This structure is used when exchanging string data over the WMI interface.
+ */
+struct wmi_string {
+	__le16 length;
+	__le16 chars[];
+} __packed;
+
+int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
+			 const struct wmi_buffer *in, struct wmi_buffer *out);
+
+int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out);
+
+int wmidev_set_block(struct wmi_device *wdev, u8 instance, const struct wmi_buffer *in);
+
 acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id,
 				   const struct acpi_buffer *in, struct acpi_buffer *out);
 
@@ -54,9 +87,11 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
  * @probe: Callback for device binding
  * @remove: Callback for device unbinding
  * @shutdown: Callback for device shutdown
- * @notify: Callback for receiving WMI events
+ * @notify: Callback for receiving WMI events (deprecated)
+ * @notify_new: Callback for receiving WMI events
  *
- * This represents WMI drivers which handle WMI devices.
+ * This represents WMI drivers which handle WMI devices. The data inside the buffer
+ * passed to the @notify_new callback is guaranteed to be aligned on a 8-byte boundary.
  */
 struct wmi_driver {
 	struct device_driver driver;
@@ -68,6 +103,7 @@ struct wmi_driver {
 	void (*remove)(struct wmi_device *wdev);
 	void (*shutdown)(struct wmi_device *wdev);
 	void (*notify)(struct wmi_device *device, union acpi_object *data);
+	void (*notify_new)(struct wmi_device *device, const struct wmi_buffer *data);
 };
 
 /**
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 2/9] platform/wmi: Add kunit test for the marshalling code
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 1/9] " Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 3/9] platform/wmi: Add helper functions for WMI string conversions Armin Wolf
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

The marshalling code used by the WMI driver core is implemented as
a separate component, suitable for unit tests.

Implmented such a unit test using KUnit. Those unit tests verify that
ACPI objects are correctly converted into WMI buffers and that WMI
strings are correctly converted into ACPI strings. They also verify
that invalid ACPI data (like nested packages) is rejected.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/wmi/Kconfig                  |   2 +
 drivers/platform/wmi/Makefile                 |   3 +
 drivers/platform/wmi/tests/Kconfig            |  16 +
 drivers/platform/wmi/tests/Makefile           |   8 +
 .../platform/wmi/tests/marshalling_kunit.c    | 449 ++++++++++++++++++
 5 files changed, 478 insertions(+)
 create mode 100644 drivers/platform/wmi/tests/Kconfig
 create mode 100644 drivers/platform/wmi/tests/Makefile
 create mode 100644 drivers/platform/wmi/tests/marshalling_kunit.c

diff --git a/drivers/platform/wmi/Kconfig b/drivers/platform/wmi/Kconfig
index 77fcbb18746b..21fa3e440042 100644
--- a/drivers/platform/wmi/Kconfig
+++ b/drivers/platform/wmi/Kconfig
@@ -31,4 +31,6 @@ config ACPI_WMI_LEGACY_DEVICE_NAMES
 	  userspace applications but will cause the registration of WMI devices with
 	  the same GUID to fail in some corner cases.
 
+source "drivers/platform/wmi/tests/Kconfig"
+
 endif # ACPI_WMI
diff --git a/drivers/platform/wmi/Makefile b/drivers/platform/wmi/Makefile
index 6f2bf8cc709e..93f37ce519ae 100644
--- a/drivers/platform/wmi/Makefile
+++ b/drivers/platform/wmi/Makefile
@@ -6,3 +6,6 @@
 
 wmi-y			:= core.o marshalling.o
 obj-$(CONFIG_ACPI_WMI)	+= wmi.o
+
+# Unit tests
+obj-y			+= tests/
diff --git a/drivers/platform/wmi/tests/Kconfig b/drivers/platform/wmi/tests/Kconfig
new file mode 100644
index 000000000000..efcbcb51c251
--- /dev/null
+++ b/drivers/platform/wmi/tests/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# ACPI WMI KUnit tests
+#
+
+config ACPI_WMI_MARSHALLING_KUNIT_TEST
+	tristate "KUnit Test for ACPI-WMI marshalling" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds unit tests for the ACPI-WMI marshalling code.
+
+	  For more information on KUnit and unit tests in general, please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
diff --git a/drivers/platform/wmi/tests/Makefile b/drivers/platform/wmi/tests/Makefile
new file mode 100644
index 000000000000..252c3125353a
--- /dev/null
+++ b/drivers/platform/wmi/tests/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Makefile for linux/drivers/platform/x86/wmi/tests
+# ACPI WMI KUnit tests
+#
+
+wmi_marshalling_kunit-y				:= marshalling_kunit.o
+obj-$(CONFIG_ACPI_WMI_MARSHALLING_KUNIT_TEST)	+= wmi_marshalling_kunit.o
diff --git a/drivers/platform/wmi/tests/marshalling_kunit.c b/drivers/platform/wmi/tests/marshalling_kunit.c
new file mode 100644
index 000000000000..1a32323663cc
--- /dev/null
+++ b/drivers/platform/wmi/tests/marshalling_kunit.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit test for the ACPI-WMI marshalling code.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wmi.h>
+
+#include <kunit/resource.h>
+#include <kunit/test.h>
+
+#include "../internal.h"
+
+struct wmi_acpi_param {
+	const char *name;
+	const union acpi_object obj;
+	const struct wmi_buffer buffer;
+};
+
+struct wmi_string_param {
+	const char *name;
+	const char *string;
+	const struct wmi_buffer buffer;
+};
+
+struct wmi_invalid_acpi_param {
+	const char *name;
+	const union acpi_object obj;
+};
+
+struct wmi_invalid_string_param {
+	const char *name;
+	const struct wmi_buffer buffer;
+};
+
+/* 0xdeadbeef */
+static u8 expected_single_integer[] = {
+	0xef, 0xbe, 0xad, 0xde,
+};
+
+/* "TEST" */
+static u8 expected_single_string[] = {
+	0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00,
+};
+
+static u8 test_buffer[] = {
+	0xab, 0xcd,
+};
+
+static u8 expected_single_buffer[] = {
+	0xab, 0xcd,
+};
+
+static union acpi_object simple_package_elements[] = {
+	{
+		.buffer = {
+			.type = ACPI_TYPE_BUFFER,
+			.length = sizeof(test_buffer),
+			.pointer = test_buffer,
+		},
+	},
+	{
+		.integer = {
+			.type = ACPI_TYPE_INTEGER,
+			.value = 0x01020304,
+		},
+	},
+};
+
+static u8 expected_simple_package[] = {
+	0xab, 0xcd,
+	0x00, 0x00,
+	0x04, 0x03, 0x02, 0x01,
+};
+
+static u8 test_small_buffer[] = {
+	0xde,
+};
+
+static union acpi_object complex_package_elements[] = {
+	{
+		.integer = {
+			.type = ACPI_TYPE_INTEGER,
+			.value = 0xdeadbeef,
+		},
+	},
+	{
+		.buffer = {
+			.type = ACPI_TYPE_BUFFER,
+			.length = sizeof(test_small_buffer),
+			.pointer = test_small_buffer,
+		},
+	},
+	{
+		.string = {
+			.type = ACPI_TYPE_STRING,
+			.length = sizeof("TEST") - 1,
+			.pointer = "TEST",
+		},
+	},
+	{
+		.buffer = {
+			.type = ACPI_TYPE_BUFFER,
+			.length = sizeof(test_small_buffer),
+			.pointer = test_small_buffer,
+		},
+	},
+	{
+		.integer = {
+			.type = ACPI_TYPE_INTEGER,
+			.value = 0x01020304,
+		},
+	}
+};
+
+static u8 expected_complex_package[] = {
+	0xef, 0xbe, 0xad, 0xde,
+	0xde,
+	0x00,
+	0x0a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00,
+	0xde,
+	0x00,
+	0x04, 0x03, 0x02, 0x01,
+};
+
+static const struct wmi_acpi_param wmi_acpi_params_array[] = {
+	{
+		.name = "single_integer",
+		.obj = {
+			.integer = {
+				.type = ACPI_TYPE_INTEGER,
+				.value = 0xdeadbeef,
+			},
+		},
+		.buffer = {
+			.data = expected_single_integer,
+			.length = sizeof(expected_single_integer),
+		},
+	},
+	{
+		.name = "single_string",
+		.obj = {
+			.string = {
+				.type = ACPI_TYPE_STRING,
+				.length = sizeof("TEST") - 1,
+				.pointer = "TEST",
+			},
+		},
+		.buffer = {
+			.data = expected_single_string,
+			.length = sizeof(expected_single_string),
+		},
+	},
+	{
+		.name = "single_buffer",
+		.obj = {
+			.buffer = {
+				.type = ACPI_TYPE_BUFFER,
+				.length = sizeof(test_buffer),
+				.pointer = test_buffer,
+			},
+		},
+		.buffer = {
+			.data = expected_single_buffer,
+			.length = sizeof(expected_single_buffer),
+		},
+	},
+	{
+		.name = "simple_package",
+		.obj = {
+			.package = {
+				.type = ACPI_TYPE_PACKAGE,
+				.count = ARRAY_SIZE(simple_package_elements),
+				.elements = simple_package_elements,
+			},
+		},
+		.buffer = {
+			.data = expected_simple_package,
+			.length = sizeof(expected_simple_package),
+		},
+	},
+	{
+		.name = "complex_package",
+		.obj = {
+			.package = {
+				.type = ACPI_TYPE_PACKAGE,
+				.count = ARRAY_SIZE(complex_package_elements),
+				.elements = complex_package_elements,
+			},
+		},
+		.buffer = {
+			.data = expected_complex_package,
+			.length = sizeof(expected_complex_package),
+		},
+	},
+};
+
+static void wmi_acpi_param_get_desc(const struct wmi_acpi_param *param, char *desc)
+{
+	strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object, wmi_acpi_params_array, wmi_acpi_param_get_desc);
+
+/* "WMI\0" */
+static u8 padded_wmi_string[] = {
+	0x0a, 0x00,
+	0x57, 0x00,
+	0x4D, 0x00,
+	0x49, 0x00,
+	0x00, 0x00,
+	0x00, 0x00,
+};
+
+static const struct wmi_string_param wmi_string_params_array[] = {
+	{
+		.name = "test",
+		.string = "TEST",
+		.buffer = {
+			.length = sizeof(expected_single_string),
+			.data = expected_single_string,
+		},
+	},
+	{
+		.name = "padded",
+		.string = "WMI",
+		.buffer = {
+			.length = sizeof(padded_wmi_string),
+			.data = padded_wmi_string,
+		},
+	},
+};
+
+static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc)
+{
+	strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(wmi_marshal_string, wmi_string_params_array, wmi_string_param_get_desc);
+
+static union acpi_object nested_package_elements[] = {
+	{
+		.package = {
+			.type = ACPI_TYPE_PACKAGE,
+			.count = ARRAY_SIZE(simple_package_elements),
+			.elements = simple_package_elements,
+		},
+	}
+};
+
+static const struct wmi_invalid_acpi_param wmi_invalid_acpi_params_array[] = {
+	{
+		.name = "nested_package",
+		.obj = {
+			.package = {
+				.type = ACPI_TYPE_PACKAGE,
+				.count = ARRAY_SIZE(nested_package_elements),
+				.elements = nested_package_elements,
+			},
+		},
+	},
+	{
+		.name = "reference",
+		.obj = {
+			.reference = {
+				.type = ACPI_TYPE_LOCAL_REFERENCE,
+				.actual_type = ACPI_TYPE_ANY,
+				.handle = NULL,
+			},
+		},
+	},
+	{
+		.name = "processor",
+		.obj = {
+			.processor = {
+				.type = ACPI_TYPE_PROCESSOR,
+				.proc_id = 0,
+				.pblk_address = 0,
+				.pblk_length = 0,
+			},
+		},
+	},
+	{
+		.name = "power_resource",
+		.obj = {
+			.power_resource = {
+				.type = ACPI_TYPE_POWER,
+				.system_level = 0,
+				.resource_order = 0,
+			},
+		},
+	},
+};
+
+static void wmi_invalid_acpi_param_get_desc(const struct wmi_invalid_acpi_param *param, char *desc)
+{
+	strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(wmi_unmarshal_acpi_object_failure, wmi_invalid_acpi_params_array,
+		  wmi_invalid_acpi_param_get_desc);
+
+static u8 oversized_wmi_string[] = {
+	0x04, 0x00, 0x00, 0x00,
+};
+
+/*
+ * The error is that 3 bytes can not hold UTF-16 characters
+ * without cutting of the last one.
+ */
+static u8 undersized_wmi_string[] = {
+	0x03, 0x00, 0x00, 0x00, 0x00,
+};
+
+static u8 non_ascii_wmi_string[] = {
+	0x04, 0x00, 0xC4, 0x00, 0x00, 0x00,
+};
+
+static const struct wmi_invalid_string_param wmi_invalid_string_params_array[] = {
+	{
+		.name = "empty_buffer",
+		.buffer = {
+			.length = 0,
+			.data = ZERO_SIZE_PTR,
+		},
+
+	},
+	{
+		.name = "oversized",
+		.buffer = {
+			.length = sizeof(oversized_wmi_string),
+			.data = oversized_wmi_string,
+		},
+	},
+	{
+		.name = "undersized",
+		.buffer = {
+			.length = sizeof(undersized_wmi_string),
+			.data = undersized_wmi_string,
+		},
+	},
+	{
+		.name = "non_ascii",
+		.buffer = {
+			.length = sizeof(non_ascii_wmi_string),
+			.data = non_ascii_wmi_string,
+		},
+	},
+};
+
+static void wmi_invalid_string_param_get_desc(const struct wmi_invalid_string_param *param,
+					      char *desc)
+{
+	strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(wmi_marshal_string_failure, wmi_invalid_string_params_array,
+		  wmi_invalid_string_param_get_desc);
+
+KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
+
+static void wmi_unmarshal_acpi_object_test(struct kunit *test)
+{
+	const struct wmi_acpi_param *param = test->param_value;
+	struct wmi_buffer result;
+	int ret;
+
+	ret = wmi_unmarshal_acpi_object(&param->obj, &result);
+	if (ret < 0)
+		KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n");
+
+	kunit_add_action(test, kfree_wrapper, result.data);
+
+	KUNIT_EXPECT_EQ(test, result.length, param->buffer.length);
+	KUNIT_EXPECT_MEMEQ(test, result.data, param->buffer.data, result.length);
+}
+
+static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test)
+{
+	const struct wmi_invalid_acpi_param *param = test->param_value;
+	struct wmi_buffer result;
+	int ret;
+
+	ret = wmi_unmarshal_acpi_object(&param->obj, &result);
+	if (ret < 0)
+		return;
+
+	kfree(result.data);
+	KUNIT_FAIL(test, "Invalid ACPI object was not rejected\n");
+}
+
+static void wmi_marshal_string_test(struct kunit *test)
+{
+	const struct wmi_string_param *param = test->param_value;
+	struct acpi_buffer result;
+	int ret;
+
+	ret = wmi_marshal_string(&param->buffer, &result);
+	if (ret < 0)
+		KUNIT_FAIL_AND_ABORT(test, "Marshalling of WMI string failed\n");
+
+	kunit_add_action(test, kfree_wrapper, result.pointer);
+
+	KUNIT_EXPECT_EQ(test, result.length, strlen(param->string));
+	KUNIT_EXPECT_STREQ(test, result.pointer, param->string);
+}
+
+static void wmi_marshal_string_failure_test(struct kunit *test)
+{
+	const struct wmi_invalid_string_param *param = test->param_value;
+	struct acpi_buffer result;
+	int ret;
+
+	ret = wmi_marshal_string(&param->buffer, &result);
+	if (ret < 0)
+		return;
+
+	kfree(result.pointer);
+	KUNIT_FAIL(test, "Invalid string was not rejected\n");
+}
+
+static struct kunit_case wmi_marshalling_test_cases[] = {
+	KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test,
+			 wmi_unmarshal_acpi_object_gen_params),
+	KUNIT_CASE_PARAM(wmi_marshal_string_test,
+			 wmi_marshal_string_gen_params),
+	KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_failure_test,
+			 wmi_unmarshal_acpi_object_failure_gen_params),
+	KUNIT_CASE_PARAM(wmi_marshal_string_failure_test,
+			 wmi_marshal_string_failure_gen_params),
+	{}
+};
+
+static struct kunit_suite wmi_marshalling_test_suite = {
+	.name = "wmi_marshalling",
+	.test_cases = wmi_marshalling_test_cases,
+};
+
+kunit_test_suite(wmi_marshalling_test_suite);
+
+MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
+MODULE_DESCRIPTION("KUnit test for the ACPI-WMI marshalling code");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+MODULE_LICENSE("GPL");
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 3/9] platform/wmi: Add helper functions for WMI string conversions
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 1/9] " Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 2/9] platform/wmi: Add kunit test for the marshalling code Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code Armin Wolf
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

WMI strings are encoded using UTF16-LE characters, forcing WMI drivers
to manually convert them to/from standard UTF8 strings. Add a two
helper functions for those tasks.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 Documentation/driver-api/wmi.rst |  3 ++
 drivers/platform/wmi/Kconfig     |  1 +
 drivers/platform/wmi/Makefile    |  2 +-
 drivers/platform/wmi/string.c    | 92 ++++++++++++++++++++++++++++++++
 include/linux/wmi.h              |  5 ++
 5 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 drivers/platform/wmi/string.c

diff --git a/Documentation/driver-api/wmi.rst b/Documentation/driver-api/wmi.rst
index db835b43c937..b847bcdcbb09 100644
--- a/Documentation/driver-api/wmi.rst
+++ b/Documentation/driver-api/wmi.rst
@@ -16,5 +16,8 @@ which will be bound to compatible WMI devices by the driver core.
 .. kernel-doc:: include/linux/wmi.h
    :internal:
 
+.. kernel-doc:: drivers/platform/wmi/string.c
+   :export:
+
 .. kernel-doc:: drivers/platform/wmi/core.c
    :export:
diff --git a/drivers/platform/wmi/Kconfig b/drivers/platform/wmi/Kconfig
index 21fa3e440042..d62f51ff3b7f 100644
--- a/drivers/platform/wmi/Kconfig
+++ b/drivers/platform/wmi/Kconfig
@@ -6,6 +6,7 @@
 menuconfig ACPI_WMI
 	tristate "ACPI-WMI support"
 	depends on ACPI && X86
+	select NLS
 	help
 	  This option enables support for the ACPI-WMI driver core.
 
diff --git a/drivers/platform/wmi/Makefile b/drivers/platform/wmi/Makefile
index 93f37ce519ae..2feff94a5594 100644
--- a/drivers/platform/wmi/Makefile
+++ b/drivers/platform/wmi/Makefile
@@ -4,7 +4,7 @@
 # ACPI WMI core
 #
 
-wmi-y			:= core.o marshalling.o
+wmi-y			:= core.o marshalling.o string.o
 obj-$(CONFIG_ACPI_WMI)	+= wmi.o
 
 # Unit tests
diff --git a/drivers/platform/wmi/string.c b/drivers/platform/wmi/string.c
new file mode 100644
index 000000000000..0fc43218aa5b
--- /dev/null
+++ b/drivers/platform/wmi/string.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * WMI string utility functions.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#include <linux/build_bug.h>
+#include <linux/compiler_types.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/nls.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/wmi.h>
+
+#include <asm/byteorder.h>
+
+static_assert(sizeof(__le16) == sizeof(wchar_t));
+
+/**
+ * wmi_string_to_utf8s - Convert a WMI string into a UTF8 string.
+ * @str: WMI string representation
+ * @dst: Buffer to fill with UTF8 characters
+ * @length: Length of the destination buffer
+ *
+ * Convert as WMI string into a standard UTF8 string. The conversion will stop
+ * once a NUL character is detected or when the buffer is full. Any invalid UTF16
+ * characters will be ignored. The resulting UTF8 string will always be NUL-terminated
+ * when this function returns successfully.
+ *
+ * Return: Length of the resulting UTF8 string or negative errno code on failure.
+ */
+ssize_t wmi_string_to_utf8s(const struct wmi_string *str, u8 *dst, size_t length)
+{
+	/* Contains the maximum number of UTF16 code points to read */
+	int inlen = le16_to_cpu(str->length) / 2;
+	int ret;
+
+	if (length < 1)
+		return -EINVAL;
+
+	/* We must leave room for the NUL character at the end of the destination buffer */
+	ret = utf16s_to_utf8s((__force const wchar_t *)str->chars, inlen, UTF16_LITTLE_ENDIAN, dst,
+			      length - 1);
+	if (ret < 0)
+		return ret;
+
+	dst[ret] = '\0';
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wmi_string_to_utf8s);
+
+/**
+ * wmi_string_from_utf8s - Convert a UTF8 string into a WMI string.
+ * @str: WMI string representation
+ * @max_chars: Maximum number of UTF16 code points to store inside the WMI string
+ * @src: UTF8 string to convert
+ * @src_length: Length of the source string without any trailing NUL-characters
+ *
+ * Convert a UTF8 string into a WMI string. The conversion will stop when the WMI string is
+ * full. The resulting WMI string will always be NUL-terminated and have its length field set
+ * to and appropriate value when this function returns successfully.
+ *
+ * Return: Number of UTF16 code points inside the WMI string or negative errno code on failure.
+ */
+ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 *src,
+			      size_t src_length)
+{
+	size_t str_length;
+	int ret;
+
+	if (max_chars < 1)
+		return -EINVAL;
+
+	/* We must leave room for the NUL character at the end of the WMI string */
+	ret = utf8s_to_utf16s(src, src_length, UTF16_LITTLE_ENDIAN, (__force wchar_t *)str->chars,
+			      max_chars - 1);
+	if (ret < 0)
+		return ret;
+
+	str_length = (ret + 1) * sizeof(u16);
+	if (str_length > U16_MAX)
+		return -EOVERFLOW;
+
+	str->length = cpu_to_le16(str_length);
+	str->chars[ret] = '\0';
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wmi_string_from_utf8s);
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index 81f24d238a2c..75cb0c7cfe57 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -62,6 +62,11 @@ struct wmi_string {
 	__le16 chars[];
 } __packed;
 
+ssize_t wmi_string_to_utf8s(const struct wmi_string *str, u8 *dst, size_t length);
+
+ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 *src,
+			      size_t src_length);
+
 int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
 			 const struct wmi_buffer *in, struct wmi_buffer *out);
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (2 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 3/9] platform/wmi: Add helper functions for WMI string conversions Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-12 16:34   ` Ilpo Järvinen
  2026-01-22 23:45   ` Nathan Chancellor
  2026-01-09 21:46 ` [PATCH v3 5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API Armin Wolf
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

The string conversion frunctions provided by the WMI driver core
have no dependencies on the remaining WMI API, making them suitable
for unit tests.

Implement such a unit test using kunit. Those unit tests verify that
converting between WMI strings and UTF8 strings works as expected.
They also verify that edge cases are handled correctly.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/wmi/tests/Kconfig        |  11 +
 drivers/platform/wmi/tests/Makefile       |   3 +
 drivers/platform/wmi/tests/string_kunit.c | 278 ++++++++++++++++++++++
 3 files changed, 292 insertions(+)
 create mode 100644 drivers/platform/wmi/tests/string_kunit.c

diff --git a/drivers/platform/wmi/tests/Kconfig b/drivers/platform/wmi/tests/Kconfig
index efcbcb51c251..f7f0f3c540f5 100644
--- a/drivers/platform/wmi/tests/Kconfig
+++ b/drivers/platform/wmi/tests/Kconfig
@@ -14,3 +14,14 @@ config ACPI_WMI_MARSHALLING_KUNIT_TEST
 	  to the KUnit documentation in Documentation/dev-tools/kunit/.
 
 	  If unsure, say N.
+
+config ACPI_WMI_STRING_KUNIT_TEST
+	tristate "KUnit Test for ACPI-WMI string conversion" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds unit tests for the ACPI-WMI string conversion code.
+	  For more information on KUnit and unit tests in general, please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
diff --git a/drivers/platform/wmi/tests/Makefile b/drivers/platform/wmi/tests/Makefile
index 252c3125353a..62c438e26259 100644
--- a/drivers/platform/wmi/tests/Makefile
+++ b/drivers/platform/wmi/tests/Makefile
@@ -6,3 +6,6 @@
 
 wmi_marshalling_kunit-y				:= marshalling_kunit.o
 obj-$(CONFIG_ACPI_WMI_MARSHALLING_KUNIT_TEST)	+= wmi_marshalling_kunit.o
+
+wmi_string_kunit-y				:= string_kunit.o
+obj-$(CONFIG_ACPI_WMI_STRING_KUNIT_TEST)	+= wmi_string_kunit.o
diff --git a/drivers/platform/wmi/tests/string_kunit.c b/drivers/platform/wmi/tests/string_kunit.c
new file mode 100644
index 000000000000..9aa3ffa85090
--- /dev/null
+++ b/drivers/platform/wmi/tests/string_kunit.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit test for the ACPI-WMI string conversion code.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wmi.h>
+
+#include <kunit/resource.h>
+#include <kunit/test.h>
+
+#include <asm/byteorder.h>
+
+struct wmi_string_param {
+	const char *name;
+	const struct wmi_string *wmi_string;
+	/*
+	 * Remember that using sizeof() on a struct wmi_string will
+	 * always return a size of two bytes due to the flexible
+	 * array member!
+	 */
+	size_t wmi_string_length;
+	const u8 *utf8_string;
+	size_t utf8_string_length;
+};
+
+#define TEST_WMI_STRING_LENGTH 12
+
+static const struct wmi_string test_wmi_string = {
+	.length = cpu_to_le16(10),
+	.chars = {
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'E'),
+		cpu_to_le16(u'S'),
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+static const u8 test_utf8_string[] = "TEST";
+
+#define SPECIAL_WMI_STRING_LENGTH 14
+
+static const struct wmi_string special_wmi_string = {
+	.length = cpu_to_le16(12),
+	.chars = {
+		cpu_to_le16(u'Ä'),
+		cpu_to_le16(u'Ö'),
+		cpu_to_le16(u'Ü'),
+		cpu_to_le16(u'ß'),
+		cpu_to_le16(u'€'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+static const u8 special_utf8_string[] = "ÄÖÜ߀";
+
+#define MULTI_POINT_WMI_STRING_LENGTH 12
+
+static const struct wmi_string multi_point_wmi_string = {
+	.length = cpu_to_le16(10),
+	.chars = {
+		cpu_to_le16(u'K'),
+		/* 🐧 */
+		cpu_to_le16(0xD83D),
+		cpu_to_le16(0xDC27),
+		cpu_to_le16(u'!'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+static const u8 multi_point_utf8_string[] = "K🐧!";
+
+#define PADDED_TEST_WMI_STRING_LENGTH 14
+
+static const struct wmi_string padded_test_wmi_string = {
+	.length = cpu_to_le16(12),
+	.chars = {
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'E'),
+		cpu_to_le16(u'S'),
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'\0'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+static const u8 padded_test_utf8_string[] = "TEST\0";
+
+#define OVERSIZED_TEST_WMI_STRING_LENGTH 14
+
+static const struct wmi_string oversized_test_wmi_string = {
+	.length = cpu_to_le16(8),
+	.chars = {
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'E'),
+		cpu_to_le16(u'S'),
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'!'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+static const u8 oversized_test_utf8_string[] = "TEST!";
+
+#define INVALID_TEST_WMI_STRING_LENGTH 14
+
+static const struct wmi_string invalid_test_wmi_string = {
+	.length = cpu_to_le16(12),
+	.chars = {
+		cpu_to_le16(u'T'),
+		/* 🐧, with low surrogate missing */
+		cpu_to_le16(0xD83D),
+		cpu_to_le16(u'E'),
+		cpu_to_le16(u'S'),
+		cpu_to_le16(u'T'),
+		cpu_to_le16(u'\0'),
+	},
+};
+
+/* We have to split the string here to end the hex escape sequence */
+static const u8 invalid_test_utf8_string[] = "T" "\xF0\x9F" "EST";
+
+static const struct wmi_string_param wmi_string_params_array[] = {
+	{
+		.name = "ascii_string",
+		.wmi_string = &test_wmi_string,
+		.wmi_string_length = TEST_WMI_STRING_LENGTH,
+		.utf8_string = test_utf8_string,
+		.utf8_string_length = sizeof(test_utf8_string),
+	},
+	{
+		.name = "special_string",
+		.wmi_string = &special_wmi_string,
+		.wmi_string_length = SPECIAL_WMI_STRING_LENGTH,
+		.utf8_string = special_utf8_string,
+		.utf8_string_length = sizeof(special_utf8_string),
+	},
+	{
+		.name = "multi_point_string",
+		.wmi_string = &multi_point_wmi_string,
+		.wmi_string_length = MULTI_POINT_WMI_STRING_LENGTH,
+		.utf8_string = multi_point_utf8_string,
+		.utf8_string_length = sizeof(multi_point_utf8_string),
+	},
+};
+
+static void wmi_string_param_get_desc(const struct wmi_string_param *param, char *desc)
+{
+	strscpy(desc, param->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(wmi_string, wmi_string_params_array, wmi_string_param_get_desc);
+
+static void wmi_string_to_utf8s_test(struct kunit *test)
+{
+	const struct wmi_string_param *param = test->param_value;
+	ssize_t ret;
+	u8 *result;
+
+	result = kunit_kzalloc(test, param->utf8_string_length, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
+
+	ret = wmi_string_to_utf8s(param->wmi_string, result, param->utf8_string_length);
+
+	KUNIT_EXPECT_EQ(test, ret, param->utf8_string_length - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, param->utf8_string, param->utf8_string_length);
+}
+
+static void wmi_string_from_utf8s_test(struct kunit *test)
+{
+	const struct wmi_string_param *param = test->param_value;
+	struct wmi_string *result;
+	size_t max_chars;
+	ssize_t ret;
+
+	max_chars = (param->wmi_string_length - sizeof(*result)) / 2;
+	result = kunit_kzalloc(test, param->wmi_string_length, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
+
+	ret = wmi_string_from_utf8s(result, max_chars, param->utf8_string,
+				    param->utf8_string_length);
+
+	KUNIT_EXPECT_EQ(test, ret, max_chars - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, param->wmi_string, param->wmi_string_length);
+}
+
+static void wmi_string_to_utf8s_padded_test(struct kunit *test)
+{
+	u8 result[sizeof(padded_test_utf8_string)];
+	ssize_t ret;
+
+	ret = wmi_string_to_utf8s(&padded_test_wmi_string, result, sizeof(result));
+
+	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
+}
+
+static void wmi_string_from_utf8s_padded_test(struct kunit *test)
+{
+	struct wmi_string *result;
+	size_t max_chars;
+	ssize_t ret;
+
+	max_chars = (PADDED_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
+	result = kunit_kzalloc(test, PADDED_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
+
+	ret = wmi_string_from_utf8s(result, max_chars, padded_test_utf8_string,
+				    sizeof(padded_test_utf8_string));
+
+	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, &test_wmi_string, sizeof(test_wmi_string));
+}
+
+static void wmi_string_to_utf8s_oversized_test(struct kunit *test)
+{
+	u8 result[sizeof(oversized_test_utf8_string)];
+	ssize_t ret;
+
+	ret = wmi_string_to_utf8s(&oversized_test_wmi_string, result, sizeof(result));
+
+	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
+}
+
+static void wmi_string_to_utf8s_invalid_test(struct kunit *test)
+{
+	u8 result[sizeof(invalid_test_utf8_string)];
+	ssize_t ret;
+
+	ret = wmi_string_to_utf8s(&invalid_test_wmi_string, result, sizeof(result));
+
+	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
+	KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
+}
+
+static void wmi_string_from_utf8s_invalid_test(struct kunit *test)
+{
+	struct wmi_string *result;
+	size_t max_chars;
+	ssize_t ret;
+
+	max_chars = (INVALID_TEST_WMI_STRING_LENGTH - sizeof(*result)) / 2;
+	result = kunit_kzalloc(test, INVALID_TEST_WMI_STRING_LENGTH, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, result);
+
+	ret = wmi_string_from_utf8s(result, max_chars, invalid_test_utf8_string,
+				    sizeof(invalid_test_utf8_string));
+
+	KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+}
+
+static struct kunit_case wmi_string_test_cases[] = {
+	KUNIT_CASE_PARAM(wmi_string_to_utf8s_test, wmi_string_gen_params),
+	KUNIT_CASE_PARAM(wmi_string_from_utf8s_test, wmi_string_gen_params),
+	KUNIT_CASE(wmi_string_to_utf8s_padded_test),
+	KUNIT_CASE(wmi_string_from_utf8s_padded_test),
+	KUNIT_CASE(wmi_string_to_utf8s_oversized_test),
+	KUNIT_CASE(wmi_string_to_utf8s_invalid_test),
+	KUNIT_CASE(wmi_string_from_utf8s_invalid_test),
+	{}
+};
+
+static struct kunit_suite wmi_string_test_suite = {
+	.name = "wmi_string",
+	.test_cases = wmi_string_test_cases,
+};
+
+kunit_test_suite(wmi_string_test_suite);
+
+MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
+MODULE_DESCRIPTION("KUnit test for the ACPI-WMI string conversion code");
+MODULE_LICENSE("GPL");
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (3 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 6/9] platform/x86/intel/wmi: thunderbolt: " Armin Wolf
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

Use the new buffer-based WMI API to also support ACPI firmware
implementations that return a ACPI buffer instead of a ACPI integer.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 .../platform/x86/intel/wmi/sbl-fw-update.c    | 43 ++++++++-----------
 1 file changed, 18 insertions(+), 25 deletions(-)

diff --git a/drivers/platform/x86/intel/wmi/sbl-fw-update.c b/drivers/platform/x86/intel/wmi/sbl-fw-update.c
index 75c82c08117f..3716ccaaed6a 100644
--- a/drivers/platform/x86/intel/wmi/sbl-fw-update.c
+++ b/drivers/platform/x86/intel/wmi/sbl-fw-update.c
@@ -14,7 +14,6 @@
  * https://slimbootloader.github.io/security/firmware-update.html
  */
 
-#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -25,41 +24,35 @@
 
 static int get_fwu_request(struct device *dev, u32 *out)
 {
-	union acpi_object *obj;
+	struct wmi_buffer buffer;
+	__le32 *result;
+	int ret;
 
-	obj = wmidev_block_query(to_wmi_device(dev), 0);
-	if (!obj)
-		return -ENODEV;
+	ret = wmidev_query_block(to_wmi_device(dev), 0, &buffer);
+	if (ret < 0)
+		return ret;
 
-	if (obj->type != ACPI_TYPE_INTEGER) {
-		dev_warn(dev, "wmidev_block_query returned invalid value\n");
-		kfree(obj);
-		return -EINVAL;
+	if (buffer.length < sizeof(*result)) {
+		kfree(buffer.data);
+		return -ENODATA;
 	}
 
-	*out = obj->integer.value;
-	kfree(obj);
+	result = buffer.data;
+	*out = le32_to_cpu(*result);
+	kfree(result);
 
 	return 0;
 }
 
 static int set_fwu_request(struct device *dev, u32 in)
 {
-	struct acpi_buffer input;
-	acpi_status status;
-	u32 value;
-
-	value = in;
-	input.length = sizeof(u32);
-	input.pointer = &value;
-
-	status = wmidev_block_set(to_wmi_device(dev), 0, &input);
-	if (ACPI_FAILURE(status)) {
-		dev_err(dev, "wmidev_block_set failed\n");
-		return -ENODEV;
-	}
+	__le32 value = cpu_to_le32(in);
+	struct wmi_buffer buffer = {
+		.length = sizeof(value),
+		.data = &value,
+	};
 
-	return 0;
+	return wmidev_set_block(to_wmi_device(dev), 0, &buffer);
 }
 
 static ssize_t firmware_update_request_show(struct device *dev,
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 6/9] platform/x86/intel/wmi: thunderbolt: Use new buffer-based WMI API
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (4 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 7/9] platform/x86: xiaomi-wmi: " Armin Wolf
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

Use the new buffer-based WMI API to avoid having to deal with ACPI
at all.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/x86/intel/wmi/thunderbolt.c | 26 +++++++++-----------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/platform/x86/intel/wmi/thunderbolt.c b/drivers/platform/x86/intel/wmi/thunderbolt.c
index 08df560a2c7a..f01dd096c689 100644
--- a/drivers/platform/x86/intel/wmi/thunderbolt.c
+++ b/drivers/platform/x86/intel/wmi/thunderbolt.c
@@ -7,7 +7,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -23,24 +22,21 @@ static ssize_t force_power_store(struct device *dev,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	struct acpi_buffer input;
-	acpi_status status;
+	struct wmi_buffer buffer;
+	int ret;
 	u8 mode;
 
-	input.length = sizeof(u8);
-	input.pointer = &mode;
+	buffer.length = sizeof(mode);
+	buffer.data = &mode;
+
 	mode = hex_to_bin(buf[0]);
-	dev_dbg(dev, "force_power: storing %#x\n", mode);
-	if (mode == 0 || mode == 1) {
-		status = wmidev_evaluate_method(to_wmi_device(dev), 0, 1, &input, NULL);
-		if (ACPI_FAILURE(status)) {
-			dev_dbg(dev, "force_power: failed to evaluate ACPI method\n");
-			return -ENODEV;
-		}
-	} else {
-		dev_dbg(dev, "force_power: unsupported mode\n");
+	if (mode > 1)
 		return -EINVAL;
-	}
+
+	ret = wmidev_invoke_method(to_wmi_device(dev), 0, 1, &buffer, NULL);
+	if (ret < 0)
+		return ret;
+
 	return count;
 }
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 7/9] platform/x86: xiaomi-wmi: Use new buffer-based WMI API
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (5 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 6/9] platform/x86/intel/wmi: thunderbolt: " Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 8/9] platform/x86: wmi-bmof: " Armin Wolf
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

Use the new buffer-based WMI API to avoid having to deal with ACPI
at all.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/x86/xiaomi-wmi.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c
index b892007b9863..badf9e42e015 100644
--- a/drivers/platform/x86/xiaomi-wmi.c
+++ b/drivers/platform/x86/xiaomi-wmi.c
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /* WMI driver for Xiaomi Laptops */
 
-#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/input.h>
 #include <linux/module.h>
@@ -56,7 +55,7 @@ static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context)
 	return input_register_device(data->input_dev);
 }
 
-static void xiaomi_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy)
+static void xiaomi_wmi_notify(struct wmi_device *wdev, const struct wmi_buffer *dummy)
 {
 	struct xiaomi_wmi *data = dev_get_drvdata(&wdev->dev);
 
@@ -85,7 +84,7 @@ static struct wmi_driver xiaomi_wmi_driver = {
 	},
 	.id_table = xiaomi_wmi_id_table,
 	.probe = xiaomi_wmi_probe,
-	.notify = xiaomi_wmi_notify,
+	.notify_new = xiaomi_wmi_notify,
 	.no_singleton = true,
 };
 module_wmi_driver(xiaomi_wmi_driver);
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 8/9] platform/x86: wmi-bmof: Use new buffer-based WMI API
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (6 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 7/9] platform/x86: xiaomi-wmi: " Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-09 21:46 ` [PATCH v3 9/9] platform/wmi: Update driver development guide Armin Wolf
  2026-01-12 15:33 ` [PATCH v3 0/9] platform/wmi: Introduce marshalling support Ilpo Järvinen
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

Use the new buffer-based WMI API to also support ACPI firmware
implementations that do not use ACPI buffers to return the BMOF data.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/x86/wmi-bmof.c | 34 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 19 deletions(-)

diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c
index 5b00370a9a22..e3a126de421b 100644
--- a/drivers/platform/x86/wmi-bmof.c
+++ b/drivers/platform/x86/wmi-bmof.c
@@ -8,7 +8,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -24,9 +23,9 @@ static ssize_t bmof_read(struct file *filp, struct kobject *kobj, const struct b
 			 char *buf, loff_t off, size_t count)
 {
 	struct device *dev = kobj_to_dev(kobj);
-	union acpi_object *obj = dev_get_drvdata(dev);
+	struct wmi_buffer *buffer = dev_get_drvdata(dev);
 
-	return memory_read_from_buffer(buf, count, &off, obj->buffer.pointer, obj->buffer.length);
+	return memory_read_from_buffer(buf, count, &off, buffer->data, buffer->length);
 }
 
 static const BIN_ATTR_ADMIN_RO(bmof, 0);
@@ -39,9 +38,9 @@ static const struct bin_attribute * const bmof_attrs[] = {
 static size_t bmof_bin_size(struct kobject *kobj, const struct bin_attribute *attr, int n)
 {
 	struct device *dev = kobj_to_dev(kobj);
-	union acpi_object *obj = dev_get_drvdata(dev);
+	struct wmi_buffer *buffer = dev_get_drvdata(dev);
 
-	return obj->buffer.length;
+	return buffer->length;
 }
 
 static const struct attribute_group bmof_group = {
@@ -56,30 +55,27 @@ static const struct attribute_group *bmof_groups[] = {
 
 static int wmi_bmof_probe(struct wmi_device *wdev, const void *context)
 {
-	union acpi_object *obj;
+	struct wmi_buffer *buffer;
+	int ret;
 
-	obj = wmidev_block_query(wdev, 0);
-	if (!obj) {
-		dev_err(&wdev->dev, "failed to read Binary MOF\n");
-		return -EIO;
-	}
+	buffer = devm_kzalloc(&wdev->dev, sizeof(*buffer), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
 
-	if (obj->type != ACPI_TYPE_BUFFER) {
-		dev_err(&wdev->dev, "Binary MOF is not a buffer\n");
-		kfree(obj);
-		return -EIO;
-	}
+	ret = wmidev_query_block(wdev, 0, buffer);
+	if (ret < 0)
+		return ret;
 
-	dev_set_drvdata(&wdev->dev, obj);
+	dev_set_drvdata(&wdev->dev, buffer);
 
 	return 0;
 }
 
 static void wmi_bmof_remove(struct wmi_device *wdev)
 {
-	union acpi_object *obj = dev_get_drvdata(&wdev->dev);
+	struct wmi_buffer *buffer = dev_get_drvdata(&wdev->dev);
 
-	kfree(obj);
+	kfree(buffer->data);
 }
 
 static const struct wmi_device_id wmi_bmof_id_table[] = {
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 9/9] platform/wmi: Update driver development guide
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (7 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 8/9] platform/x86: wmi-bmof: " Armin Wolf
@ 2026-01-09 21:46 ` Armin Wolf
  2026-01-12 15:33 ` [PATCH v3 0/9] platform/wmi: Introduce marshalling support Ilpo Järvinen
  9 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-09 21:46 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

New WMI drivers should use the new buffer-based WMI API instead of
the deprecated ACPI-based API. Update the driver development guide
to recommend the buffer-based API to driver developers and explain
the purpose of struct wmi_buffer.

Also update the ACPI interface documentation to describe the
conversion rules for converting ACPI objects into WMI buffers.

Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 Documentation/wmi/acpi-interface.rst          | 68 +++++++++++++++++
 .../wmi/driver-development-guide.rst          | 76 +++++++++++++------
 2 files changed, 121 insertions(+), 23 deletions(-)

diff --git a/Documentation/wmi/acpi-interface.rst b/Documentation/wmi/acpi-interface.rst
index 1ef003b033bf..4657101c528a 100644
--- a/Documentation/wmi/acpi-interface.rst
+++ b/Documentation/wmi/acpi-interface.rst
@@ -104,3 +104,71 @@ holding the notification ID of the event. This method should be evaluated every
 time an ACPI notification is received, since some ACPI implementations use a
 queue to store WMI event data items. This queue will overflow after a couple
 of WMI events are received without retrieving the associated WMI event data.
+
+Conversion rules for ACPI data types
+------------------------------------
+
+Consumers of the ACPI-WMI interface use binary buffers to exchange data with the WMI driver core,
+with the internal structure of the buffer being only know to the consumers. The WMI driver core is
+thus responsible for converting the data inside the buffer into an appropriate ACPI data type for
+consumption by the ACPI firmware. Additionally, any data returned by the various ACPI methods needs
+to be converted back into a binary buffer.
+
+The layout of said buffers is defined by the MOF description of the WMI method or data block in
+question [1]_:
+
+=============== ======================================================================= =========
+Data Type       Layout                                                                  Alignment
+=============== ======================================================================= =========
+``string``      Starts with an unsigned 16-bit little endian integer specifying         2 bytes
+                the length of the string data in bytes, followed by the string data
+                encoded as UTF-16LE with **optional** NULL termination and padding.
+                Keep in mind that some firmware implementations might depend on the
+                terminating NULL character to be present. Also the padding should
+                always be performed with NULL characters.
+``boolean``     Single byte where 0 means ``false`` and nonzero means ``true``.         1 byte
+``sint8``       Signed 8-bit integer.                                                   1 byte
+``uint8``       Unsigned 8-bit integer.                                                 1 byte
+``sint16``      Signed 16-bit little endian integer.                                    2 bytes
+``uint16``      Unsigned 16-bit little endian integer.                                  2 bytes
+``sint32``      Signed 32-bit little endian integer.                                    4 bytes
+``uint32``      Unsigned 32-bit little endian integer.                                  4 bytes
+``sint64``      Signed 64-bit little endian integer.                                    8 bytes
+``uint64``      Unsigned 64-bit little endian integer.                                  8 bytes
+``datetime``    A fixed-length 25-character UTF-16LE string with the format             2 bytes
+                *yyyymmddhhmmss.mmmmmmsutc* where *yyyy* is the 4-digit year, *mm* is
+                the 2-digit month, *dd* is the 2-digit day, *hh* is the 2-digit hour
+                based on a 24-hour clock, *mm* is the 2-digit minute, *ss* is the
+                2-digit second, *mmmmmm* is the 6-digit microsecond, *s* is a plus or
+                minus character depending on whether *utc* is a positive or negative
+                offset from UTC (or a colon if the date is an interval). Unpopulated
+                fields should be filled with asterisks.
+=============== ======================================================================= =========
+
+Arrays should be aligned based on the alignment of their base type, while objects should be
+aligned based on the largest alignment of an element inside them.
+
+All buffers returned by the WMI driver core are 8-byte aligned. When converting ACPI data types
+into such buffers the following conversion rules apply:
+
+=============== ============================================================
+ACPI Data Type  Converted into
+=============== ============================================================
+Buffer          Copied as-is.
+Integer         Converted into a ``uint32``.
+String          Converted into a ``string`` with a terminating NULL character
+                to match the behavior the of the Windows driver.
+Package         Each element inside the package is converted with alignment
+                of the resulting data types being respected. Nested packages
+                are not allowed.
+=============== ============================================================
+
+The Windows driver does attempt to handle nested packages, but this results in internal data
+structures (``_ACPI_METHOD_ARGUMENT_V1``) erroneously being copied into the resulting buffer.
+ACPI firmware implementations should thus not return nested packages from ACPI methods
+associated with the ACPI-WMI interface.
+
+References
+==========
+
+.. [1] https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/driver-defined-wmi-data-items
diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst
index 5680303ae314..fbc2d9b12fe9 100644
--- a/Documentation/wmi/driver-development-guide.rst
+++ b/Documentation/wmi/driver-development-guide.rst
@@ -70,7 +70,7 @@ to matching WMI devices using a struct wmi_device_id table:
         .probe = foo_probe,
         .remove = foo_remove,         /* optional, devres is preferred */
         .shutdown = foo_shutdown,     /* optional, called during shutdown */
-        .notify = foo_notify,         /* optional, for event handling */
+        .notify_new = foo_notify,     /* optional, for event handling */
         .no_notify_data = true,       /* optional, enables events containing no additional data */
         .no_singleton = true,         /* required for new WMI drivers */
   };
@@ -90,9 +90,9 @@ the WMI device and put it in a well-known state for the WMI driver to pick up la
 or kexec. Most WMI drivers need no special shutdown handling and can thus omit this callback.
 
 Please note that new WMI drivers are required to be able to be instantiated multiple times,
-and are forbidden from using any deprecated GUID-based WMI functions. This means that the
-WMI driver should be prepared for the scenario that multiple matching WMI devices are present
-on a given machine.
+and are forbidden from using any deprecated GUID-based or ACPI-based WMI functions. This means
+that the WMI driver should be prepared for the scenario that multiple matching WMI devices are
+present on a given machine.
 
 Because of this, WMI drivers should use the state container design pattern as described in
 Documentation/driver-api/driver-model/design-patterns.rst.
@@ -104,38 +104,37 @@ Documentation/driver-api/driver-model/design-patterns.rst.
 WMI method drivers
 ------------------
 
-WMI drivers can call WMI device methods using wmidev_evaluate_method(), the
-structure of the ACPI buffer passed to this function is device-specific and usually
-needs some tinkering to get right. Looking at the ACPI tables containing the WMI
-device usually helps here. The method id and instance number passed to this function
-are also device-specific, looking at the decoded Binary MOF is usually enough to
-find the right values.
+WMI drivers can call WMI device methods using wmidev_invoke_method(). For each WMI method
+invocation the WMI driver needs to provide the instance number and the method ID, as well as
+a buffer with the method arguments and optionally a buffer for the results.
 
-The maximum instance number can be retrieved during runtime using wmidev_instance_count().
+The layout of said buffers is device-specific and described by the Binary MOF data associated
+with a given WMI device. Said Binary MOF data also describes the method ID of a given WMI method
+with the ``WmiMethodId`` qualifier. WMI devices exposing WMI methods usually expose only a single
+instance (instance number 0), but in theory can expose multiple instances as well. In such a case
+the number of instances can be retrieved using wmidev_instance_count().
 
-Take a look at drivers/platform/x86/inspur_platform_profile.c for an example WMI method driver.
+Take a look at drivers/platform/x86/intel/wmi/thunderbolt.c for an example WMI method driver.
 
 WMI data block drivers
 ----------------------
 
-WMI drivers can query WMI device data blocks using wmidev_block_query(), the
-structure of the returned ACPI object is again device-specific. Some WMI devices
-also allow for setting data blocks using wmidev_block_set().
+WMI drivers can query WMI data blocks using wmidev_query_block(), the layout of the returned
+buffer is again device-specific and described by the Binary MOF data. Some WMI data blocks are
+also writeable and can be set using wmidev_set_block(). The number of data block instances can
+again be retrieved using wmidev_instance_count().
 
-The maximum instance number can also be retrieved using wmidev_instance_count().
-
-Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example
-WMI data block driver.
+Take a look at drivers/platform/x86/intel/wmi/sbl-fw-update.c for an example WMI data block driver.
 
 WMI event drivers
 -----------------
 
-WMI drivers can receive WMI events via the notify() callback inside the struct wmi_driver.
+WMI drivers can receive WMI events via the notify_new() callback inside the struct wmi_driver.
 The WMI subsystem will then take care of setting up the WMI event accordingly. Please note that
-the structure of the ACPI object passed to this callback is device-specific, and freeing the
-ACPI object is being done by the WMI subsystem, not the driver.
+the layout of the buffer passed to this callback is device-specific, and freeing of the buffer
+is done by the WMI subsystem itself, not the driver.
 
-The WMI driver core will take care that the notify() callback will only be called after
+The WMI driver core will take care that the notify_new() callback will only be called after
 the probe() callback has been called, and that no events are being received by the driver
 right before and after calling its remove() or shutdown() callback.
 
@@ -147,6 +146,36 @@ the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``.
 
 Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver.
 
+Exchanging data with the WMI driver core
+----------------------------------------
+
+WMI drivers can exchange data with the WMI driver core using struct wmi_buffer. The internal
+structure of those buffers is device-specific and only known by the WMI driver. Because of this
+the WMI driver itself is responsible for parsing and validating the data received from its
+WMI device.
+
+The structure of said buffers is described by the MOF data associated with the WMI device in
+question. When such a buffer contains multiple data items it usually makes sense to define a
+C structure and use it during parsing. Since the WMI driver core guarantees that all buffers
+received from a WMI device are aligned on an 8-byte boundary, WMI drivers can simply perform
+a cast between the WMI buffer data and this C structure.
+
+This however should only be done after the size of the buffer was verified to be large enough
+to hold the whole C structure. WMI drivers should reject undersized buffers as they are usually
+sent by the WMI device to signal an internal error. Oversized buffers however should be accepted
+to emulate the behavior of the Windows WMI implementation.
+
+When defining a C structure for parsing WMI buffers the alignment of the data items should be
+respected. This is especially important for 64-bit integers as those have different alignments
+on 64-bit (8-byte alignment) and 32-bit (4-byte alignment) architectures. It is thus a good idea
+to manually specify the alignment of such data items or mark the whole structure as packed when
+appropriate. Integer data items in general are little-endian integers and should be marked as
+such using ``__le64`` and friends. When parsing WMI string data items the struct wmi_string should
+be used as WMI strings have a different layout than C strings.
+
+See Documentation/wmi/acpi-interface.rst for more information regarding the binary format
+of WMI data items.
+
 Handling multiple WMI devices at once
 -------------------------------------
 
@@ -171,6 +200,7 @@ Things to avoid
 When developing WMI drivers, there are a couple of things which should be avoided:
 
 - usage of the deprecated GUID-based WMI interface which uses GUIDs instead of WMI device structs
+- usage of the deprecated ACPI-based WMI interface which uses ACPI objects instead of plain buffers
 - bypassing of the WMI subsystem when talking to WMI devices
 - WMI drivers which cannot be instantiated multiple times.
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 0/9] platform/wmi: Introduce marshalling support
  2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
                   ` (8 preceding siblings ...)
  2026-01-09 21:46 ` [PATCH v3 9/9] platform/wmi: Update driver development guide Armin Wolf
@ 2026-01-12 15:33 ` Ilpo Järvinen
  2026-01-12 18:00   ` Armin Wolf
  9 siblings, 1 reply; 17+ messages in thread
From: Ilpo Järvinen @ 2026-01-12 15:33 UTC (permalink / raw)
  To: hansg, Armin Wolf
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

On Fri, 09 Jan 2026 22:46:10 +0100, Armin Wolf wrote:

> The Windows WMI-ACPI driver likely uses wmilib [1] to interact with
> the WMI service in userspace. Said library uses plain byte buffers
> for exchanging data, so the WMI-ACPI driver has to convert between
> those byte buffers and ACPI objects returned by the ACPI firmware.
> 
> The format of the byte buffer is publicly documented [2], and after
> some reverse eingineering of the WMI-ACPI driver using a set of custom
> ACPI tables, the following conversion rules have been discovered:
> 
> [...]


Thank you for your contribution, it has been applied to my local
review-ilpo-next branch. Note it will show up in the public
platform-drivers-x86/review-ilpo-next branch only once I've pushed my
local branch there, which might take a while.

The list of commits applied:
[1/9] platform/wmi: Introduce marshalling support
      commit: bfa284e9f5e77c9e7389116a403b1dc478f2d58e
[2/9] platform/wmi: Add kunit test for the marshalling code
      commit: 1e4746e93871168f50f237e9e316dc6c9a883719
[3/9] platform/wmi: Add helper functions for WMI string conversions
      commit: 3ae53ee45d5c958aae883173d1e4cafe15564cce
[4/9] platform/wmi: Add kunit test for the string conversion code
      commit: 3579df4cf0b5a3c1d50146c72b13bb4215d509b5
[5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API
      commit: ca7861de6a37a52bf75fe41be51fd39162a9281d
[6/9] platform/x86/intel/wmi: thunderbolt: Use new buffer-based WMI API
      commit: 7f331e5f10ebb72d3bbc83470e4b409337024093
[7/9] platform/x86: xiaomi-wmi: Use new buffer-based WMI API
      commit: e9997669653bc0622f9ed8a3fe778cc989d1e254
[8/9] platform/x86: wmi-bmof: Use new buffer-based WMI API
      commit: 70d37a7fd341e5c0090385034feb8f6f93a56ae7
[9/9] platform/wmi: Update driver development guide
      commit: 0835f9737d4705a9f72de05fde09ba806dcbc862

--
 i.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-09 21:46 ` [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code Armin Wolf
@ 2026-01-12 16:34   ` Ilpo Järvinen
  2026-01-12 17:59     ` Armin Wolf
  2026-01-22 23:45   ` Nathan Chancellor
  1 sibling, 1 reply; 17+ messages in thread
From: Ilpo Järvinen @ 2026-01-12 16:34 UTC (permalink / raw)
  To: Armin Wolf
  Cc: Hans de Goede, platform-driver-x86, LKML, linux,
	Dell.Client.Kernel, corbet, linux-doc

On Fri, 9 Jan 2026, Armin Wolf wrote:

> The string conversion frunctions provided by the WMI driver core
> have no dependencies on the remaining WMI API, making them suitable
> for unit tests.
> 
> Implement such a unit test using kunit. Those unit tests verify that
> converting between WMI strings and UTF8 strings works as expected.
> They also verify that edge cases are handled correctly.
> 
> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> ---
>  drivers/platform/wmi/tests/Kconfig        |  11 +
>  drivers/platform/wmi/tests/Makefile       |   3 +
>  drivers/platform/wmi/tests/string_kunit.c | 278 ++++++++++++++++++++++
>  3 files changed, 292 insertions(+)
>  create mode 100644 drivers/platform/wmi/tests/string_kunit.c
> 
> diff --git a/drivers/platform/wmi/tests/Kconfig b/drivers/platform/wmi/tests/Kconfig
> index efcbcb51c251..f7f0f3c540f5 100644
> --- a/drivers/platform/wmi/tests/Kconfig
> +++ b/drivers/platform/wmi/tests/Kconfig
> @@ -14,3 +14,14 @@ config ACPI_WMI_MARSHALLING_KUNIT_TEST
>  	  to the KUnit documentation in Documentation/dev-tools/kunit/.
>  
>  	  If unsure, say N.
> +
> +config ACPI_WMI_STRING_KUNIT_TEST
> +	tristate "KUnit Test for ACPI-WMI string conversion" if !KUNIT_ALL_TESTS
> +	depends on KUNIT
> +	default KUNIT_ALL_TESTS
> +	help
> +	  This builds unit tests for the ACPI-WMI string conversion code.
> +	  For more information on KUnit and unit tests in general, please refer
> +	  to the KUnit documentation in Documentation/dev-tools/kunit/.
> +
> +	  If unsure, say N.
> diff --git a/drivers/platform/wmi/tests/Makefile b/drivers/platform/wmi/tests/Makefile
> index 252c3125353a..62c438e26259 100644
> --- a/drivers/platform/wmi/tests/Makefile
> +++ b/drivers/platform/wmi/tests/Makefile
> @@ -6,3 +6,6 @@
>  
>  wmi_marshalling_kunit-y				:= marshalling_kunit.o
>  obj-$(CONFIG_ACPI_WMI_MARSHALLING_KUNIT_TEST)	+= wmi_marshalling_kunit.o
> +
> +wmi_string_kunit-y				:= string_kunit.o
> +obj-$(CONFIG_ACPI_WMI_STRING_KUNIT_TEST)	+= wmi_string_kunit.o
> diff --git a/drivers/platform/wmi/tests/string_kunit.c b/drivers/platform/wmi/tests/string_kunit.c
> new file mode 100644
> index 000000000000..9aa3ffa85090
> --- /dev/null
> +++ b/drivers/platform/wmi/tests/string_kunit.c
> @@ -0,0 +1,278 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * KUnit test for the ACPI-WMI string conversion code.
> + *
> + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/wmi.h>
> +
> +#include <kunit/resource.h>
> +#include <kunit/test.h>
> +
> +#include <asm/byteorder.h>
> +
> +struct wmi_string_param {
> +	const char *name;
> +	const struct wmi_string *wmi_string;
> +	/*
> +	 * Remember that using sizeof() on a struct wmi_string will
> +	 * always return a size of two bytes due to the flexible
> +	 * array member!
> +	 */
> +	size_t wmi_string_length;
> +	const u8 *utf8_string;
> +	size_t utf8_string_length;
> +};
> +
> +#define TEST_WMI_STRING_LENGTH 12
> +
> +static const struct wmi_string test_wmi_string = {
> +	.length = cpu_to_le16(10),
> +	.chars = {
> +		cpu_to_le16(u'T'),

I've applied this to for-next and intend to keep these there but FYI these 
trigger sparse errors. I don't know if they're fixable or not with 
reasonable effort on kernel side.

$ sparse --version
0.6.4 (Debian: 0.6.4-3)

--
 i.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-12 16:34   ` Ilpo Järvinen
@ 2026-01-12 17:59     ` Armin Wolf
  2026-01-12 18:11       ` Ilpo Järvinen
  0 siblings, 1 reply; 17+ messages in thread
From: Armin Wolf @ 2026-01-12 17:59 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Hans de Goede, platform-driver-x86, LKML, linux,
	Dell.Client.Kernel, corbet, linux-doc

Am 12.01.26 um 17:34 schrieb Ilpo Järvinen:

> On Fri, 9 Jan 2026, Armin Wolf wrote:
>
>> The string conversion frunctions provided by the WMI driver core
>> have no dependencies on the remaining WMI API, making them suitable
>> for unit tests.
>>
>> Implement such a unit test using kunit. Those unit tests verify that
>> converting between WMI strings and UTF8 strings works as expected.
>> They also verify that edge cases are handled correctly.
>>
>> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
>> ---
>>   drivers/platform/wmi/tests/Kconfig        |  11 +
>>   drivers/platform/wmi/tests/Makefile       |   3 +
>>   drivers/platform/wmi/tests/string_kunit.c | 278 ++++++++++++++++++++++
>>   3 files changed, 292 insertions(+)
>>   create mode 100644 drivers/platform/wmi/tests/string_kunit.c
>>
>> diff --git a/drivers/platform/wmi/tests/Kconfig b/drivers/platform/wmi/tests/Kconfig
>> index efcbcb51c251..f7f0f3c540f5 100644
>> --- a/drivers/platform/wmi/tests/Kconfig
>> +++ b/drivers/platform/wmi/tests/Kconfig
>> @@ -14,3 +14,14 @@ config ACPI_WMI_MARSHALLING_KUNIT_TEST
>>   	  to the KUnit documentation in Documentation/dev-tools/kunit/.
>>   
>>   	  If unsure, say N.
>> +
>> +config ACPI_WMI_STRING_KUNIT_TEST
>> +	tristate "KUnit Test for ACPI-WMI string conversion" if !KUNIT_ALL_TESTS
>> +	depends on KUNIT
>> +	default KUNIT_ALL_TESTS
>> +	help
>> +	  This builds unit tests for the ACPI-WMI string conversion code.
>> +	  For more information on KUnit and unit tests in general, please refer
>> +	  to the KUnit documentation in Documentation/dev-tools/kunit/.
>> +
>> +	  If unsure, say N.
>> diff --git a/drivers/platform/wmi/tests/Makefile b/drivers/platform/wmi/tests/Makefile
>> index 252c3125353a..62c438e26259 100644
>> --- a/drivers/platform/wmi/tests/Makefile
>> +++ b/drivers/platform/wmi/tests/Makefile
>> @@ -6,3 +6,6 @@
>>   
>>   wmi_marshalling_kunit-y				:= marshalling_kunit.o
>>   obj-$(CONFIG_ACPI_WMI_MARSHALLING_KUNIT_TEST)	+= wmi_marshalling_kunit.o
>> +
>> +wmi_string_kunit-y				:= string_kunit.o
>> +obj-$(CONFIG_ACPI_WMI_STRING_KUNIT_TEST)	+= wmi_string_kunit.o
>> diff --git a/drivers/platform/wmi/tests/string_kunit.c b/drivers/platform/wmi/tests/string_kunit.c
>> new file mode 100644
>> index 000000000000..9aa3ffa85090
>> --- /dev/null
>> +++ b/drivers/platform/wmi/tests/string_kunit.c
>> @@ -0,0 +1,278 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * KUnit test for the ACPI-WMI string conversion code.
>> + *
>> + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/string.h>
>> +#include <linux/wmi.h>
>> +
>> +#include <kunit/resource.h>
>> +#include <kunit/test.h>
>> +
>> +#include <asm/byteorder.h>
>> +
>> +struct wmi_string_param {
>> +	const char *name;
>> +	const struct wmi_string *wmi_string;
>> +	/*
>> +	 * Remember that using sizeof() on a struct wmi_string will
>> +	 * always return a size of two bytes due to the flexible
>> +	 * array member!
>> +	 */
>> +	size_t wmi_string_length;
>> +	const u8 *utf8_string;
>> +	size_t utf8_string_length;
>> +};
>> +
>> +#define TEST_WMI_STRING_LENGTH 12
>> +
>> +static const struct wmi_string test_wmi_string = {
>> +	.length = cpu_to_le16(10),
>> +	.chars = {
>> +		cpu_to_le16(u'T'),
> I've applied this to for-next and intend to keep these there but FYI these
> trigger sparse errors. I don't know if they're fixable or not with
> reasonable effort on kernel side.

To me it seems that sparse ignores the u-prefix signaling that the character constant
has a length of 16-bits, but good catch.

If this really is a problem then gcc would issue a warning anyway (happened when i was
using the 🐧 character which does not fit into a 16-bit character constant).

Thanks,
Armin Wolf

>
> $ sparse --version
> 0.6.4 (Debian: 0.6.4-3)
>
> --
>   i.
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 0/9] platform/wmi: Introduce marshalling support
  2026-01-12 15:33 ` [PATCH v3 0/9] platform/wmi: Introduce marshalling support Ilpo Järvinen
@ 2026-01-12 18:00   ` Armin Wolf
  0 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-12 18:00 UTC (permalink / raw)
  To: Ilpo Järvinen, hansg
  Cc: platform-driver-x86, linux-kernel, linux, Dell.Client.Kernel,
	corbet, linux-doc

Am 12.01.26 um 16:33 schrieb Ilpo Järvinen:

> On Fri, 09 Jan 2026 22:46:10 +0100, Armin Wolf wrote:
>
>> The Windows WMI-ACPI driver likely uses wmilib [1] to interact with
>> the WMI service in userspace. Said library uses plain byte buffers
>> for exchanging data, so the WMI-ACPI driver has to convert between
>> those byte buffers and ACPI objects returned by the ACPI firmware.
>>
>> The format of the byte buffer is publicly documented [2], and after
>> some reverse eingineering of the WMI-ACPI driver using a set of custom
>> ACPI tables, the following conversion rules have been discovered:
>>
>> [...]
>
> Thank you for your contribution, it has been applied to my local
> review-ilpo-next branch. Note it will show up in the public
> platform-drivers-x86/review-ilpo-next branch only once I've pushed my
> local branch there, which might take a while.
>
> The list of commits applied:
> [1/9] platform/wmi: Introduce marshalling support
>        commit: bfa284e9f5e77c9e7389116a403b1dc478f2d58e
> [2/9] platform/wmi: Add kunit test for the marshalling code
>        commit: 1e4746e93871168f50f237e9e316dc6c9a883719
> [3/9] platform/wmi: Add helper functions for WMI string conversions
>        commit: 3ae53ee45d5c958aae883173d1e4cafe15564cce
> [4/9] platform/wmi: Add kunit test for the string conversion code
>        commit: 3579df4cf0b5a3c1d50146c72b13bb4215d509b5
> [5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API
>        commit: ca7861de6a37a52bf75fe41be51fd39162a9281d
> [6/9] platform/x86/intel/wmi: thunderbolt: Use new buffer-based WMI API
>        commit: 7f331e5f10ebb72d3bbc83470e4b409337024093
> [7/9] platform/x86: xiaomi-wmi: Use new buffer-based WMI API
>        commit: e9997669653bc0622f9ed8a3fe778cc989d1e254
> [8/9] platform/x86: wmi-bmof: Use new buffer-based WMI API
>        commit: 70d37a7fd341e5c0090385034feb8f6f93a56ae7
> [9/9] platform/wmi: Update driver development guide
>        commit: 0835f9737d4705a9f72de05fde09ba806dcbc862

Thank you :)

> --
>   i.
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-12 17:59     ` Armin Wolf
@ 2026-01-12 18:11       ` Ilpo Järvinen
  0 siblings, 0 replies; 17+ messages in thread
From: Ilpo Järvinen @ 2026-01-12 18:11 UTC (permalink / raw)
  To: Armin Wolf
  Cc: Hans de Goede, platform-driver-x86, LKML, linux,
	Dell.Client.Kernel, corbet, linux-doc

[-- Attachment #1: Type: text/plain, Size: 4443 bytes --]

On Mon, 12 Jan 2026, Armin Wolf wrote:

> Am 12.01.26 um 17:34 schrieb Ilpo Järvinen:
> 
> > On Fri, 9 Jan 2026, Armin Wolf wrote:
> > 
> > > The string conversion frunctions provided by the WMI driver core
> > > have no dependencies on the remaining WMI API, making them suitable
> > > for unit tests.
> > > 
> > > Implement such a unit test using kunit. Those unit tests verify that
> > > converting between WMI strings and UTF8 strings works as expected.
> > > They also verify that edge cases are handled correctly.
> > > 
> > > Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> > > ---
> > >   drivers/platform/wmi/tests/Kconfig        |  11 +
> > >   drivers/platform/wmi/tests/Makefile       |   3 +
> > >   drivers/platform/wmi/tests/string_kunit.c | 278 ++++++++++++++++++++++
> > >   3 files changed, 292 insertions(+)
> > >   create mode 100644 drivers/platform/wmi/tests/string_kunit.c
> > > 
> > > diff --git a/drivers/platform/wmi/tests/Kconfig
> > > b/drivers/platform/wmi/tests/Kconfig
> > > index efcbcb51c251..f7f0f3c540f5 100644
> > > --- a/drivers/platform/wmi/tests/Kconfig
> > > +++ b/drivers/platform/wmi/tests/Kconfig
> > > @@ -14,3 +14,14 @@ config ACPI_WMI_MARSHALLING_KUNIT_TEST
> > >   	  to the KUnit documentation in Documentation/dev-tools/kunit/.
> > >     	  If unsure, say N.
> > > +
> > > +config ACPI_WMI_STRING_KUNIT_TEST
> > > +	tristate "KUnit Test for ACPI-WMI string conversion" if
> > > !KUNIT_ALL_TESTS
> > > +	depends on KUNIT
> > > +	default KUNIT_ALL_TESTS
> > > +	help
> > > +	  This builds unit tests for the ACPI-WMI string conversion code.
> > > +	  For more information on KUnit and unit tests in general, please
> > > refer
> > > +	  to the KUnit documentation in Documentation/dev-tools/kunit/.
> > > +
> > > +	  If unsure, say N.
> > > diff --git a/drivers/platform/wmi/tests/Makefile
> > > b/drivers/platform/wmi/tests/Makefile
> > > index 252c3125353a..62c438e26259 100644
> > > --- a/drivers/platform/wmi/tests/Makefile
> > > +++ b/drivers/platform/wmi/tests/Makefile
> > > @@ -6,3 +6,6 @@
> > >     wmi_marshalling_kunit-y				:= marshalling_kunit.o
> > >   obj-$(CONFIG_ACPI_WMI_MARSHALLING_KUNIT_TEST)	+=
> > > wmi_marshalling_kunit.o
> > > +
> > > +wmi_string_kunit-y				:= string_kunit.o
> > > +obj-$(CONFIG_ACPI_WMI_STRING_KUNIT_TEST)	+= wmi_string_kunit.o
> > > diff --git a/drivers/platform/wmi/tests/string_kunit.c
> > > b/drivers/platform/wmi/tests/string_kunit.c
> > > new file mode 100644
> > > index 000000000000..9aa3ffa85090
> > > --- /dev/null
> > > +++ b/drivers/platform/wmi/tests/string_kunit.c
> > > @@ -0,0 +1,278 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + * KUnit test for the ACPI-WMI string conversion code.
> > > + *
> > > + * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
> > > + */
> > > +
> > > +#include <linux/module.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/string.h>
> > > +#include <linux/wmi.h>
> > > +
> > > +#include <kunit/resource.h>
> > > +#include <kunit/test.h>
> > > +
> > > +#include <asm/byteorder.h>
> > > +
> > > +struct wmi_string_param {
> > > +	const char *name;
> > > +	const struct wmi_string *wmi_string;
> > > +	/*
> > > +	 * Remember that using sizeof() on a struct wmi_string will
> > > +	 * always return a size of two bytes due to the flexible
> > > +	 * array member!
> > > +	 */
> > > +	size_t wmi_string_length;
> > > +	const u8 *utf8_string;
> > > +	size_t utf8_string_length;
> > > +};
> > > +
> > > +#define TEST_WMI_STRING_LENGTH 12
> > > +
> > > +static const struct wmi_string test_wmi_string = {
> > > +	.length = cpu_to_le16(10),
> > > +	.chars = {
> > > +		cpu_to_le16(u'T'),
> > I've applied this to for-next and intend to keep these there but FYI these
> > trigger sparse errors. I don't know if they're fixable or not with
> > reasonable effort on kernel side.
> 
> To me it seems that sparse ignores the u-prefix signaling that the character
> constant
> has a length of 16-bits, but good catch.
> 
> If this really is a problem then gcc would issue a warning anyway (happened
> when i was
> using the 🐧 character which does not fit into a 16-bit character constant).

I guess I'll have to add another filter to my build-test.sh for this file. 
I already -v -e 'error: bad constant expression' filter in use. Sadly 
sparse seems to be rotting.

-- 
 i.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-09 21:46 ` [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code Armin Wolf
  2026-01-12 16:34   ` Ilpo Järvinen
@ 2026-01-22 23:45   ` Nathan Chancellor
  2026-01-23 19:17     ` Armin Wolf
  1 sibling, 1 reply; 17+ messages in thread
From: Nathan Chancellor @ 2026-01-22 23:45 UTC (permalink / raw)
  To: Armin Wolf
  Cc: hansg, ilpo.jarvinen, platform-driver-x86, linux-kernel, linux,
	Dell.Client.Kernel, corbet, linux-doc, llvm

Hi Armin,

On Fri, Jan 09, 2026 at 10:46:14PM +0100, Armin Wolf wrote:
> The string conversion frunctions provided by the WMI driver core
> have no dependencies on the remaining WMI API, making them suitable
> for unit tests.
> 
> Implement such a unit test using kunit. Those unit tests verify that
> converting between WMI strings and UTF8 strings works as expected.
> They also verify that edge cases are handled correctly.
> 
> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
...
> +++ b/drivers/platform/wmi/tests/string_kunit.c
...
> +static const u8 oversized_test_utf8_string[] = "TEST!";
...
> +static void wmi_string_to_utf8s_oversized_test(struct kunit *test)
> +{
> +	u8 result[sizeof(oversized_test_utf8_string)];
> +	ssize_t ret;
> +
> +	ret = wmi_string_to_utf8s(&oversized_test_wmi_string, result, sizeof(result));
> +
> +	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
> +	KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
> +}

After this change in -next as commit 0e1a8143e797 ("platform/wmi: Add
kunit test for the string conversion code"), I am seeing a warning from
clang around oversized_test_utf8_string:

  drivers/platform/wmi/tests/string_kunit.c:108:17: error: variable 'oversized_test_utf8_string' is not needed and will not be emitted [-Werror,-Wunneeded-internal-declaration]
    108 | static const u8 oversized_test_utf8_string[] = "TEST!";
        |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~

oversized_test_utf8_string is only used in sizeof() in
wmi_string_to_utf8s_oversized_test(). clang warns because sizeof() is
evaluated at compile time, so oversized_test_utf8_string won't end up in
the final binary. This is typically a bug since the developer may have
intended to use the variable elsewhere but I was not able to easily
determine that in this case.

If it is intentional that this variable is only needed in sizeof(), it
could either be marked with __maybe_unused or eliminated in favor of a
direct 'sizeof("TEST!")', depending on maintainer/developer preference.
I am happy to send a patch.

Cheers,
Nathan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code
  2026-01-22 23:45   ` Nathan Chancellor
@ 2026-01-23 19:17     ` Armin Wolf
  0 siblings, 0 replies; 17+ messages in thread
From: Armin Wolf @ 2026-01-23 19:17 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: hansg, ilpo.jarvinen, platform-driver-x86, linux-kernel, linux,
	Dell.Client.Kernel, corbet, linux-doc, llvm

Am 23.01.26 um 00:45 schrieb Nathan Chancellor:

> Hi Armin,
>
> On Fri, Jan 09, 2026 at 10:46:14PM +0100, Armin Wolf wrote:
>> The string conversion frunctions provided by the WMI driver core
>> have no dependencies on the remaining WMI API, making them suitable
>> for unit tests.
>>
>> Implement such a unit test using kunit. Those unit tests verify that
>> converting between WMI strings and UTF8 strings works as expected.
>> They also verify that edge cases are handled correctly.
>>
>> Signed-off-by: Armin Wolf <W_Armin@gmx.de>
> ...
>> +++ b/drivers/platform/wmi/tests/string_kunit.c
> ...
>> +static const u8 oversized_test_utf8_string[] = "TEST!";
> ...
>> +static void wmi_string_to_utf8s_oversized_test(struct kunit *test)
>> +{
>> +	u8 result[sizeof(oversized_test_utf8_string)];
>> +	ssize_t ret;
>> +
>> +	ret = wmi_string_to_utf8s(&oversized_test_wmi_string, result, sizeof(result));
>> +
>> +	KUNIT_EXPECT_EQ(test, ret, sizeof(test_utf8_string) - 1);
>> +	KUNIT_EXPECT_MEMEQ(test, result, test_utf8_string, sizeof(test_utf8_string));
>> +}
> After this change in -next as commit 0e1a8143e797 ("platform/wmi: Add
> kunit test for the string conversion code"), I am seeing a warning from
> clang around oversized_test_utf8_string:
>
>    drivers/platform/wmi/tests/string_kunit.c:108:17: error: variable 'oversized_test_utf8_string' is not needed and will not be emitted [-Werror,-Wunneeded-internal-declaration]
>      108 | static const u8 oversized_test_utf8_string[] = "TEST!";
>          |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
>
> oversized_test_utf8_string is only used in sizeof() in
> wmi_string_to_utf8s_oversized_test(). clang warns because sizeof() is
> evaluated at compile time, so oversized_test_utf8_string won't end up in
> the final binary. This is typically a bug since the developer may have
> intended to use the variable elsewhere but I was not able to easily
> determine that in this case.
>
> If it is intentional that this variable is only needed in sizeof(), it
> could either be marked with __maybe_unused or eliminated in favor of a
> direct 'sizeof("TEST!")', depending on maintainer/developer preference.
> I am happy to send a patch.
>
> Cheers,
> Nathan

Good catch, it seems that i forgot to add the test case that was supposed to use oversized_test_utf8_string.
I will send a patch that adds this missing test case, fixing this warning in the process.

Thanks,
Armin Wolf


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-01-23 19:17 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-09 21:46 [PATCH v3 0/9] platform/wmi: Introduce marshalling support Armin Wolf
2026-01-09 21:46 ` [PATCH v3 1/9] " Armin Wolf
2026-01-09 21:46 ` [PATCH v3 2/9] platform/wmi: Add kunit test for the marshalling code Armin Wolf
2026-01-09 21:46 ` [PATCH v3 3/9] platform/wmi: Add helper functions for WMI string conversions Armin Wolf
2026-01-09 21:46 ` [PATCH v3 4/9] platform/wmi: Add kunit test for the string conversion code Armin Wolf
2026-01-12 16:34   ` Ilpo Järvinen
2026-01-12 17:59     ` Armin Wolf
2026-01-12 18:11       ` Ilpo Järvinen
2026-01-22 23:45   ` Nathan Chancellor
2026-01-23 19:17     ` Armin Wolf
2026-01-09 21:46 ` [PATCH v3 5/9] platform/x86: intel-wmi-sbl-fw-update: Use new buffer-based WMI API Armin Wolf
2026-01-09 21:46 ` [PATCH v3 6/9] platform/x86/intel/wmi: thunderbolt: " Armin Wolf
2026-01-09 21:46 ` [PATCH v3 7/9] platform/x86: xiaomi-wmi: " Armin Wolf
2026-01-09 21:46 ` [PATCH v3 8/9] platform/x86: wmi-bmof: " Armin Wolf
2026-01-09 21:46 ` [PATCH v3 9/9] platform/wmi: Update driver development guide Armin Wolf
2026-01-12 15:33 ` [PATCH v3 0/9] platform/wmi: Introduce marshalling support Ilpo Järvinen
2026-01-12 18:00   ` Armin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox